本以为没有机会接触鼎鼎大名的支付宝和微信接口(公司本身是做第三方支付的),最近由于一个售货机项目需要对接银联,支付宝和微信接口,因为我自身已经对接了银联,之后根据安排,由我对接微信的相关接口。话不多说,让我们开启踩坑之旅。

 对接微信支付接口准备工作:

     1.微信支付文档地址:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_1

2.微信支付签名验证地址:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=20_1

3.下载微信支付官方demo(根据自身需求):https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=11_1

4.申请相应的账号,包括:微信支付商户号,公众号ID:appid,appsecret,key,以及业务需要有可能用到的证书文件

接下来所有的示例都用统一下单接口来展现

  • 第一步:阅读文档

进入微信支付文档首页,根据我们使用微信支付的不同场景选择不同的文档来进行阅读,否则,你就有可能因为文档阅读错误导致demo跑不通而到处找错。

仔细阅读方框中的文档说明后,我们就可以进入到API列表中的统一下单接口中,准备对接此接口

请务必注意传递字段的描述,微信支付文档中有很多地方在传递参数中,如果某个必传参数触发某个条件,那就需要多传递另外的参数,务必看仔细后再用demo去进行调用。

  • 第二步:修改官方demo进行测试

此处为什么说要修改官方demo,因为官方demo只提供了必要的结构和代码,相关我们自己的参数还需要自己去实现,打比方说:微信demo中有一个类:WXPayConfig,是一个抽象类,你就必须先实现里面的方法,然后自己写一个测试用例进行调用和调试。

和官方demo相比,我只增加了这两个类来分别实现相应的接口,统一下单接口中的测试和修改基本都在WXPay中完成,下面我贴上这两个类的代码,仅供参考。

WxPayConfigImpl类代码:

package com.github.wxpay.sdk;import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;public class WxPayConfigImpl extends WXPayConfig{private byte[] certData;private static WxPayConfigImpl INSTANCE;//公众号AppIDprivate String appId = "";//商户号private String mchId = "";//keyprivate String key = "";private WxPayConfigImpl() throws Exception{
//        String certPath = "D://CERT/common/apiclient_cert.p12";
//        File file = new File(certPath);
//        InputStream certStream = new FileInputStream(file);
//        this.certData = new byte[(int) file.length()];
//        certStream.read(this.certData);
//        certStream.close();}public static WxPayConfigImpl getInstance() throws Exception{if (INSTANCE == null) {synchronized (WxPayConfigImpl.class) {if (INSTANCE == null) {INSTANCE = new WxPayConfigImpl();}}}return INSTANCE;}public String getAppID() {return this.appId;}public String getMchID() {return this.mchId;}public String getKey() {return this.key;}public InputStream getCertStream() {ByteArrayInputStream certBis;certBis = new ByteArrayInputStream(this.certData);return certBis;}public int getHttpConnectTimeoutMs() {return 2000;}public int getHttpReadTimeoutMs() {return 10000;}IWXPayDomain getWXPayDomain() {return WXPayDomainSimpleImpl.instance();}public String getPrimaryDomain() {return "api.mch.weixin.qq.com";}public String getAlternateDomain() {return "api2.mch.weixin.qq.com";}@Overridepublic int getReportWorkerNum() {return 1;}@Overridepublic int getReportBatchSize() {return 2;}
}

WXPayDomainSimpleImp类代码:

package com.github.wxpay.sdk;
import org.apache.http.conn.ConnectTimeoutException;import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;/*** Created by blaketang on 2017/6/16.*/
public class WXPayDomainSimpleImpl implements IWXPayDomain {private WXPayDomainSimpleImpl(){}private static class WxpayDomainHolder{private static IWXPayDomain holder = new WXPayDomainSimpleImpl();}public static IWXPayDomain instance(){return WxpayDomainHolder.holder;}public synchronized void report(final String domain, long elapsedTimeMillis, final Exception ex) {DomainStatics info = domainData.get(domain);if(info == null){info = new DomainStatics(domain);domainData.put(domain, info);}if(ex == null){ //successif(info.succCount >= 2){    //continue succ, clear error countinfo.connectTimeoutCount = info.dnsErrorCount = info.otherErrorCount = 0;}else{++info.succCount;}}else if(ex instanceof ConnectTimeoutException){info.succCount = info.dnsErrorCount = 0;++info.connectTimeoutCount;}else if(ex instanceof UnknownHostException){info.succCount = 0;++info.dnsErrorCount;}else{info.succCount = 0;++info.otherErrorCount;}}public synchronized DomainInfo getDomain(final WXPayConfig config) {DomainStatics primaryDomain = domainData.get(WXPayConstants.DOMAIN_API);if(primaryDomain == null ||primaryDomain.isGood()) {return new DomainInfo(WXPayConstants.DOMAIN_API, true);}long now = System.currentTimeMillis();if(switchToAlternateDomainTime == 0){   //first switchswitchToAlternateDomainTime = now;return new DomainInfo(WXPayConstants.DOMAIN_API2, false);}else if(now - switchToAlternateDomainTime < MIN_SWITCH_PRIMARY_MSEC){DomainStatics alternateDomain = domainData.get(WXPayConstants.DOMAIN_API2);if(alternateDomain == null ||alternateDomain.isGood() ||alternateDomain.badCount() < primaryDomain.badCount()){return new DomainInfo(WXPayConstants.DOMAIN_API2, false);}else{return new DomainInfo(WXPayConstants.DOMAIN_API, true);}}else{  //force switch backswitchToAlternateDomainTime = 0;primaryDomain.resetCount();DomainStatics alternateDomain = domainData.get(WXPayConstants.DOMAIN_API2);if(alternateDomain != null)alternateDomain.resetCount();return new DomainInfo(WXPayConstants.DOMAIN_API, true);}}static class DomainStatics {final String domain;int succCount = 0;int connectTimeoutCount = 0;int dnsErrorCount =0;int otherErrorCount = 0;DomainStatics(String domain) {this.domain = domain;}void resetCount(){succCount = connectTimeoutCount = dnsErrorCount = otherErrorCount = 0;}boolean isGood(){ return connectTimeoutCount <= 2 && dnsErrorCount <= 2; }int badCount(){return connectTimeoutCount + dnsErrorCount * 5 + otherErrorCount / 4;}}private final int MIN_SWITCH_PRIMARY_MSEC = 3 * 60 * 1000;  //3 minutesprivate long switchToAlternateDomainTime = 0;private Map<String, DomainStatics> domainData = new HashMap<String, DomainStatics>();
}

记下来就是展现你有没有仔细看文档的时候了,我们可以写个测试类,也可以直接写个main方法,我这里因为后续要集成到代码中,所以我直接用main方法直接运行

<xml>
<nonce_str>8SwC0RG5WpHXPZrykLxEq7chaYFrKCbd</nonce_str>
<out_trade_no>L0000000000000000026</out_trade_no>
<total_fee>10</total_fee>
<product_id>359</product_id>
<appid></appid>
<sign></sign>
<trade_type>NATIVE</trade_type>
<body>福优售货机</body>
<notify_url>http://222.186.36.87:8086/paytest/weixin/payNotify</notify_url>
<mch_id></mch_id>
<spbill_create_ip>222.186.36.87</spbill_create_ip>
<sign_type>MD5</sign_type>
</xml>

此处为使用NATIVE支付时传递的参数(此处传递的是必传参数,根据业务需要大家可以根据文档来灵活使用),这里需要给大家说一下微信的签名验证工具

一般情况下,只要正确调用了相关的接口,是不会出现签名不过的情况,但就是有一些拿到官方文档后大改特改的人,所以这个时候需要用到微信的签名验证工具,地址在博客开头。

具体用法:拿到上面我展现的xml文件(debug找到输出地方打印即可),放到下图的文本框中进行验证

最终进行签名的校验即可。

