springboot 微信支付


微信支付第三彈--SpringBoot整合微信APP支付

原文鏈接:https://blog.csdn.net/qq_37345604/article/details/93039953

版權聲明:本文為博主原創文章,遵循 CC 4.0 by-sa 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接: https://blog.csdn.net/qq_37345604/article/details/93039953

吐槽

 做完APP微信支付,就兩個字:心累,並不是這個功能有多難,就是想吐槽一下微信,太TMD的店大欺客了!簽名,呵呵,參數順序都得按照他們的排序。。。。。。。。

吐槽歸吐槽,還是做一下知識復盤,下面是做APP微信支付步驟和代碼,框架用的是SpringBoot

步驟

必備參數:

 ①:appid:微信開放平台上面的應用appid,和公眾號appid不同

②:mch_id:商戶ID,微信商戶平台上商戶信息

③:key:商戶key(API秘鑰)

        登錄微信商戶平台--->賬戶中心--->API安全--->設置秘鑰

步驟

    ①、根據賬號參數拼接進行簽名

    ②、根據參數和簽名發起微信統一下單接口

    ③、把微信統一下單返回參數返回移動端

    ④、移動端根據參數拉起微信支付

    ⑤、支付成功后微信進行回調通知

    ⑥、判斷微信返回狀態,成功處理當前平台業務並返回微信return_code和return_msg兩個參數,不然微信會一直進行回調

參數配置

  1.  
    #微信APP支付參數
  2.  
    wxpayconfig:
  3.  
    #商戶應用appId
  4.  
    appid: wx383123456fbb7826
  5.  
    #商戶ID
  6.  
    mch_id: 1234567011
  7.  
    #設備號
  8.  
    device_info: WEB
  9.  
    #商戶key:api秘鑰(32位)
  10.  
    key: VfnmAMI111111111EQjhvglWzDDO
  11.  
    #統一下單接口
  12.  
    url: https: //api.mch.weixin.qq.com/pay/unifiedorder
  13.  
    #回調接口
  14.  
    notify_url: http: //baidu.com/home/wechatnotify
  15.  
    wx_package: Sign=WXPay

 

微信配置類

  1.  
    /**
  2.  
    * WxpayConfig.java
  3.  
    * com.prereadweb.order.config
  4.  
    * Copyright (c) 2019,
  5.  
    */
  6.  
    package com.prereadweb.order.config;
  7.  
     
  8.  
    import lombok.Data;
  9.  
    import org.springframework.boot.context.properties.ConfigurationProperties;
  10.  
    import org.springframework.stereotype.Component;
  11.  
     
  12.  
    /**
  13.  
    * @Description: 微信配置類
  14.  
    * @author: Administrator
  15.  
    * @date: 2019/6/17 19:35
  16.  
    */
  17.  
    @Data
  18.  
    @Component
  19.  
    @ConfigurationProperties(prefix="wxpayconfig")
  20.  
    public class WxpayConfig {
  21.  
     
  22.  
    private String appid; // 公眾賬號ID
  23.  
     
  24.  
    private String mch_id; // 商戶號
  25.  
     
  26.  
    private String device_info; // 設備號
  27.  
     
  28.  
    private String key; // 商戶的key【API密匙】
  29.  
     
  30.  
    private String url; // api請求地址
  31.  
     
  32.  
    private String notify_url; // 服務器異步通知頁面路徑
  33.  
     
  34.  
    private String return_url; // 服務器同步通知頁面路徑
  35.  
    private String wx_package;
  36.  
    }

 

統一下單代碼

