完美解决微信支付一个app多个签名,多个包名的问题


h5支付的资料还真叫个少,不过找到一个好的方式,按着大神的步骤去实现还真就ok了,话不多说,开始准备吧

看一下官方文档还是很必要的,知道必不可少的参数是什么:https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_20&index=1

微信支付的坑很多,特别在平台的设置上

首先需要APPID,微信支付商户号mch_id,API**key,Appsecret(secret),说明在这里https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=3_1

然后设置授权域名,在接口设置中就能找到,包括js接口安全域名和网页授权域名:

完美解决微信支付一个app多个签名,多个包名的问题

完美解决微信支付一个app多个签名,多个包名的问题


这个点进去之后会看到最下面两个:js接口安全域名,这个可以设置三个,就是填写你访问页面的域名即可


下面这个是网页授权回调域名,用于你支付完毕后回调的域名,将下载的文件放到服务器的根路径,确保可以访问,我是放在tomcat的webapp中

设置的域名要备案

完美解决微信支付一个app多个签名,多个包名的问题


然后设置支付域名,设置路径:商户平台-->产品中心-->开发配置中设置域名,

如果是公众号支付就设置对应的,要注意的是公众号支付授权域名为请求的前一级,比如你要请求http://xxx/wx/abc,那么你就设置http://xxx/wx即可

h5支付设置h5域名就行,不用后缀,直接写你要设置的域名

完美解决微信支付一个app多个签名,多个包名的问题

partnerkey需要在API中设置,需要安装证书,这个根据提示安装即可,自行设置32位partnerkey


我用的是一个大神的IJPay的springboot版,写成自己的SpringMVC版,后续都会给链接

主要用的的是封装的jar,现在maven库中已经有了,用0.8版本以上的吧,这样jdk兼容问题已经解决

完美解决微信支付一个app多个签名,多个包名的问题


着手代码

[html] view plain copy
  1. public static WxPayApiConfig getApiConfig() {  
  2.         return WxPayApiConfig.New()  
  3.                        .setAppId(appID)  
  4.                        .setMchId(mchID)  
  5.                        .setPaternerKey(partnerKey)  
  6.                        .setPayModel(WxPayApiConfig.PayModel.BUSINESSMODEL);  
  7.     }  



[html] view plain copy
  1.   
[html] view plain copy
  1. /**  
  2.      * 微信H5 支付--------------------好使  
  3.      * 注意:必须再web页面中发起支付且域名已添加到开发配置中  
  4.      */  
  5.     @RequestMapping(value ="/pay.do",method = {RequestMethod.POST,RequestMethod.GET})  
  6.     public void wapPay(HttpServletRequest request,HttpServletResponse response){  
  7.         System.out.println("--pay start--");  
  8.                 String notify_url = "https://你的域名/pay_notify.do";//这是回调地址,方法在下面  
  9.         //获取ip  
[html] view plain copy
  1.     String ip = IpKit.getRealIp(request);  
  2.     if (com.jpay.ext.kit.StrKit.isBlank(ip)) {  
  3.         ip = "127.0.0.1";  
  4.     }  
  5.       
  6.     H5ScencInfo sceneInfo = new H5ScencInfo();  
  7.       
  8.     H5 h5_info = new H5();  
  9.     h5_info.setType("Wap");  
  10.     //此域名必须在商户平台--"产品中心"--"开发配置"中添加  
  11.       
  12.     h5_info.setWap_url("http://www.xxx.com");  
  13.     h5_info.setWap_name("公司官网");  
  14.     sceneInfo.setH5_info(h5_info);  
  15.     WxPayApiConfig wxPayApiConfig=getApiConfig();  
  16.     Map<String, String> params=WxPayApiConfig.New()  
  17.                                        .setAppId(appID)  
  18.                                        .setMchId(mchID)  
  19.                                        .setBody("H5支付测试")  
  20.                                        .setSpbillCreateIp(ip)  
  21.                                        .setTotalFee("520")  
  22.                                        .setTradeType(WxPayApi.TradeType.MWEB)  
  23.                                        .setNotifyUrl(notify_url)  
  24.                                        .setPaternerKey(partnerKey)  
  25.                                        .setOutTradeNo(String.valueOf(System.currentTimeMillis()))  
  26.                                        .setSceneInfo("{\"h5_info\": {\"type\":\"IOS\",\"app_name\": \"mtgg\",\"package_name\": \"com.tencent.tmgp.sgame\"}}")  
  27.                                        .setAttach("H5支付测试")  
  28.                                        .build();  
  29.     String xmlResult = WxPayApi.pushOrder(false,params);  
  30.     Map<String, String> result = PaymentKit.xmlToMap(xmlResult);  
  31.     //返回结果  
  32.     String return_code = result.get("return_code");  
  33.     String return_msg = result.get("return_msg");  
  34.     if (!PaymentKit.codeIsOK(return_code)) {  
  35.         log.error("return_code>"+return_code+" return_msg>"+return_msg);  
  36.         throw new RuntimeException(return_msg);  
  37.     }  
  38.     String result_code = result.get("result_code");  
  39.     if (!PaymentKit.codeIsOK(result_code)) {  
  40.         log.error("result_code>"+result_code+" return_msg>"+return_msg);  
  41.         throw new RuntimeException(return_msg);  
  42.     }  
  43.     // 以下字段在return_code 和result_code都为SUCCESS的时候有返回  
  44.       
  45.     String prepay_id = result.get("prepay_id");  
  46.     String mweb_url = result.get("mweb_url");  
  47.       
  48.     log.info("prepay_id:"+prepay_id+" mweb_url:"+mweb_url);  
  49.     try {  
  50.         response.sendRedirect(mweb_url);  
  51.     } catch (IOException e) {  
  52.         e.printStackTrace();  
  53.     }  
  54. }  
