• 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 + " ");
    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,如果有参数的值是中文,可以暂时改成英文,如果英文签名成功,基本锁定就是编码格式问题了

    大部分错误都是在这几点上,耐下心思慢慢排,可以多百度一下,总有能解决你的问题的博客

  • 相关阅读:
    聚会
    Wannafly summer camp Day2
    HDU6627 equation
    2019牛客暑期多校D.Big Integer
    对主席树的理解以及使用
    2019牛客暑期多校训练营(第四场)C.sequence(单调栈+线段树)
    2019 Multi-University Training Contest 1
    浅谈序列自动机
    2019江西省程序设计竞赛
    拉格朗日插值的应用
  • 原文地址:https://www.cnblogs.com/linwenbin/p/11355925.html
Copyright © 2020-2023  润新知