controller層

  1.  
    /**
  2.  
    * @Function: 去支付
  3.  
    * @author: YangXueFeng
  4.  
    * @Date: 2019/6/14 16:46
  5.  
    */
  6.  
    @RequestMapping("/gowechatpay")
  7.  
    public Object goWeChatPay(@Param("orderId") Long orderId, HttpServletRequest request, HttpServletResponse response) throws Exception {
  8.  
    return weChatService.goWeChatPay(orderId, request);
  9.  
    }

 

 service層代碼

  1.  
    /**
  2.  
    * @Function: 去支付
  3.  
    * @author: YangXueFeng
  4.  
    * @Date: 2019/6/14 16:50
  5.  
    */
  6.  
    @Override
  7.  
    public Map<String, Object> goWeChatPay(Long orderId, HttpServletRequest request) {
  8.  
    Map<String, Object> map = new HashMap<>();
  9.  
    if(Util.isEmpty(orderId)) {
  10.  
    map.put("code", UserStatusEnum.ERROR.intKey());
  11.  
    map.put("msg", UserStatusEnum.ERROR.value());
  12.  
    return map;
  13.  
    }
  14.  
    //獲取訂單信息
  15.  
    PayParameterForm payParameter = orderMapper.getPayParameter(orderId);
  16.  
    double price = payParameter.getActualPrice();
  17.  
    System.out. println("price:" + price);
  18.  
    // 微信開放平台審核通過的應用APPID
  19.  
    System.out. println("appid是:" + wxpayconfig.getAppid());
  20.  
    System.out. println("mch_id是:" + wxpayconfig.getMch_id());
  21.  
    String nonce_str = Util.getRandomString( 30);
  22.  
    System.out. println("隨機字符串是:" + nonce_str);
  23.  
    int total_fee = (int) (price * 100);
  24.  
     
  25.  
    String total_price = null; // 訂單總金額,單位為分,詳見支付金額
  26.  
    String spbill_create_ip = WXSignUtils.getRemortIP(request); // "127.0.0.1";
  27.  
    System.out. println("spbill_create_ip===="+spbill_create_ip);
  28.  
    String notify_url = wxpayconfig.getNotify_url();
  29.  
    System.out. println("notify_url是:" + notify_url);
  30.  
    String trade_type = "APP";
  31.  
     
  32.  
    // 參數:開始生成簽名
  33.  
    SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
  34.  
    parameters.put( "appid", wxpayconfig.getAppid());
  35.  
    parameters.put( "body", payParameter.getTitle());
  36.  
    parameters.put( "mch_id", wxpayconfig.getMch_id());
  37.  
    parameters.put( "nonce_str", nonce_str);
  38.  
    parameters.put( "notify_url", notify_url);
  39.  
    parameters.put( "out_trade_no", String.valueOf(payParameter.getOrderId()));
  40.  
    /*
  41.  
    parameters.put("total_fee", total_fee);
  42.  
    */
  43.  
    parameters.put( "spbill_create_ip",spbill_create_ip);
  44.  
    parameters.put( "total_fee", 1);
  45.  
    parameters.put( "trade_type", trade_type);
  46.  
    String sign = WXSignUtils.createSign( "UTF-8", parameters);
  47.  
    System.out. println("簽名是:" + sign);
  48.  
    Unifiedorder unifiedorder = new Unifiedorder();
  49.  
    unifiedorder.setAppid(wxpayconfig.getAppid());
  50.  
    unifiedorder.setBody(payParameter.getTitle());
  51.  
    unifiedorder.setMch_id(wxpayconfig.getMch_id());
  52.  
    unifiedorder.setNonce_str(nonce_str);
  53.  
    unifiedorder.setNotify_url(notify_url);
  54.  
    unifiedorder.setOut_trade_no(String.valueOf(payParameter.getOrderId()));
  55.  
    unifiedorder.setSpbill_create_ip(spbill_create_ip);
  56.  
    unifiedorder.setTotal_fee( 1);
  57.  
    unifiedorder.setTrade_type(trade_type);
  58.  
    unifiedorder.setSign(sign);
  59.  
     
  60.  
    // 構造xml參數
  61.  
    String xmlInfo = HttpXmlUtils.xmlInfo(unifiedorder);
  62.  
    System.out. println("xmlInfo:" + xmlInfo);
  63.  
     
  64.  
    String wxUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
  65.  
    String method = "POST";
  66.  
    String weixinPost = HttpXmlUtils.httpsRequest(wxUrl, method, xmlInfo).toString(); // 請求微信
  67.  
    System.out. println("weixinPost:" + weixinPost);
  68.  
    UnifiedorderResult unifiedorderResult = ParseXMLUtils.jdomParseXml(weixinPost); // 解析微信的反饋
  69.  
    if (unifiedorderResult != null) {
  70.  
    if ("SUCCESS".equals(unifiedorderResult.getReturn_code())) {
  71.  
    if("INVALID_REQUEST".equals(unifiedorderResult.getErr_code())){
  72.  
    map.put("code", UserStatusEnum.ERROR.intKey());
  73.  
    map.put("msg", "參數錯誤");
  74.  
    return map;
  75.  
    }
  76.  
    // 開始拼接App調起微信的參數
  77.  
    SortedMap<Object, Object> wxAppparameters = new TreeMap<Object, Object>();
  78.  
    wxAppparameters.put( "appid", unifiedorderResult.getAppid());
  79.  
    wxAppparameters.put( "partnerid", unifiedorderResult.getMch_id());
  80.  
    wxAppparameters.put( "prepayid", unifiedorderResult.getPrepay_id());
  81.  
    wxAppparameters.put( "package", wxpayconfig.getWx_package());
  82.  
    wxAppparameters.put( "noncestr", nonce_str);
  83.  
    wxAppparameters.put( "timestamp", String.valueOf(new Date().getTime()).substring(0, 10));
  84.  
    wxAppparameters.put( "sign", WXSignUtils.createSign("UTF-8", wxAppparameters));
  85.  
    map.put("code", UserStatusEnum.SUCCESS.intKey());
  86.  
    map.put("msg", UserStatusEnum.SUCCESS.value());
  87.  
    map.put("data", wxAppparameters);
  88.  
    return map;
  89.  
    } else {
  90.  
    System.out. println("錯誤原因為:" + unifiedorderResult.getReturn_msg());
  91.  
    map.put("code", UserStatusEnum.ERROR.intKey());
  92.  
    map.put("msg", unifiedorderResult.getReturn_msg());
  93.  
    return map;
  94.  
    }
  95.  
    } else {
  96.  
    System.out. println("服務端請求微信的返回值異常。");
  97.  
    map.put("code", UserStatusEnum.ERROR.intKey());
  98.  
    map.put("msg", "服務端請求微信的返回值異常。");
  99.  
    return map;
  100.  
    }
  101.  
    }

 

此處簽名時參數的排序如下↓

謹記!這是微信挖的一個坑,如果不按照這個排序的話,你的統一下單接口很有可能會一直返回:簽名失敗

返回參數:

微信回調函數

controller層

聲明:此處要有返回值,如果你的項目配置了攔截器,記得把這個方法的路徑放開,不然微信會訪問不到

  1.  
    /**
  2.  
    * @Function: 微信支付回調
  3.  
    * @author: YangXueFeng
  4.  
    * @Date: 2019/6/18 18:50
  5.  
    */
  6.  
    @RequestMapping("/wechatnotify")
  7.  
    public String weChatNotify(HttpServletRequest request) {
  8.  
    String returnXML = null;
  9.  
    try {
  10.  
    returnXML = weChatService.weChatNotify(request);
  11.  
    } catch (Exception e) {
  12.  
    e.printStackTrace();
  13.  
    }
  14.  
    return returnXML;
  15.  
    }

 