先给出H5ScencInfo

[html] view plain copy
  1. package com.mtgg.entity;  
  2.   
  3. import com.jfinal.kit.JsonKit;  
  4.   
  5.   
  6. /**  
  7.  * @author Javen  
  8.  */  
  9. public class H5ScencInfo {  
  10.     private H5 h5_info;  
  11.       
  12.     public H5 getH5_info() {  
  13.         return h5_info;  
  14.     }  
  15.       
  16.     public void setH5_info(H5 h5_info) {  
  17.         this.h5_info = h5_info;  
  18.     }  
  19.       
  20.       
  21.     @Override  
  22.     public String toString() {  
  23.         return JsonKit.toJson(h5_info);  
  24.     }  
  25.       
  26.       
  27.     public static class H5{  
  28.         private String type;  
  29.         private String app_name;  
  30.         private String bundle_id;  
  31.         private String package_name;  
  32.         private String wap_url;  
  33.         private String wap_name;  
  34.         public String getType() {  
  35.             return type;  
  36.         }  
  37.         public void setType(String type) {  
  38.             this.type = type;  
  39.         }  
  40.         public String getApp_name() {  
  41.             return app_name;  
  42.         }  
  43.         public void setApp_name(String app_name) {  
  44.             this.app_name = app_name;  
  45.         }  
  46.         public String getBundle_id() {  
  47.             return bundle_id;  
  48.         }  
  49.         public void setBundle_id(String bundle_id) {  
  50.             this.bundle_id = bundle_id;  
  51.         }  
  52.         public String getPackage_name() {  
  53.             return package_name;  
  54.         }  
  55.         public void setPackage_name(String package_name) {  
  56.             this.package_name = package_name;  
  57.         }  
  58.         public String getWap_url() {  
  59.             return wap_url;  
  60.         }  
  61.         public void setWap_url(String wap_url) {  
  62.             this.wap_url = wap_url;  
  63.         }  
  64.         public String getWap_name() {  
  65.             return wap_name;  
  66.         }  
  67.         public void setWap_name(String wap_name) {  
  68.             this.wap_name = wap_name;  
  69.         }  
  70.     }  
  71. }  

注意notify_url要保证能够访问,用域名访问

最后发送mweb_url就可以打开微信进行支付了

给出支付成功的返回

[html] view plain copy
  1.   