  • 第三步:解决过程中遇到的bug

1.切记,必须拿到最新的商户参数和密钥,并且保证正确可用

2.拿到demo后全局浏览后,补充必要文件和参数

3.根据文档传递参数,注意文档的备注

4.参数签名为MD5,注意追踪demo默认签名类型

  • 第四步:生成二维码进行支付

统一下单接口支付成功后,会返回你一串以weixin.开头的url地址,用二维码生成工具生成后,即可用微信扫一扫功能扫码付款了,注意,传递金额是以分为单位,测试时不要金额传递过多哟。

  • 第五步:接收支付成功回调
public void payNotify() {try {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成mapMap<String, String> m = new HashMap<String, String>();m = XMLUtil.doXMLParse(sb.toString());System.out.println("微信支付,支付通知数据:"+m.toString());//过滤空 设置 TreeMapSortedMap<Object,Object> packageParams = new TreeMap<Object,Object>();Iterator it = m.keySet().iterator();while (it.hasNext()) {String parameter = (String) it.next();String parameterValue = m.get(parameter);String v = "";if(null != parameterValue) {v = parameterValue.trim();}packageParams.put(parameter, v);}//判断签名是否正确if(PayCommonUtil.isTenpaySign("UTF-8", packageParams,key)) {//------------------------------//处理业务开始//------------------------------String resXml = "";if(VendorConstant.Weixin.SUCCESS.equals((String)packageParams.get("result_code"))){// 这里是支付成功//执行自己的业务逻辑String mch_id = (String)packageParams.get("mch_id");String openid = (String)packageParams.get("openid");String is_subscribe = (String)packageParams.get("is_subscribe");String out_trade_no = (String)packageParams.get("out_trade_no");String result_code = (String)packageParams.get("result_code");String total_fee = (String)packageParams.get("total_fee");String transaction_id = (String)packageParams.get("transaction_id");System.out.println("mch_id:"+mch_id);System.out.println("openid:"+openid);log.info("is_subscribe:"+is_subscribe);log.info("out_trade_no:"+out_trade_no);log.info("result_code:"+result_code);log.info("total_fee:"+total_fee);log.info("transaction_id:",transaction_id);payCombineService.notifyPayResult("4",divideAmount(total_fee),out_trade_no,result_code,transaction_id);//执行自己的业务逻辑log.info("支付成功");//通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"+ "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";} else {log.info("支付失败,错误信息:" + packageParams.get("err_code"));resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"+ "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";}//------------------------------//处理业务完毕//------------------------------BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());out.write(resXml.getBytes());out.flush();out.close();} else{log.info("通知签名验证失败");}}catch (Exception e){e.printStackTrace();}}

因为此处的回调代码已经集成到公司项目里面了,这里就只贴出相应的代码点到为止,相应的工具类大家可以到支付回调工具类下载,配套使用更佳哦。

总结:实际上,微信支付能对接全国的开发者是有其道理的,我遇到问题的时候在百度的时候碰到很多这样的语句,都说微信支付文档是大坑,确实,很多时候有很多问题都是自己不仔细,然后微信接口提示你签名错误,其实,只要认真看了微信官方文档,绝大多数问题都可以迎刃而解,很多时候都是自己不细心导致的。所以,有些时候,细心最重要。

下一波我将介绍微信退款和退款结果通知的相关内容,剧透一下下:退款结果通知又是一个小坑。

微信支付-----统一下单接口对接相关推荐

  1. APP 对接 java 微信支付统一下单接口

    首先插入微信支付的时序图 统一下单时候的请求对象,需要把这个转为xml 文件格式所以需要在pom.xml 文件中导入 .和微信支付的sdk <dependency> <groupId ...

  2. java微信支付 [统一下单接口] 与 [订单查询接口] 调用成功完整代码与结果

    公司最近要搞微信支付, 之前也没有做过, 但是搞过阿里云, 想来也不是很难. 在网上找了很多贴子, 在eclipse里做了5个测试工程, 没有测试成功, 后来下了微信SDK, 也做了个测试样例, 期间 ...

  3. php微信支付mch_id参数格式错误,在.net core上,Web网站调用微信支付-统一下单接口(xml传参)一直返回错误:mch_id参数格式错误...

    一.问题描述 在调用统一下单接口时,报mch_id参数格式错误,但商户ID确实是10位数字正确的,可就是一直报这个错误 返回的错误xml如下: 二.排错过程 1.多次对比官网xml格式,确认生成的xm ...

  4. 微信支付服务器system error,调用微信支付统一下单接口出现err_code:SYSTEMERROR错误...

    调用统一下单接口: 返回如下 {'appid': 'wxxxxxxxxx', 'err_code': 'SYSTEMERROR', 'err_code_des': 'system error', 'm ...

  5. 微信支付统一下单接口返回数据乱码

    做的一个网页扫码支付 微信公众号和商户号都已经申请号,密钥也配置了 验证签名通过,有的朋友问题会处在签名验证错误上,需要MD5加密设置编码格式为UTF-8 我的问题不在这里 统一下单后返回为fail ...

  6. 【微信支付统一下单】JAVA与XML请求内容体的双向映射

    在微信支付统一下单接口文档中,请求体body和微信端返回值都是xml格式的内容. 例如: <!-- 请求微信端的内容 ---> <xml><appid>wx2421 ...

  7. 微信V3 - 微信支付统一下单 --01

    准备工作: private static PrivateKey merchantPrivateKey; static { try { merchantPrivateKey = PemUtil.load ...

  8. SpringBoot实现小程序微信支付统一下单

    SpringBoot实现微信支付统一下单 最近做小程序有需要用到微信支付,而在页面拉起微信支付前需要先进行统一下单,然后再返回参数给前端调用微信支付wx.requestPayment.网上参考了很多代 ...

  9. 微信支付 统一下单 字段 body 为中文时 报【签名错误】解决方案(C# SDK)

    微信支付 统一下单 字段 body 为中文时 报[签名错误]解决方案(C# SDK) 参考文章: (1)微信支付 统一下单 字段 body 为中文时 报[签名错误]解决方案(C# SDK) (2)ht ...

最新文章

  1. 2016阿里前端笔试题学习
  2. 初学者python编辑器-面向初学者的Python编辑器Mu
  3. 燕京理工学院java期末_英华学堂燕京理工学院的答案
  4. android canvas_Android自定义View之绘制虚线
  5. 初始化方法-在类的外部给对象增加属性的隐患
  6. rocketmq 消息指定_进大厂必备的RocketMQ你会吗?
  7. 手把手教你用Python给小姐姐美个颜
  8. python的celery的面试_面试必问的celery,你了解多少?
  9. python数据分析第一步:读取以及查看数据
  10. 比较 Python(Python 与其他语言的比较)
  11. 《Java从入门到放弃》JavaSE入门篇:JDBC(入门版)
  12. PCWorld评10大科技产品:IBM超级计算机上榜
  13. c语言顺序结构和选择结构
  14. 怎么在html的表格中加筛选,excel中表头合并单元格的筛选
  15. PHP微信固码免签系统源码+带监控APP和教程
  16. 鲁大师2021半年报电动车智能排行:九号霸榜,造车新势力崛起!
  17. 麦子学院学习视频之机器学习(1):1.1 机器学习介绍
  18. 优思学院:六西格玛黑带DOE考题分析
  19. Jersey 的使用详解
  20. Photoshop学习第4课-让你的照片漂亮一百倍的PS美颜术

热门文章

  1. abaqus Tie python脚本报错 原因令人震惊
  2. 云服务器增加虚拟内存
  3. 小米4c android版本号,小米4c的手机系统是什么?能升级安卓5.0吗?
  4. Win11找不到wt.exe如何解决?Win11终端打不开怎么办?
  5. 一碗酸爽面-倒在黎明前
  6. LaTeX \genfrac 分式命令
  7. JAVA中pin什么意思_pin是什么意思用法
  8. 智能家庭监控开发框架
  9. 看,2021年,一个普通应届生的成长之旅
  10. 手把手带你安装PyTorch指定版本嘿!