service層

  1.  
    /**
  2.  
    * @Function: 微信回調接口
  3.  
    * @author: YangXueFeng
  4.  
    * @Date: 2019/6/17 11:05
  5.  
    */
  6.  
    @ Override
  7.  
    public String weChatNotify(HttpServletRequest request) throws Exception {
  8.  
    Map<String, String> map = new HashMap<>();
  9.  
    System.out.println("----------------微信回調開始啦----------------------");
  10.  
    // 讀取參數
  11.  
    InputStream inputStream;
  12.  
    StringBuffer sb = new StringBuffer();
  13.  
    inputStream = request.getInputStream();
  14.  
    String s;
  15.  
    BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
  16.  
    while ((s = in.readLine()) != null) {
  17.  
    sb.append(s);
  18.  
    }
  19.  
    in.close();
  20.  
    inputStream.close();
  21.  
    // 解析xml成map
  22.  
    Map<String, String> m = new HashMap<String, String>();
  23.  
    m = WXSignUtils.doXMLParse(sb.toString());
  24.  
    // 過濾空 設置 TreeMap
  25.  
    SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();
  26.  
    Iterator<String> it = m.keySet().iterator();
  27.  
    while (it.hasNext()) {
  28.  
    String parameter = it.next();
  29.  
    String parameterValue = m.get(parameter);
  30.  
     
  31.  
    String v = "";
  32.  
    if (null != parameterValue) {
  33.  
    v = parameterValue.trim();
  34.  
    }
  35.  
    System.out.println("p:" + parameter + ",v:" + v);
  36.  
    packageParams.put(parameter, v);
  37.  
    }
  38.  
    // 微信支付的API密鑰
  39.  
    String key = wxpayconfig.getKey();
  40.  
    if(!isTenpaySign("UTF-8", packageParams, key)){
  41.  
    map.put("return_code", "FAIL");
  42.  
    map.put("return_msg", "return_code不正確");
  43.  
    return StringUtil.GetMapToXML(map);
  44.  
    }
  45.  
    //返回狀態存入redis中
  46.  
    if(m.get("return_code").equals("SUCCESS")){
  47.  
    RedisUtil.set("wx"+m.get("out_trade_no"),m.get("result_code"),300);
  48.  
    }
  49.  
    if (isTenpaySign("UTF-8", packageParams, key)) {
  50.  
    // 驗證通過
  51.  
    if ("SUCCESS".equals((String) packageParams.get("result_code"))) {
  52.  
    String out_trade_no = (String) packageParams.get("out_trade_no");
  53.  
    /* 訂單不為空 */
  54.  
    if (!Util.isEmpty(out_trade_no)) {
  55.  
    //支付成功后的業務處理
  56.  
    OrderEntity order = orderMapper.getOrderInfo(Long.valueOf(out_trade_no));
  57.  
    if(!Util.isEmpty(order)){
  58.  
    order.setStatus( CalculatStaticConstant.CHECK_ONE);
  59.  
    order.setCompleteTime( DateUtil.currentDate());
  60.  
    orderMapper.updateOrder(order);
  61.  
    System.out.println("----------------修改訂單狀態----------------------");
  62.  
    }
  63.  
    /* 添加支付信息 */
  64.  
    OrderPayEntity orderPay = new OrderPayEntity();
  65.  
    orderPay.setId( Long.valueOf(IdUtils.getPrimaryKey()));
  66.  
    orderPay.setOrderId(order.getId());
  67.  
    orderPay.setUserId(order.getUserId());
  68.  
    orderPay.setPayPrice(order.getActualPrice());
  69.  
    orderPay.setPayType( PayTypeEnum.WE_CHAT_PAY.intKey());
  70.  
    orderPay.setStatus( CalculatStaticConstant.CHECK_ONE);
  71.  
    orderPay.setPayTime( DateUtil.currentDate());
  72.  
    orderMapper.saveOrderPay(orderPay);
  73.  
    System.out.println("----------------添加支付信息----------------------");
  74.  
    map.put("return_code", "SUCCESS");
  75.  
    map.put("return_msg", "OK");
  76.  
    return StringUtil.GetMapToXML(map);
  77.  
    }
  78.  
    }
  79.  
    } else {
  80.  
    System.out.println("支付失敗");
  81.  
    map.put("return_code", "error");
  82.  
    map.put("return_msg", "支付失敗");
  83.  
    return StringUtil.GetMapToXML(map);
  84.  
    }
  85.  
    System.out.println("支付失敗");
  86.  
    System.out.println("支付失敗");
  87.  
    map.put("return_code", "error");
  88.  
    map.put("return_msg", "支付失敗");
  89.  
    return StringUtil.GetMapToXML(map);
  90.  
    }
  1.  
    /**
  2.  
    * @Function: 是否簽名正確,規則是:按參數名稱a-z排序,遇到空值的參數不參加簽名。
  3.  
    * @author: YangXueFeng
  4.  
    * @Date: 2019/6/17 17:10
  5.  
    */
  6.  
    @SuppressWarnings( "rawtypes")
  7.  
    public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams,
  8.  
    String API_KEY) {
  9.  
    StringBuffer sb = new StringBuffer();
  10.  
    Set es = packageParams.entrySet();
  11.  
    Iterator it = es.iterator();
  12.  
    while (it.hasNext()) {
  13.  
    Map.Entry entry = (Map.Entry) it.next();
  14.  
    String k = (String) entry.getKey();
  15.  
    String v = (String) entry.getValue();
  16.  
    if (!"sign".equals(k) && null != v && !"".equals(v)) {
  17.  
    sb.append(k + "=" + v + "&");
  18.  
    }
  19.  
    }
  20.  
    sb.append( "key=" + API_KEY);
  21.  
    // 算出摘要
  22.  
    String mysign = MD5Util.MD5Encode(sb.toString()).toLowerCase();
  23.  
    String tenpaySign = ((String) packageParams.get("sign")).toLowerCase();
  24.  
    return tenpaySign.equals(mysign);
  25.  
    }

 