[html] view plain copy
  1. @RequestMapping(value = "/pay_notify.do",method={RequestMethod.POST,RequestMethod.GET})  
  2.     @ResponseBody  
  3.     public void pay_notify(HttpServletRequest request,HttpServletResponse response) {  
  4.         // 支付结果通用通知文档: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7  
  5.         System.out.println("---------------支付回调----------------");  
  6.         String xmlMsg = HttpKit.readData(request);  
  7.         System.out.println("pay notice---------"+xmlMsg);  
  8.         Map<String, String> params = PaymentKit.xmlToMap(xmlMsg);  
  9. //      String appid  = params.get("appid");  
  10. //      //商户号  
  11. //      String mch_id  = params.get("mch_id");  
  12.         String result_code  = params.get("result_code");  
  13. //      String openId      = params.get("openid");  
  14. //      //交易类型  
  15. //      String trade_type      = params.get("trade_type");  
  16. //      //付款银行  
  17. //      String bank_type      = params.get("bank_type");  
  18. //      // 总金额  
  19.         String total_fee     = params.get("total_fee");  
  20.         total_fee = total_fee.substring(0,total_fee.length()-2);  
  21. //      //现金支付金额  
  22. //      String cash_fee     = params.get("cash_fee");  
  23. //      // 微信支付订单号  
  24. //      String transaction_id      = params.get("transaction_id");  
  25. //      // 商户订单号  
  26. //      String out_trade_no      = params.get("out_trade_no");  
  27. //      // 支付完成时间,格式为yyyyMMddHHmmss  
  28. //      String time_end      = params.get("time_end");  
  29.           
  30.         /////////////////////////////以下是附加参数///////////////////////////////////  
  31.           
  32.         String account      = params.get("attach");  
  33.         System.out.println("回调total_fee-->"+total_fee);  
  34.         System.out.println("回调account-->"+account);  
  35. //      String fee_type      = params.get("fee_type");  
  36. //      String is_subscribe      = params.get("is_subscribe");  
  37. //      String err_code      = params.get("err_code");  
  38. //      String err_code_des      = params.get("err_code_des");  
  39.         // 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态  
  40.         // 避免已经成功、关闭、退款的订单被再次更新  
  41. //      Order order = Order.dao.getOrderByTransactionId(transaction_id);  
  42. //      if (order==null) {  
  43.         String resXml = "";  
  44.         WxPayApiConfigKit.setThreadLocalWxPayApiConfig(getApiConfig());  
  45.         if(PaymentKit.verifyNotify(params, WxPayApiConfigKit.getWxPayApiConfig().getPaternerKey())){  
  46.             if (("SUCCESS").equals(result_code)) {  
  47.                 // TODO 根据商户订单号更改押金状态  
  48.                 System.out.println("成功,存储");  
  49.                   
  50.                 resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"  
  51.                         + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";  
  52.                   
  53.             } else {  
  54.                 //TODO FAIL支付失败  
  55.                 log.debug("支付失败的回调消息");  
  56.                 resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"  
  57.                         + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";  
  58.   
  59.             }  
  60.             BufferedOutputStream out = null;  
  61.             try {  
  62.                 out = new BufferedOutputStream(  
  63.                         response.getOutputStream());  
  64.                 out.write(resXml.getBytes());  
  65.                 out.flush();  
  66.                 out.close();  
  67.             } catch (Exception e) {  
  68.                 e.printStackTrace();  
  69.             }  
  70.         }  
  71. //      }  
  72.   
  73.     }  


这里需要注意最后的xml.put(),return PaymentKit.toXml(xml)一定要返回给微信,SUCCESS表示商户接收通知成功并校验成功,这样微信才会知道商户支付成功,否则会不断通知,这样就会重复处理数据,这个错误是致命的


上面回调我改了一下,可以做到闭嘴,不会重复通知


下面就是测试调起微信支付

完美解决微信支付一个app多个签名,多个包名的问题完美解决微信支付一个app多个签名,多个包名的问题

完美解决微信支付一个app多个签名,多个包名的问题完美解决微信支付一个app多个签名,多个包名的问题


常见错误:

1、网络环境未能通过安全验证,请稍后再试(IP改变导致的) 
2、商家参数格式有误,请联系商家解决(H5支付的referer为空导致) 
3、商家存在未配置的参数,请联系商家解决(H5支付的域名问题) 
4、支付请求已失效,请重新发起支付(有效期为5分钟) 

5、请在微信外打开订单,进行支付(H5支付不能直接在微信客户端内调起)


我遇到过一次获取code时回调了两次错误,因为code只能用一次,第二次就失效了网上说什么的都有,谁知道怎么完全解决可以留言,感谢

我的demo地址:注意回调不用demo中的,用这篇文档的回调方式,可以闭嘴(包括公众号支付):http://download.****.net/download/goligory/10044575

借鉴:http://blog.****.net/zyw_java/article/details/77507835,感兴趣可以看他的更多相关支付