springboot 微信支付

mac2022-06-30  27

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

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

2019年06月20日 15:40:12 Snow、杨 阅读数 366   版权声明:本文为博主原创文章,遵循 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两个参数,不然微信会一直进行回调

参数配置

  #微信APP支付参数   wxpayconfig:   #商户应用appId   appid: wx383123456fbb7826   #商户ID   mch_id: 1234567011   #设备号   device_info: WEB   #商户key:api秘钥(32位)   key: VfnmAMI111111111EQjhvglWzDDO   #统一下单接口   url: https: //api.mch.weixin.qq.com/pay/unifiedorder   #回调接口   notify_url: http: //baidu.com/home/wechatnotify   wx_package: Sign=WXPay

 

微信配置类

  /**   * WxpayConfig.java   * com.prereadweb.order.config   * Copyright (c) 2019,   */   package com.prereadweb.order.config;       import lombok.Data;   import org.springframework.boot.context.properties.ConfigurationProperties;   import org.springframework.stereotype.Component;       /**   * @Description: 微信配置类   * @author: Administrator   * @date: 2019/6/17 19:35   */   @Data   @Component   @ConfigurationProperties(prefix="wxpayconfig")   public class WxpayConfig {       private String appid; // 公众账号ID       private String mch_id; // 商户号       private String device_info; // 设备号       private String key; // 商户的key【API密匙】       private String url; // api请求地址       private String notify_url; // 服务器异步通知页面路径       private String return_url; // 服务器同步通知页面路径   private String wx_package;   }

 

统一下单代码

controller层

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

 

 service层代码

  /**   * @Function: 去支付   * @author: YangXueFeng   * @Date: 2019/6/14 16:50   */   @Override   public Map<String, Object> goWeChatPay(Long orderId, HttpServletRequest request) {   Map<String, Object> map = new HashMap<>();   if(Util.isEmpty(orderId)) {   map.put("code", UserStatusEnum.ERROR.intKey());   map.put("msg", UserStatusEnum.ERROR.value());   return map;   }   //获取订单信息   PayParameterForm payParameter = orderMapper.getPayParameter(orderId);   double price = payParameter.getActualPrice();   System.out. println("price:" + price);   // 微信开放平台审核通过的应用APPID   System.out. println("appid是:" + wxpayconfig.getAppid());   System.out. println("mch_id是:" + wxpayconfig.getMch_id());   String nonce_str = Util.getRandomString( 30);   System.out. println("随机字符串是:" + nonce_str);   int total_fee = (int) (price * 100);       String total_price = null; // 订单总金额,单位为分,详见支付金额   String spbill_create_ip = WXSignUtils.getRemortIP(request); // "127.0.0.1";   System.out. println("spbill_create_ip===="+spbill_create_ip);   String notify_url = wxpayconfig.getNotify_url();   System.out. println("notify_url是:" + notify_url);   String trade_type = "APP";       // 参数:开始生成签名   SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();   parameters.put( "appid", wxpayconfig.getAppid());   parameters.put( "body", payParameter.getTitle());   parameters.put( "mch_id", wxpayconfig.getMch_id());   parameters.put( "nonce_str", nonce_str);   parameters.put( "notify_url", notify_url);   parameters.put( "out_trade_no", String.valueOf(payParameter.getOrderId()));   /*   parameters.put("total_fee", total_fee);   */   parameters.put( "spbill_create_ip",spbill_create_ip);   parameters.put( "total_fee", 1);   parameters.put( "trade_type", trade_type);   String sign = WXSignUtils.createSign( "UTF-8", parameters);   System.out. println("签名是:" + sign);   Unifiedorder unifiedorder = new Unifiedorder();   unifiedorder.setAppid(wxpayconfig.getAppid());   unifiedorder.setBody(payParameter.getTitle());   unifiedorder.setMch_id(wxpayconfig.getMch_id());   unifiedorder.setNonce_str(nonce_str);   unifiedorder.setNotify_url(notify_url);   unifiedorder.setOut_trade_no(String.valueOf(payParameter.getOrderId()));   unifiedorder.setSpbill_create_ip(spbill_create_ip);   unifiedorder.setTotal_fee( 1);   unifiedorder.setTrade_type(trade_type);   unifiedorder.setSign(sign);       // 构造xml参数   String xmlInfo = HttpXmlUtils.xmlInfo(unifiedorder);   System.out. println("xmlInfo:" + xmlInfo);       String wxUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";   String method = "POST";   String weixinPost = HttpXmlUtils.httpsRequest(wxUrl, method, xmlInfo).toString(); // 请求微信   System.out. println("weixinPost:" + weixinPost);   UnifiedorderResult unifiedorderResult = ParseXMLUtils.jdomParseXml(weixinPost); // 解析微信的反馈   if (unifiedorderResult != null) {   if ("SUCCESS".equals(unifiedorderResult.getReturn_code())) {   if("INVALID_REQUEST".equals(unifiedorderResult.getErr_code())){   map.put("code", UserStatusEnum.ERROR.intKey());   map.put("msg", "参数错误");   return map;   }   // 开始拼接App调起微信的参数   SortedMap<Object, Object> wxAppparameters = new TreeMap<Object, Object>();   wxAppparameters.put( "appid", unifiedorderResult.getAppid());   wxAppparameters.put( "partnerid", unifiedorderResult.getMch_id());   wxAppparameters.put( "prepayid", unifiedorderResult.getPrepay_id());   wxAppparameters.put( "package", wxpayconfig.getWx_package());   wxAppparameters.put( "noncestr", nonce_str);   wxAppparameters.put( "timestamp", String.valueOf(new Date().getTime()).substring(0, 10));   wxAppparameters.put( "sign", WXSignUtils.createSign("UTF-8", wxAppparameters));   map.put("code", UserStatusEnum.SUCCESS.intKey());   map.put("msg", UserStatusEnum.SUCCESS.value());   map.put("data", wxAppparameters);   return map;   } else {   System.out. println("错误原因为:" + unifiedorderResult.getReturn_msg());   map.put("code", UserStatusEnum.ERROR.intKey());   map.put("msg", unifiedorderResult.getReturn_msg());   return map;   }   } else {   System.out. println("服务端请求微信的返回值异常。");   map.put("code", UserStatusEnum.ERROR.intKey());   map.put("msg", "服务端请求微信的返回值异常。");   return map;   }   }

 

此处签名时参数的排序如下↓

谨记!这是微信挖的一个坑,如果不按照这个排序的话,你的统一下单接口很有可能会一直返回:签名失败

返回参数:

微信回调函数

controller层

声明:此处要有返回值,如果你的项目配置了拦截器,记得把这个方法的路径放开,不然微信会访问不到

  /**   * @Function: 微信支付回调   * @author: YangXueFeng   * @Date: 2019/6/18 18:50   */   @RequestMapping("/wechatnotify")   public String weChatNotify(HttpServletRequest request) {   String returnXML = null;   try {   returnXML = weChatService.weChatNotify(request);   } catch (Exception e) {   e.printStackTrace();   }   return returnXML;   }

 

service层

  /**   * @Function: 微信回调接口   * @author: YangXueFeng   * @Date: 2019/6/17 11:05   */   @ Override   public String weChatNotify(HttpServletRequest request) throws Exception {   Map<String, String> map = new HashMap<>();   System.out.println("----------------微信回调开始啦----------------------");   // 读取参数   InputStream inputStream;   StringBuffer sb = new StringBuffer();   inputStream = request.getInputStream();   String s;   BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));   while ((s = in.readLine()) != null) {   sb.append(s);   }   in.close();   inputStream.close();   // 解析xml成map   Map<String, String> m = new HashMap<String, String>();   m = WXSignUtils.doXMLParse(sb.toString());   // 过滤空 设置 TreeMap   SortedMap<Object, Object> packageParams = new TreeMap<Object, Object>();   Iterator<String> it = m.keySet().iterator();   while (it.hasNext()) {   String parameter = it.next();   String parameterValue = m.get(parameter);       String v = "";   if (null != parameterValue) {   v = parameterValue.trim();   }   System.out.println("p:" + parameter + ",v:" + v);   packageParams.put(parameter, v);   }   // 微信支付的API密钥   String key = wxpayconfig.getKey();   if(!isTenpaySign("UTF-8", packageParams, key)){   map.put("return_code", "FAIL");   map.put("return_msg", "return_code不正确");   return StringUtil.GetMapToXML(map);   }   //返回状态存入redis中   if(m.get("return_code").equals("SUCCESS")){   RedisUtil.set("wx"+m.get("out_trade_no"),m.get("result_code"),300);   }   if (isTenpaySign("UTF-8", packageParams, key)) {   // 验证通过   if ("SUCCESS".equals((String) packageParams.get("result_code"))) {   String out_trade_no = (String) packageParams.get("out_trade_no");   /* 订单不为空 */   if (!Util.isEmpty(out_trade_no)) {   //支付成功后的业务处理   OrderEntity order = orderMapper.getOrderInfo(Long.valueOf(out_trade_no));   if(!Util.isEmpty(order)){   order.setStatus( CalculatStaticConstant.CHECK_ONE);   order.setCompleteTime( DateUtil.currentDate());   orderMapper.updateOrder(order);   System.out.println("----------------修改订单状态----------------------");   }   /* 添加支付信息 */   OrderPayEntity orderPay = new OrderPayEntity();   orderPay.setId( Long.valueOf(IdUtils.getPrimaryKey()));   orderPay.setOrderId(order.getId());   orderPay.setUserId(order.getUserId());   orderPay.setPayPrice(order.getActualPrice());   orderPay.setPayType( PayTypeEnum.WE_CHAT_PAY.intKey());   orderPay.setStatus( CalculatStaticConstant.CHECK_ONE);   orderPay.setPayTime( DateUtil.currentDate());   orderMapper.saveOrderPay(orderPay);   System.out.println("----------------添加支付信息----------------------");   map.put("return_code", "SUCCESS");   map.put("return_msg", "OK");   return StringUtil.GetMapToXML(map);   }   }   } else {   System.out.println("支付失败");   map.put("return_code", "error");   map.put("return_msg", "支付失败");   return StringUtil.GetMapToXML(map);   }   System.out.println("支付失败");   System.out.println("支付失败");   map.put("return_code", "error");   map.put("return_msg", "支付失败");   return StringUtil.GetMapToXML(map);   }   /**   * @Function: 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。   * @author: YangXueFeng   * @Date: 2019/6/17 17:10   */   @SuppressWarnings( "rawtypes")   public static boolean isTenpaySign(String characterEncoding, SortedMap<Object, Object> packageParams,   String API_KEY) {   StringBuffer sb = new StringBuffer();   Set es = packageParams.entrySet();   Iterator it = es.iterator();   while (it.hasNext()) {   Map.Entry entry = (Map.Entry) it.next();   String k = (String) entry.getKey();   String v = (String) entry.getValue();   if (!"sign".equals(k) && null != v && !"".equals(v)) {   sb.append(k + "=" + v + "&");   }   }   sb.append( "key=" + API_KEY);   // 算出摘要   String mysign = MD5Util.MD5Encode(sb.toString()).toLowerCase();   String tenpaySign = ((String) packageParams.get("sign")).toLowerCase();   return tenpaySign.equals(mysign);   }

 

相关工具类

微信签名工具类

  /**   * WXSignUtils.java   * com.prereadweb.order.util   * Copyright (c) 2019,   */   package com.prereadweb.order.util;       import com.prereadweb.utils.MD5Util;   import org.jdom.Document;   import org.jdom.JDOMException;   import org.jdom.input.SAXBuilder;       import javax.servlet.http.HttpServletRequest;   import java.io.ByteArrayInputStream;   import java.io.IOException;   import java.io.InputStream;   import java.util.*;       /**   * @Description: 微信支付签名   * @author: Administrator   * @date: 2019/6/17 15:43   */   public class WXSignUtils {       /* API秘钥 */   private static String Key ="VfnmAMasdasdasdasWzDDO";       /**   * 微信支付签名算法sign   * @param characterEncoding   * @param parameters   * @return   */   public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters){   StringBuffer sb = new StringBuffer();   Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)   Iterator it = es.iterator();   while(it.hasNext()) {   Map.Entry entry = (Map.Entry)it.next();   String k = (String)entry.getKey();   Object v = entry.getValue();   if(null != v && !"".equals(v)   && ! "sign".equals(k) && !"key".equals(k)) {   sb.append(k + "=" + v + "&");   }   }   sb.append( "key=" + Key);   System.out.println( "字符串拼接后是:"+sb.toString());   String sign = MD5Util.MD5Encode(sb.toString()).toUpperCase();   return sign;   }       /**   * @Function: 获取IP   * @author: YangXueFeng   * @Date: 2019/6/17 16:44   */   public static String getRemortIP(HttpServletRequest request) {   if (request.getHeader("x-forwarded-for") == null) {   return request.getRemoteAddr();   }   return request.getHeader("x-forwarded-for");   }       /**   * @Function: 解析XML   * @author: YangXueFeng   * @Date: 2019/6/17 17:07   */   public static Map doXMLParse(String strxml) throws JDOMException,   IOException {   strxml = strxml.replaceFirst( "encoding=\".*\"", "encoding=\"UTF-8\"");       if (null == strxml || "".equals(strxml)) {   return null;   }       Map m = new HashMap();       InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));   SAXBuilder builder = new SAXBuilder();   Document doc = builder.build( in);   org.jdom.Element root = doc.getRootElement();   List list = root.getChildren();   Iterator it = list.iterator();   while (it.hasNext()) {   org.jdom.Element e = (org.jdom.Element) it.next();   String k = e.getName();   String v = "";   List children = e.getChildren();   if (children.isEmpty()) {   v = e.getTextNormalize();   } else {   v = getChildrenText(children);   }       m.put(k, v);   }       // 关闭流   in.close();       return m;   }       public static String getChildrenText(List children) {   StringBuffer sb = new StringBuffer();   if (!children.isEmpty()) {   Iterator it = children.iterator();   while (it.hasNext()) {   org.jdom.Element e = (org.jdom.Element) it.next();   String name = e.getName();   String value = e.getTextNormalize();   List list = e.getChildren();   sb.append( "<" + name + ">");   if (!list.isEmpty()) {   sb.append(getChildrenText(list));   }   sb.append(value);   sb.append( "</" + name + ">");   }   }       return sb.toString();   }       }

 

统一下单提交微信参数实体类

  /**   * UnifiedorderResult.java   * com.prereadweb.order.util   * Copyright (c) 2019,   */   package com.prereadweb.order.util;       import lombok.Data;       /**   * @Description: 统一下单提交(微信参数)   * @author: Administrator   * @ date: 2019/6/17 16:11   */   @Data   public class UnifiedorderResult {   private String return_code;   private String return_msg;   private String appid;   private String mch_id;   private String device_info;   private String nonce_str;   private String sign;   private String result_code;   private String err_code;   private String err_code_des;   private String trade_type;   private String prepay_id;   }

 

DOM解析

  /**   * ParseXMLUtils.java   * com.prereadweb.order.util   * Copyright (c) 2019, 北京聚智未来科技有限公司版权所有.   */   package com.prereadweb.order.util;       import com.prereadweb.utils.Util;   import org.dom4j.Document;   import org.dom4j.DocumentException;   import org.dom4j.DocumentHelper;   import org.dom4j.Element;   import org.dom4j.io.SAXReader;   import org.jdom.input.SAXBuilder;   import org.xml.sax.InputSource;       import java.io.StringReader;   import java.util.Iterator;   import java.util.List;       /**   * @Description: DOM解析   * @author: Administrator   * @date: 2019/6/17 15:50   */   public class ParseXMLUtils {       /**   * 1、DOM解析   */   @SuppressWarnings( "rawtypes")   public static void beginXMLParse(String xml){   Document doc = null;   try {   doc = DocumentHelper.parseText(xml); // 将字符串转为XML       Element rootElt = doc.getRootElement(); // 获取根节点smsReport       System. out.println("根节点是:"+rootElt.getName());       Iterator iters = rootElt.elementIterator( "sendResp"); // 获取根节点下的子节点sms       while (iters.hasNext()) {   Element recordEle1 = (Element) iters.next();   Iterator iter = recordEle1.elementIterator( "sms");       while (iter.hasNext()) {   Element recordEle = (Element) iter.next();   String phone = recordEle.elementTextTrim( "phone"); // 拿到sms节点下的子节点stat值       String smsID = recordEle.elementTextTrim( "smsID"); // 拿到sms节点下的子节点stat值       System. out.println(phone+":"+smsID);   }   }   } catch (DocumentException e) {   e.printStackTrace();   } catch (Exception e) {   e.printStackTrace();   }   }       /**   * 2、DOM4j解析XML(支持xpath)   * 解析的时候自动去掉CDMA   * @param xml   */   public static void xpathParseXml(String xml){   try {   StringReader read = new StringReader(xml);   SAXReader saxReader = new SAXReader();   Document doc = saxReader.read(read);   String xpath = "/xml/appid";   System. out.print(doc.selectSingleNode(xpath).getText());   } catch (DocumentException e) {   e.printStackTrace();   }   }       /**   * 3、JDOM解析XML   * 解析的时候自动去掉CDMA   * @param xml   */   @SuppressWarnings( "unchecked")   public static UnifiedorderResult jdomParseXml(String xml){   UnifiedorderResult unifieorderResult = new UnifiedorderResult();   try {   StringReader read = new StringReader(xml);   // 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入   InputSource source = new InputSource(read);   // 创建一个新的SAXBuilder   SAXBuilder sb = new SAXBuilder();   // 通过输入源构造一个Document   org.jdom.Document doc;   doc = (org.jdom.Document) sb.build(source);       org.jdom.Element root = doc.getRootElement(); // 指向根节点   List<org.jdom.Element> list = root.getChildren();       if(list != null && list.size() > 0){   boolean flag1 = true;   boolean flag2 = true;   for (org.jdom.Element element : list) {   System. out.println("key是:"+element.getName()+",值是:"+element.getText());       if("return_code".equals(element.getName())){   if("FAIL".equals(element.getText())){   flag1 = false;   } else{   unifieorderResult.setReturn_code(element.getText());   }   }       if("return_msg".equals(element.getName())){   if(element.getText() != null && !"OK".equals(element.getText())){//微信支付的第一个坑,这里返回了OK,23333   System. out.println("统一下单参数有误,错误原因为:"+element.getText());   return null;   }   }       if(flag1){   if("appid".equals(element.getName())){   unifieorderResult.setAppid(element.getText());   }   if("mch_id".equals(element.getName())){   unifieorderResult.setMch_id(element.getText());   }   if("nonce_str".equals(element.getName())){   unifieorderResult.setNonce_str(element.getText());   }   if("sign".equals(element.getName())){   unifieorderResult.setSign(element.getText());   }   if("err_code".equals(element.getName())){   unifieorderResult.setErr_code(element.getText());   }   if("err_code_des".equals(element.getName())){   unifieorderResult.setErr_code_des(element.getText());   }   if("result_code".equals(element.getName())){   if("FAIL".equals(element.getText())){   flag2 = false;   System. out.println("统一下单业务结果有误,无法返回预支付交易会话标识");   } else{   unifieorderResult.setResult_code(element.getText());   }   }   }   if(flag1 && flag2 && flag2 == true){   if("trade_type".equals(element.getName())){   unifieorderResult.setTrade_type(element.getText());   }   if("prepay_id".equals(element.getName())){   System. out.println("统一下单接口成功返回预支付交易会话标识!");   unifieorderResult.setPrepay_id(element.getText());   }   }       }   return unifieorderResult;   } else{   return null;   }       } catch (Exception e) {   e.printStackTrace();   return null;   }       }       public static boolean parseInt(String key){   if(!Util.isEmpty(key)){   if(key.equals("total_fee")||key.equals("cash_fee")||key.equals("coupon_fee")||key.equals("coupon_count")||key.equals("coupon_fee_0")){   return true;   }   }       return false;   }       }

 

post提交xml格式的参数

  /**   * HttpXmlUtils.java   * com.prereadweb.order.util   * Copyright (c) 2019, 北京聚智未来科技有限公司版权所有.   */   package com.prereadweb.order.util;       import com.prereadweb.order.form.Unifiedorder;       import javax.net.ssl.HttpsURLConnection;   import java.io.*;   import java.net.HttpURLConnection;   import java.net.MalformedURLException;   import java.net.URL;       /**   * @Description: post提交xml格式的参数   * @author: Administrator   * @date: 2019/6/17 15:46   */   public class HttpXmlUtils {   /**   * 开始post提交参数到接口   * 并接受返回   * @param url   * @param xml   * @param method   * @param contentType   * @return   */   public static String xmlHttpProxy(String url,String xml,String method,String contentType){   InputStream is = null;   OutputStreamWriter os = null;       try {   URL _url = new URL(url);   HttpURLConnection conn = (HttpURLConnection) _url.openConnection();   conn.setDoInput(true);   conn.setDoOutput(true);   conn.setRequestProperty("Content-type", "text/xml");   conn.setRequestProperty("Pragma:", "no-cache");   conn.setRequestProperty("Cache-Control", "no-cache");   conn.setRequestMethod("POST");   os = new OutputStreamWriter(conn.getOutputStream());   os.write(new String(xml.getBytes(contentType)));   os.flush();       //返回值   is = conn.getInputStream();   return getContent(is, "utf-8");   } catch (MalformedURLException e) {   e.printStackTrace();   } catch (IOException e) {   e.printStackTrace();   } finally{   try {   if(os!=null){os.close();}   if(is!=null){is.close();}   } catch (IOException e) {   e.printStackTrace();   }   }   return null;   }       /**   * 解析返回的值   * @param is   * @param charset   * @return   */   public static String getContent(InputStream is, String charset) {   String pageString = null;   InputStreamReader isr = null;   BufferedReader br = null;   StringBuffer sb = null;   try {   isr = new InputStreamReader(is, charset);   br = new BufferedReader(isr);   sb = new StringBuffer();   String line = null;   while ((line = br.readLine()) != null) {   sb.append(line + "\n");   }   pageString = sb.toString();   } catch (Exception e) {   e.printStackTrace();   } finally {   try {   if (is != null){   is.close();   }   if(isr!=null){   isr.close();   }   if(br!=null){   br.close();   }   } catch (IOException e) {   e.printStackTrace();   }   sb = null;   }   return pageString;   }       /**   * 构造xml参数   * @param xml   * @return   */   public static String xmlInfo(Unifiedorder unifiedorder){   //构造xml参数的时候,至少又是个必传参数   /*   * <xml>   <appid>wx2421b1c4370ec43b</appid>   <attach>支付测试</attach>   <body>JSAPI支付测试</body>   <mch_id>10000100</mch_id>   <nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>   <notify_url>http://wxpay.weixin.qq.com/pub_v2/pay/notify.v2.php</notify_url>   <openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>   <out_trade_no>1415659990</out_trade_no>   <spbill_create_ip>14.23.150.211</spbill_create_ip>   <total_fee>1</total_fee>   <trade_type>JSAPI</trade_type>   <sign>0CB01533B8C1EF103065174F50BCA001</sign>   </xml>   */       if(unifiedorder!=null){   StringBuffer bf = new StringBuffer();   bf.append(" <xml>");       bf.append(" <appid><![CDATA[");   bf.append(unifiedorder.getAppid());   bf.append("]]> </appid>");       bf.append(" <body><![CDATA[");   bf.append(unifiedorder.getBody());   bf.append("]]> </body>");       bf.append(" <mch_id><![CDATA[");   bf.append(unifiedorder.getMch_id());   bf.append("]]> </mch_id>");       bf.append(" <nonce_str><![CDATA[");   bf.append(unifiedorder.getNonce_str());   bf.append("]]> </nonce_str>");       bf.append(" <notify_url><![CDATA[");   bf.append(unifiedorder.getNotify_url());   bf.append("]]> </notify_url>");       bf.append(" <out_trade_no><![CDATA[");   bf.append(unifiedorder.getOut_trade_no());   bf.append("]]> </out_trade_no>");       bf.append(" <spbill_create_ip><![CDATA[");   bf.append(unifiedorder.getSpbill_create_ip());   bf.append("]]> </spbill_create_ip>");       bf.append(" <total_fee><![CDATA[");   bf.append(unifiedorder.getTotal_fee());   bf.append("]]> </total_fee>");       bf.append(" <trade_type><![CDATA[");   bf.append(unifiedorder.getTrade_type());   bf.append("]]> </trade_type>");       bf.append(" <sign><![CDATA[");   bf.append(unifiedorder.getSign());   bf.append("]]> </sign>");       bf.append(" </xml>");   return bf.toString();   }       return "";   }                   /**   * post请求并得到返回结果   * @param requestUrl   * @param requestMethod   * @param output   * @return   */   public static String httpsRequest(String requestUrl, String requestMethod, String output) {   try{   URL url = new URL(requestUrl);   HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();   connection.setDoOutput(true);   connection.setDoInput(true);   connection.setUseCaches(false);   connection.setRequestMethod(requestMethod);   if (null != output) {   OutputStream outputStream = connection.getOutputStream();   outputStream.write(output.getBytes("UTF-8"));   outputStream.close();   }   // 从输入流读取返回内容   InputStream inputStream = connection.getInputStream();   InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");   BufferedReader bufferedReader = new BufferedReader(inputStreamReader);   String str = null;   StringBuffer buffer = new StringBuffer();   while ((str = bufferedReader.readLine()) != null) {   buffer.append(str);   }   bufferedReader.close();   inputStreamReader.close();   inputStream.close();   inputStream = null;   connection.disconnect();   return buffer.toString();   }catch(Exception ex){   ex.printStackTrace();   }       return "";   }   }

将map转换为xml类

  /**   * StringUtil.java   * com.prereadweb.utils   * Copyright (c) 2019, 北京聚智未来科技有限公司版权所有.   */   package com.prereadweb.utils;       import java.util.Map;       /**   * @Description: String工具类   * @author: Administrator   * @date: 2019/6/19 11:31   */   public class StringUtil {       /**   * @Function: 将map转换为xml   * @author: YangXueFeng   * @Date: 2019/6/19 11:32   */   public static String GetMapToXML(Map<String,String> param){   StringBuffer sb = new StringBuffer();   sb.append( "<xml>");   for (Map.Entry<String,String> entry : param.entrySet()) {   sb.append( "<"+ entry.getKey() +">");   sb.append(entry.getValue());   sb.append( "</"+ entry.getKey() +">");   }   sb.append( "</xml>");   return sb.toString();   }   }

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

 

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

转载于:https://www.cnblogs.com/linwenbin/p/11355925.html

最新回复(0)