相關工具類

微信簽名工具類

  1.  
    /**
  2.  
    * WXSignUtils.java
  3.  
    * com.prereadweb.order.util
  4.  
    * Copyright (c) 2019,
  5.  
    */
  6.  
    package com.prereadweb.order.util;
  7.  
     
  8.  
    import com.prereadweb.utils.MD5Util;
  9.  
    import org.jdom.Document;
  10.  
    import org.jdom.JDOMException;
  11.  
    import org.jdom.input.SAXBuilder;
  12.  
     
  13.  
    import javax.servlet.http.HttpServletRequest;
  14.  
    import java.io.ByteArrayInputStream;
  15.  
    import java.io.IOException;
  16.  
    import java.io.InputStream;
  17.  
    import java.util.*;
  18.  
     
  19.  
    /**
  20.  
    * @Description: 微信支付簽名
  21.  
    * @author: Administrator
  22.  
    * @date: 2019/6/17 15:43
  23.  
    */
  24.  
    public class WXSignUtils {
  25.  
     
  26.  
    /* API秘鑰 */
  27.  
    private static String Key ="VfnmAMasdasdasdasWzDDO";
  28.  
     
  29.  
    /**
  30.  
    * 微信支付簽名算法sign
  31.  
    * @param characterEncoding
  32.  
    * @param parameters
  33.  
    * @return
  34.  
    */
  35.  
    public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters){
  36.  
    StringBuffer sb = new StringBuffer();
  37.  
    Set es = parameters.entrySet();//所有參與傳參的參數按照accsii排序(升序)
  38.  
    Iterator it = es.iterator();
  39.  
    while(it.hasNext()) {
  40.  
    Map.Entry entry = (Map.Entry)it.next();
  41.  
    String k = (String)entry.getKey();
  42.  
    Object v = entry.getValue();
  43.  
    if(null != v && !"".equals(v)
  44.  
    && ! "sign".equals(k) && !"key".equals(k)) {
  45.  
    sb.append(k + "=" + v + "&");
  46.  
    }
  47.  
    }
  48.  
    sb.append( "key=" + Key);
  49.  
    System.out.println( "字符串拼接后是:"+sb.toString());
  50.  
    String sign = MD5Util.MD5Encode(sb.toString()).toUpperCase();
  51.  
    return sign;
  52.  
    }
  53.  
     
  54.  
    /**
  55.  
    * @Function: 獲取IP
  56.  
    * @author: YangXueFeng
  57.  
    * @Date: 2019/6/17 16:44
  58.  
    */
  59.  
    public static String getRemortIP(HttpServletRequest request) {
  60.  
    if (request.getHeader("x-forwarded-for") == null) {
  61.  
    return request.getRemoteAddr();
  62.  
    }
  63.  
    return request.getHeader("x-forwarded-for");
  64.  
    }
  65.  
     
  66.  
    /**
  67.  
    * @Function: 解析XML
  68.  
    * @author: YangXueFeng
  69.  
    * @Date: 2019/6/17 17:07
  70.  
    */
  71.  
    public static Map doXMLParse(String strxml) throws JDOMException,
  72.  
    IOException {
  73.  
    strxml = strxml.replaceFirst( "encoding=\".*\"", "encoding=\"UTF-8\"");
  74.  
     
  75.  
    if (null == strxml || "".equals(strxml)) {
  76.  
    return null;
  77.  
    }
  78.  
     
  79.  
    Map m = new HashMap();
  80.  
     
  81.  
    InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
  82.  
    SAXBuilder builder = new SAXBuilder();
  83.  
    Document doc = builder.build( in);
  84.  
    org.jdom.Element root = doc.getRootElement();
  85.  
    List list = root.getChildren();
  86.  
    Iterator it = list.iterator();
  87.  
    while (it.hasNext()) {
  88.  
    org.jdom.Element e = (org.jdom.Element) it.next();
  89.  
    String k = e.getName();
  90.  
    String v = "";
  91.  
    List children = e.getChildren();
  92.  
    if (children.isEmpty()) {
  93.  
    v = e.getTextNormalize();
  94.  
    } else {
  95.  
    v = getChildrenText(children);
  96.  
    }
  97.  
     
  98.  
    m.put(k, v);
  99.  
    }
  100.  
     
  101.  
    // 關閉流
  102.  
    in.close();
  103.  
     
  104.  
    return m;
  105.  
    }
  106.  
     
  107.  
    public static String getChildrenText(List children) {
  108.  
    StringBuffer sb = new StringBuffer();
  109.  
    if (!children.isEmpty()) {
  110.  
    Iterator it = children.iterator();
  111.  
    while (it.hasNext()) {
  112.  
    org.jdom.Element e = (org.jdom.Element) it.next();
  113.  
    String name = e.getName();
  114.  
    String value = e.getTextNormalize();
  115.  
    List list = e.getChildren();
  116.  
    sb.append( "<" + name + ">");
  117.  
    if (!list.isEmpty()) {
  118.  
    sb.append(getChildrenText(list));
  119.  
    }
  120.  
    sb.append(value);
  121.  
    sb.append( "</" + name + ">");
  122.  
    }
  123.  
    }
  124.  
     
  125.  
    return sb.toString();
  126.  
    }
  127.  
     
  128.  
    }

 

