PC网页微信扫码支付(模式二)

微信支付:模式二(JAVA)

PC网页微信扫码支付(模式二)_第1张图片
支付过程

开始

前言:由于微信官方文档非常扯淡,也不够阿里文档详细,集中和简单,并且官方提供demo多样性和复杂性,此次我采用的是模式二,http工具类请求。

  1. 首先,我们需要在开发平台获取我们需要的参数。

    • appid:产品配置中获得app_id
    • device_info:WEB(自定义参数,可以为终端设备号(门店号或收银设备ID),PC网页或公众号内支付可以传"WEB")
    • mch_id:商家号
    • notify_url:回调路径
    • spbill_create_ip:项目ip(可以127.0.0.1,但是不可以localhost)
    • trade_type:NATIVE
    • key:密钥
    • url:https://api.mch.weixin.qq.com/pay/unifiedorder
  2. 工具类

    1. WxConfig.class(微信配置)

       public class WxConfig {
           public static final String appid = ""; //app_id
           public static final String body = "订单支付"; // 订单内容
           public static final String device_info = "WEB"; // 类型:网站
           public static final String mch_id = ""; // 商家号
           public static final String notify_url = "/wx/paycallback.json"; // 回调路径
           public static final String spbill_create_ip = "127.0.0.1"; // 项目ip
           public static final String trade_type = "NATIVE";
           public static final String key = ""; //key
           public static final String url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //请求路径
       }
      
    2. SignGenerate.class(生成请求微信参数格式)

       public final class SignGenerate {
           // 生成md5加密后的sign
           public static String wxSignGenerate(Map paramsMap, String key) {
               StringBuilder builder = new StringBuilder();
               for (Map.Entry entry : paramsMap.entrySet()) {
                   builder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
               }
               builder.append("key=").append(key);
               return DigestUtils.md5Hex(builder.toString()).toUpperCase();
           }
      
           // 将配置生成微信需要的xml格式
           public static String buildWxXmlJson(String productNumber,String amount){
               StringBuilder data = new StringBuilder("");
               Map paramsMap = new LinkedHashMap<>();
               paramsMap.put("appid", WxConfig.appid);
               paramsMap.put("body", WxConfig.body);
               paramsMap.put("device_info", WxConfig.device_info);
               paramsMap.put("mch_id", WxConfig.mch_id);
               paramsMap.put("nonce_str", SerialGenerator.genSerialCode());
               paramsMap.put("notify_url", WxConfig.notify_url);
               paramsMap.put("out_trade_no", productNumber);
               paramsMap.put("spbill_create_ip", WxConfig.spbill_create_ip);
               paramsMap.put("total_fee", amount);
               paramsMap.put("trade_type", WxConfig.trade_type);
               String sign = wxSignGenerate(paramsMap, WxConfig.key);
               paramsMap.put("sign", sign);
               for (Map.Entry entry : paramsMap.entrySet()) {
                   data.append("<").append(entry.getKey()).append(">").append(entry.getValue()).append("");
               }
               data.append("");
               return data.toString();
           }
       }
      
    3. WeixinWebUtil(微信请求工具类)

       public class WeixinWebUtil {
           private static Logger log = LoggerFactory.getLogger(WeixinWebUtil.class);
      
           public static String doGet(String url, String charset, int connectTimeout, int readTimeout) {
               return httpRequest(url, "GET", null, charset, connectTimeout, readTimeout, null);
           }
       
           public static String doGet(String url, String charset, int connectTimeout, int readTimeout, Map headerMap) {
               return httpRequest(url, "GET", null, charset, connectTimeout, readTimeout, headerMap);
           }
       
       
           //url为不带 ? 号的url
           public static String doGet(String url, Map paramMap, String charset, int connectTimeout, int readTimeout) throws IOException {
               String query = buildQuery(paramMap, charset);
               return httpRequest(url + "?" + query, "GET", null, charset, connectTimeout, readTimeout, null);
           }
       
           public static String doGet(String url, Map paramMap, String charset, int connectTimeout, int readTimeout, Map headerMap) throws IOException {
               String query = buildQuery(paramMap, charset);
               return httpRequest(url + "?" + query, "GET", null, charset, connectTimeout, readTimeout, headerMap);
           }
       
           public static String doPost(String url, Map paramMap, String jsonParam, String charset, int connectTimeout, int readTimeout) throws IOException {
               String query = buildQuery(paramMap, charset);
               return httpRequest(url + "?" + query, "POST", jsonParam, charset, connectTimeout, readTimeout, null);
           }
       
           public static String doPost(String url, Map paramMap, String jsonParam, String charset, int connectTimeout, int readTimeout, Map headerMap) throws IOException {
               String query = buildQuery(paramMap, charset);
               return httpRequest(url + "?" + query, "POST", jsonParam, charset, connectTimeout, readTimeout, headerMap);
           }
       
           public static String doPost(String url, String jsonParam, String charset, int connectTimeout, int readTimeout) {
               return httpRequest(url, "POST", jsonParam, charset, connectTimeout, readTimeout, null);
           }
       
           public static String doPost(String url, String jsonParam, String charset, int connectTimeout, int readTimeout, Map headerMap) {
               return httpRequest(url, "POST", jsonParam, charset, connectTimeout, readTimeout, headerMap);
           }
       
       
           /**
            * 发起https请求并获取结果
            *
            * @param requestUrl 请求地址
            * @param requestMethod 请求方式(GET、POST)
            * @param outputStr 提交的数据
            * @return String
            */
           private static String httpRequest(String requestUrl, String requestMethod, String outputStr, String charset, int connectTimeout, int readTimeout, Map headerMap) {
               StringBuffer buffer = new StringBuffer();
               try {
                   // 创建SSLContext对象,并使用我们指定的信任管理器初始化
                   TrustManager[] tm = { new MyX509TrustManager() };
                   SSLContext sslContext = SSLContext.getInstance("TLSV1"); //使用TLS协议加密
       //          SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
                   sslContext.init(null, tm, new java.security.SecureRandom());
                   // 从上述SSLContext对象中得到SSLSocketFactory对象
                   SSLSocketFactory ssf = sslContext.getSocketFactory();
       
                   URL url = new URL(requestUrl);
                   HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
                   httpUrlConn.setSSLSocketFactory(ssf);
       
                   httpUrlConn.setDoOutput(true);
                   httpUrlConn.setDoInput(true);
                   httpUrlConn.setUseCaches(false);
                   httpUrlConn.setConnectTimeout(connectTimeout);
                   httpUrlConn.setReadTimeout(readTimeout);
                   // 设置请求方式(GET/POST)
                   httpUrlConn.setRequestMethod(requestMethod);
       
                   if(headerMap!=null){
                       for(Map.Entry entry : headerMap.entrySet()){
                           httpUrlConn.setRequestProperty(entry.getKey(), entry.getValue());
                       }
                   }
       
                   if ("GET".equalsIgnoreCase(requestMethod)){
                       httpUrlConn.connect();
                   }
       
                   // 当有数据需要提交时
                   if (StringUtils.isNotBlank(outputStr)) {
                       OutputStream outputStream = httpUrlConn.getOutputStream();
                       // 注意编码格式,防止中文乱码
                       outputStream.write(outputStr.getBytes(charset));
                       outputStream.close();
                   }
       
                   // 将返回的输入流转换成字符串
                   InputStream inputStream = httpUrlConn.getInputStream();
                   InputStreamReader inputStreamReader = new InputStreamReader(inputStream, charset);
                   BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
       
                   String str = null;
                   while ((str = bufferedReader.readLine()) != null) {
                       buffer.append(str);
                   }
                   bufferedReader.close();
                   inputStreamReader.close();
                   // 释放资源
                   inputStream.close();
                   inputStream = null;
                   httpUrlConn.disconnect();
               } catch (ConnectException ce) {
                   log.error("Weixin server connection timed out.");
               } catch (Exception e) {
                   log.error("https request error:", e);
               }
               return buffer.toString();
           }
       
       
           public static String buildQuery(Map params, String charset) throws IOException {
               if (params == null || params.isEmpty()) {
                   return null;
               }
       
               StringBuilder query = new StringBuilder();
               Set> entries = params.entrySet();
               boolean hasParam = false;
       
               for (Map.Entry entry : entries) {
                   String name = entry.getKey();
                   String value = entry.getValue();
                   // 忽略参数名或参数值为空的参数
                   if (StringUtils.isNotBlank(name) && StringUtils.isNotBlank(value)) {
                       if (hasParam) {
                           query.append("&");
                       } else {
                           hasParam = true;
                       }
       
                       query.append(name).append("=").append(URLEncoder.encode(value, charset));
                   }
               }
       
               return query.toString();
           }
       }
       }
      

    4.XMLUtil.class(解析WxXML响应,将XML字符串转为Map)

     public final class XMLUtil {
     /**
      * 将微信xml格式解析成map
      * @param xmlString
      * @return
      * @throws DocumentException
      */
     public static Map parseXmlStr(String xmlString) throws DocumentException {
         //去掉前后的xml标签
         xmlString = xmlString.replaceAll("", "");
         System.out.println(xmlString);
         //匹配一段一段这样的数据   
         Pattern pattern = Pattern.compile("<.*?/.*?>");
         Matcher matcher = pattern.matcher(xmlString);
         //配置是否包含 CDATA 包裹的数据
         Pattern pattern2 = Pattern.compile("!.*]");
         Map map = new HashMap<>();
         while (matcher.find()) {
             //获取键
             String key = matcher.group().replaceAll(".*/", "");
             key = key.substring(0, key.length() - 1);
             Matcher matcher2 = pattern2.matcher(matcher.group());
             String value = matcher.group().replaceAll("", "");
             //获取值
             if (matcher2.find() && !value.equals("DATA")) {
                 value = matcher2.group().replaceAll("!.*\\[", "");
                 value = value.substring(0, value.length() - 2);
             }
             map.put(key, value);
         }
         return map;
     }
    

    }

  3. 业务

     String xmlJson = SignGenerate.buildWxXmlJson("商品号", "金额");
     String result = WeixinWebUtil.doPost(WxConfig.url, xmlJson, "UTF-8", 3000, 3000); // 发送请求
     Map resultMap = XMLUtil.parseXmlStr(result); // 解析Wx的相应参数
     String code_url resultMap.get("code_url"); // code_url是Wx响应的扫码网页路径
     // 生成二维码
     ByteArrayOutputStream outputStream = QRCode.from(code_url).to(ImageType.PNG).stream();
     httpResponse.setContentType("image/png");
     httpResponse.setContentLength(outputStream.size());
     OutputStream outStream = httpResponse.getOutputStream();
     outStream.write(outputStream.toByteArray());
     outStream.flush();
     outStream.close();
    
  4. Maven依赖

     
         com.thoughtworks.xstream
         xstream
         ${xstream.version}
     
     
         org.codehaus.jettison
         jettison
         ${jettison.version}
     
     
         com.google.zxing
         core
         ${zxing.version}
     
     
         net.glxn
         qrgen
         ${qrgen.version}
     

你可能感兴趣的:(PC网页微信扫码支付(模式二))