統一下單提交微信參數實體類

  1.  
    /**
  2.  
    * UnifiedorderResult.java
  3.  
    * com.prereadweb.order.util
  4.  
    * Copyright (c) 2019,
  5.  
    */
  6.  
    package com.prereadweb.order.util;
  7.  
     
  8.  
    import lombok.Data;
  9.  
     
  10.  
    /**
  11.  
    * @Description: 統一下單提交(微信參數)
  12.  
    * @author: Administrator
  13.  
    * @ date: 2019/6/17 16:11
  14.  
    */
  15.  
    @Data
  16.  
    public class UnifiedorderResult {
  17.  
    private String return_code;
  18.  
    private String return_msg;
  19.  
    private String appid;
  20.  
    private String mch_id;
  21.  
    private String device_info;
  22.  
    private String nonce_str;
  23.  
    private String sign;
  24.  
    private String result_code;
  25.  
    private String err_code;
  26.  
    private String err_code_des;
  27.  
    private String trade_type;
  28.  
    private String prepay_id;
  29.  
    }

 

DOM解析

  1.  
    /**
  2.  
    * ParseXMLUtils.java
  3.  
    * com.prereadweb.order.util
  4.  
    * Copyright (c) 2019, 北京聚智未來科技有限公司版權所有.
  5.  
    */
  6.  
    package com.prereadweb.order.util;
  7.  
     
  8.  
    import com.prereadweb.utils.Util;
  9.  
    import org.dom4j.Document;
  10.  
    import org.dom4j.DocumentException;
  11.  
    import org.dom4j.DocumentHelper;
  12.  
    import org.dom4j.Element;
  13.  
    import org.dom4j.io.SAXReader;
  14.  
    import org.jdom.input.SAXBuilder;
  15.  
    import org.xml.sax.InputSource;
  16.  
     
  17.  
    import java.io.StringReader;
  18.  
    import java.util.Iterator;
  19.  
    import java.util.List;
  20.  
     
  21.  
    /**
  22.  
    * @Description: DOM解析
  23.  
    * @author: Administrator
  24.  
    * @date: 2019/6/17 15:50
  25.  
    */
  26.  
    public class ParseXMLUtils {
  27.  
     
  28.  
    /**
  29.  
    * 1、DOM解析
  30.  
    */
  31.  
    @SuppressWarnings( "rawtypes")
  32.  
    public static void beginXMLParse(String xml){
  33.  
    Document doc = null;
  34.  
    try {
  35.  
    doc = DocumentHelper.parseText(xml); // 將字符串轉為XML
  36.  
     
  37.  
    Element rootElt = doc.getRootElement(); // 獲取根節點smsReport
  38.  
     
  39.  
    System. out.println("根節點是:"+rootElt.getName());
  40.  
     
  41.  
    Iterator iters = rootElt.elementIterator( "sendResp"); // 獲取根節點下的子節點sms
  42.  
     
  43.  
    while (iters.hasNext()) {
  44.  
    Element recordEle1 = (Element) iters.next();
  45.  
    Iterator iter = recordEle1.elementIterator( "sms");
  46.  
     
  47.  
    while (iter.hasNext()) {
  48.  
    Element recordEle = (Element) iter.next();
  49.  
    String phone = recordEle.elementTextTrim( "phone"); // 拿到sms節點下的子節點stat值
  50.  
     
  51.  
    String smsID = recordEle.elementTextTrim( "smsID"); // 拿到sms節點下的子節點stat值
  52.  
     
  53.  
    System. out.println(phone+":"+smsID);
  54.  
    }
  55.  
    }
  56.  
    } catch (DocumentException e) {
  57.  
    e.printStackTrace();
  58.  
    } catch (Exception e) {
  59.  
    e.printStackTrace();
  60.  
    }
  61.  
    }
  62.  
     
  63.  
    /**
  64.  
    * 2、DOM4j解析XML(支持xpath)
  65.  
    * 解析的時候自動去掉CDMA
  66.  
    * @param xml
  67.  
    */
  68.  
    public static void xpathParseXml(String xml){
  69.  
    try {
  70.  
    StringReader read = new StringReader(xml);
  71.  
    SAXReader saxReader = new SAXReader();
  72.  
    Document doc = saxReader.read(read);
  73.  
    String xpath = "/xml/appid";
  74.  
    System. out.print(doc.selectSingleNode(xpath).getText());
  75.  
    } catch (DocumentException e) {
  76.  
    e.printStackTrace();
  77.  
    }
  78.  
    }
  79.  
     
  80.  
    /**
  81.  
    * 3、JDOM解析XML
  82.  
    * 解析的時候自動去掉CDMA
  83.  
    * @param xml
  84.  
    */
  85.  
    @SuppressWarnings( "unchecked")
  86.  
    public static UnifiedorderResult jdomParseXml(String xml){
  87.  
    UnifiedorderResult unifieorderResult = new UnifiedorderResult();
  88.  
    try {
  89.  
    StringReader read = new StringReader(xml);
  90.  
    // 創建新的輸入源SAX 解析器將使用 InputSource 對象來確定如何讀取 XML 輸入
  91.  
    InputSource source = new InputSource(read);
  92.  
    // 創建一個新的SAXBuilder
  93.  
    SAXBuilder sb = new SAXBuilder();
  94.  
    // 通過輸入源構造一個Document
  95.  
    org.jdom.Document doc;
  96.  
    doc = (org.jdom.Document) sb.build(source);
  97.  
     
  98.  
    org.jdom.Element root = doc.getRootElement(); // 指向根節點
  99.  
    List<org.jdom.Element> list = root.getChildren();
  100.  
     
  101.  
    if(list != null && list.size() > 0){
  102.  
    boolean flag1 = true;
  103.  
    boolean flag2 = true;
  104.  
    for (org.jdom.Element element : list) {
  105.  
    System. out.println("key是:"+element.getName()+",值是:"+element.getText());
  106.  
     
  107.  
    if("return_code".equals(element.getName())){
  108.  
    if("FAIL".equals(element.getText())){
  109.  
    flag1 = false;
  110.  
    } else{
  111.  
    unifieorderResult.setReturn_code(element.getText());
  112.  
    }
  113.  
    }
  114.  
     
  115.  
    if("return_msg".equals(element.getName())){
  116.  
    if(element.getText() != null && !"OK".equals(element.getText())){//微信支付的第一個坑,這里返回了OK,23333
  117.  
    System. out.println("統一下單參數有誤,錯誤原因為:"+element.getText());
  118.  
    return null;
  119.  
    }
  120.  
    }
  121.  
     
  122.  
    if(flag1){
  123.  
    if("appid".equals(element.getName())){
  124.  
    unifieorderResult.setAppid(element.getText());
  125.  
    }
  126.  
    if("mch_id".equals(element.getName())){
  127.  
    unifieorderResult.setMch_id(element.getText());
  128.  
    }
  129.  
    if("nonce_str".equals(element.getName())){
  130.  
    unifieorderResult.setNonce_str(element.getText());
  131.  
    }
  132.  
    if("sign".equals(element.getName())){
  133.  
    unifieorderResult.setSign(element.getText());
  134.  
    }
  135.  
    if("err_code".equals(element.getName())){
  136.  
    unifieorderResult.setErr_code(element.getText());
  137.  
    }
  138.  
    if("err_code_des".equals(element.getName())){
  139.  
    unifieorderResult.setErr_code_des(element.getText());
  140.  
    }
  141.  
    if("result_code".equals(element.getName())){
  142.  
    if("FAIL".equals(element.getText())){
  143.  
    flag2 = false;
  144.  
    System. out.println("統一下單業務結果有誤,無法返回預支付交易會話標識");
  145.  
    } else{
  146.  
    unifieorderResult.setResult_code(element.getText());
  147.  
    }
  148.  
    }
  149.  
    }
  150.  
    if(flag1 && flag2 && flag2 == true){
  151.  
    if("trade_type".equals(element.getName())){
  152.  
    unifieorderResult.setTrade_type(element.getText());
  153.  
    }
  154.  
    if("prepay_id".equals(element.getName())){
  155.  
    System. out.println("統一下單接口成功返回預支付交易會話標識!");
  156.  
    unifieorderResult.setPrepay_id(element.getText());
  157.  
    }
  158.  
    }
  159.  
     
  160.  
    }
  161.  
    return unifieorderResult;
  162.  
    } else{
  163.  
    return null;
  164.  
    }
  165.  
     
  166.  
    } catch (Exception e) {
  167.  
    e.printStackTrace();
  168.  
    return null;
  169.  
    }
  170.  
     
  171.  
    }
  172.  
     
  173.  
    public static boolean parseInt(String key){
  174.  
    if(!Util.isEmpty(key)){
  175.  
    if(key.equals("total_fee")||key.equals("cash_fee")||key.equals("coupon_fee")||key.equals("coupon_count")||key.equals("coupon_fee_0")){
  176.  
    return true;
  177.  
    }
  178.  
    }
  179.  
     
  180.  
    return false;
  181.  
    }
  182.  
     
  183.  
    }

 

post提交xml格式的參數

  1.  
    /**
  2.  
    * HttpXmlUtils.java
  3.  
    * com.prereadweb.order.util
  4.  
    * Copyright (c) 2019, 北京聚智未來科技有限公司版權所有.
  5.  
    */
  6.  
    package com.prereadweb.order.util;
  7.  
     
  8.  
    import com.prereadweb.order.form.Unifiedorder;
  9.  
     
  10.  
    import javax.net.ssl.HttpsURLConnection;
  11.  
    import java.io.*;
  12.  
    import java.net.HttpURLConnection;
  13.  
    import java.net.MalformedURLException;
  14.  
    import java.net.URL;
  15.  
     
  16.  
    /**
  17.  
    * @Description: post提交xml格式的參數
  18.  
    * @author: Administrator
  19.  
    * @date: 2019/6/17 15:46
  20.  
    */
  21.  
    public class HttpXmlUtils {
  22.  
    /**
  23.  
    * 開始post提交參數到接口
  24.  
    * 並接受返回
  25.  
    * @param url
  26.  
    * @param xml
  27.  
    * @param method
  28.  
    * @param contentType
  29.  
    * @return
  30.  
    */
  31.  
    public static String xmlHttpProxy(String url,String xml,String method,String contentType){
  32.  
    InputStream is = null;
  33.  
    OutputStreamWriter os = null;
  34.  
     
  35.  
    try {
  36.  
    URL _url = new URL(url);
  37.  
    HttpURLConnection conn = (HttpURLConnection) _url.openConnection();
  38.  
    conn.setDoInput(true);
  39.  
    conn.setDoOutput(true);
  40.  
    conn.setRequestProperty("Content-type", "text/xml");
  41.  
    conn.setRequestProperty("Pragma:", "no-cache");
  42.  
    conn.setRequestProperty("Cache-Control", "no-cache");
  43.  
    conn.setRequestMethod("POST");
  44.  
    os = new OutputStreamWriter(conn.getOutputStream());
  45.  
    os.write(new String(xml.getBytes(contentType)));
  46.  
    os.flush();
  47.  
     
  48.  
    //返回值
  49.  
    is = conn.getInputStream();
  50.  
    return getContent(is, "utf-8");
  51.  
    } catch (MalformedURLException e) {
  52.  
    e.printStackTrace();
  53.  
    } catch (IOException e) {
  54.  
    e.printStackTrace();
  55.  
    } finally{
  56.  
    try {
  57.  
    if(os!=null){os.close();}
  58.  
    if(is!=null){is.close();}
  59.  
    } catch (IOException e) {
  60.  
    e.printStackTrace();
  61.  
    }
  62.  
    }
  63.  
    return null;
  64.  
    }
  65.  
     
  66.  
    /**
  67.  
    * 解析返回的值
  68.  
    * @param is
  69.  
    * @param charset
  70.  
    * @return
  71.  
    */
  72.  
    public static String getContent(InputStream is, String charset) {
  73.  
    String pageString = null;
  74.  
    InputStreamReader isr = null;
  75.  
    BufferedReader br = null;
  76.  
    StringBuffer sb = null;
  77.  
    try {
  78.  
    isr = new InputStreamReader(is, charset);
  79.  
    br = new BufferedReader(isr);
  80.  
    sb = new StringBuffer();
  81.  
    String line = null;
  82.  
    while ((line = br.readLine()) != null) {
  83.  
    sb.append(line + "\n");
  84.  
    }
  85.  
    pageString = sb.toString();
  86.  
    } catch (Exception e) {
  87.  
    e.printStackTrace();
  88.  
    } finally {
  89.  
    try {
  90.  
    if (is != null){
  91.  
    is.close();
  92.  
    }
  93.  
    if(isr!=null){
  94.  
    isr.close();
  95.  
    }
  96.  
    if(br!=null){
  97.  
    br.close();
  98.  
    }
  99.  
    } catch (IOException e) {
  100.  
    e.printStackTrace();
  101.  
    }
  102.  
    sb = null;
  103.  
    }
  104.  
    return pageString;
  105.  
    }
  106.  
     
  107.  
    /**
  108.  
    * 構造xml參數
  109.  
    * @param xml
  110.  
    * @return
  111.  
    */
  112.  
    public static String xmlInfo(Unifiedorder unifiedorder){
  113.  
    //構造xml參數的時候,至少又是個必傳參數
  114.  
    /*
  115.  
    * <xml>
  116.  
    <appid>wx2421b1c4370ec43b</appid>
  117.  
    <attach>支付測試</attach>
  118.  
    <body>JSAPI支付測試</body>
  119.  
    <mch_id>10000100</mch_id>
  120.  
    <nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>
  121.  
    <notify_url>http://wxpay.weixin.qq.com/pub_v2/pay/notify.v2.php</notify_url>
  122.  
    <openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>
  123.  
    <out_trade_no>1415659990</out_trade_no>
  124.  
    <spbill_create_ip>14.23.150.211</spbill_create_ip>
  125.  
    <total_fee>1</total_fee>
  126.  
    <trade_type>JSAPI</trade_type>
  127.  
    <sign>0CB01533B8C1EF103065174F50BCA001</sign>
  128.  
    </xml>
  129.  
    */
  130.  
     
  131.  
    if(unifiedorder!=null){
  132.  
    StringBuffer bf = new StringBuffer();
  133.  
    bf.append(" <xml>");
  134.  
     
  135.  
    bf.append(" <appid><![CDATA[");
  136.  
    bf.append(unifiedorder.getAppid());
  137.  
    bf.append("]]> </appid>");
  138.  
     
  139.  
    bf.append(" <body><![CDATA[");
  140.  
    bf.append(unifiedorder.getBody());
  141.  
    bf.append("]]> </body>");
  142.  
     
  143.  
    bf.append(" <mch_id><![CDATA[");
  144.  
    bf.append(unifiedorder.getMch_id());
  145.  
    bf.append("]]> </mch_id>");
  146.  
     
  147.  
    bf.append(" <nonce_str><![CDATA[");
  148.  
    bf.append(unifiedorder.getNonce_str());
  149.  
    bf.append("]]> </nonce_str>");
  150.  
     
  151.  
    bf.append(" <notify_url><![CDATA[");
  152.  
    bf.append(unifiedorder.getNotify_url());
  153.  
    bf.append("]]> </notify_url>");
  154.  
     
  155.  
    bf.append(" <out_trade_no><![CDATA[");
  156.  
    bf.append(unifiedorder.getOut_trade_no());
  157.  
    bf.append("]]> </out_trade_no>");
  158.  
     
  159.  
    bf.append(" <spbill_create_ip><![CDATA[");
  160.  
    bf.append(unifiedorder.getSpbill_create_ip());
  161.  
    bf.append("]]> </spbill_create_ip>");
  162.  
     
  163.  
    bf.append(" <total_fee><![CDATA[");
  164.  
    bf.append(unifiedorder.getTotal_fee());
  165.  
    bf.append("]]> </total_fee>");
  166.  
     
  167.  
    bf.append(" <trade_type><![CDATA[");
  168.  
    bf.append(unifiedorder.getTrade_type());
  169.  
    bf.append("]]> </trade_type>");
  170.  
     
  171.  
    bf.append(" <sign><![CDATA[");
  172.  
    bf.append(unifiedorder.getSign());
  173.  
    bf.append("]]> </sign>");
  174.  
     
  175.  
    bf.append(" </xml>");
  176.  
    return bf.toString();
  177.  
    }
  178.  
     
  179.  
    return "";
  180.  
    }
  181.  
     
  182.  
     
  183.  
     
  184.  
     
  185.  
    /**
  186.  
    * post請求並得到返回結果
  187.  
    * @param requestUrl
  188.  
    * @param requestMethod
  189.  
    * @param output
  190.  
    * @return
  191.  
    */
  192.  
    public static String httpsRequest(String requestUrl, String requestMethod, String output) {
  193.  
    try{
  194.  
    URL url = new URL(requestUrl);
  195.  
    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
  196.  
    connection.setDoOutput(true);
  197.  
    connection.setDoInput(true);
  198.  
    connection.setUseCaches(false);
  199.  
    connection.setRequestMethod(requestMethod);
  200.  
    if (null != output) {
  201.  
    OutputStream outputStream = connection.getOutputStream();
  202.  
    outputStream.write(output.getBytes("UTF-8"));
  203.  
    outputStream.close();
  204.  
    }
  205.  
    // 從輸入流讀取返回內容
  206.  
    InputStream inputStream = connection.getInputStream();
  207.  
    InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
  208.  
    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
  209.  
    String str = null;
  210.  
    StringBuffer buffer = new StringBuffer();
  211.  
    while ((str = bufferedReader.readLine()) != null) {
  212.  
    buffer.append(str);
  213.  
    }
  214.  
    bufferedReader.close();
  215.  
    inputStreamReader.close();
  216.  
    inputStream.close();
  217.  
    inputStream = null;
  218.  
    connection.disconnect();
  219.  
    return buffer.toString();
  220.  
    }catch(Exception ex){
  221.  
    ex.printStackTrace();
  222.  
    }
  223.  
     
  224.  
    return "";
  225.  
    }
  226.  
    }

將map轉換為xml類

  1.  
    /**
  2.  
    * StringUtil.java
  3.  
    * com.prereadweb.utils
  4.  
    * Copyright (c) 2019, 北京聚智未來科技有限公司版權所有.
  5.  
    */
  6.  
    package com.prereadweb.utils;
  7.  
     
  8.  
    import java.util.Map;
  9.  
     
  10.  
    /**
  11.  
    * @Description: String工具類
  12.  
    * @author: Administrator
  13.  
    * @date: 2019/6/19 11:31
  14.  
    */
  15.  
    public class StringUtil {
  16.  
     
  17.  
    /**
  18.  
    * @Function: 將map轉換為xml
  19.  
    * @author: YangXueFeng
  20.  
    * @Date: 2019/6/19 11:32
  21.  
    */
  22.  
    public static String GetMapToXML(Map<String,String> param){
  23.  
    StringBuffer sb = new StringBuffer();
  24.  
    sb.append( "<xml>");
  25.  
    for (Map.Entry<String,String> entry : param.entrySet()) {
  26.  
    sb.append( "<"+ entry.getKey() +">");
  27.  
    sb.append(entry.getValue());
  28.  
    sb.append( "</"+ entry.getKey() +">");
  29.  
    }
  30.  
    sb.append( "</xml>");
  31.  
    return sb.toString();
  32.  
    }
  33.  
    }

至此微信APP支付完成,功能其實不難,就是微信官方的API有點CD,大部分做微信支付遇到錯誤基本都是【簽名錯誤】這個東西下面是遇到這個錯誤的排查方法

【簽名錯誤排查】

1、xml拼接時候排序一定要按照下面這張圖,每次說到這里就想吐槽微信*****

2、使用微信簽名工具檢查簽名和程序生成的是否一致,選擇MD5、XML,然后把請求的參數xml(xmlInfo)放進去,看看是否校驗通過:簽名校驗

3、如果簽名工具校驗通過,說明程序沒有問題,如果到了這一步,大部分可以鎖定是你的賬號問題或者是API秘鑰的問題了

首先檢查賬戶有沒有開通APP支付功能,還有一點,你開通后,微信會給你賬戶打一筆驗證款,你要點擊確認和輸入金額,這不操作是一定要有的具體操作請參照微信開放平台

4、API秘鑰這里有兩點需要聲明,API秘鑰有時候會出現第一次設置的不能使用,需要多設置幾次,還有就是微信官方說的,API秘鑰設置成功15分鍾后才會生效

5、調用微信統一下單時候傳的訂單金額total_fee參數是int類型,這也是一個坑坑坑

6、調用統一下單接口時傳參數名稱要和微信上面的一樣,千萬別出現大寫,不然絕對簽名錯誤:統一下單接口傳參

7、如果使用簽名工具校驗沒通過,大部分錯誤是出在編碼格式上面,可以把所有編碼格式改成UTF-8,如果有參數的值是中文,可以暫時改成英文,如果英文簽名成功,基本鎖定就是編碼格式問題了

 

大部分錯誤都是在這幾點上,耐下心思慢慢排,可以多百度一下,總有能解決你的問題的博客


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM