微信小程序支付
微信小程序支付流程
如下图所示,微信支付官方给出了小程序支付的流程

微信图示开发使用步骤
- 用户进入小程序,选择商品服务,确认下单;
- 小程序前台将用户的请求以及用户信息(openid),提交到小程序后台;
- 小程序后台生成预订单,调用微信支付的统一下单接口,将小程序的预订单提交到微信支付;
- 通过返回的return_code字段,判断提交成功后,获取微信支付返回的成功信息即预付单信息,包括prepay_id;
- 将微信返回的预付单信息,加上其他必要信息,签名后,返回给前端用于拉起微信收银台,完成支付。
- 根据小程序后台提交预订单到微信后台时所提交的通知地址,或小程序主动调用微信支付接口,可查询支付结果。
小程序后台调用微信支付预订单接口
前提参数:
//小程序appidprivate String appid;//小程序关联的商户号private String partner;//商户号的秘钥private String partnerkey;- 参数封装,小程序调用微信预订单借口至少需要封装以下,其他参考微信支付
//1.参数封装Map param=new HashMap();//公众账号IDparam.put("appid", appid);//商户号param.put("mch_id", partner);//随机字符串param.put("nonce_str", WXPayUtil.generateNonceStr());param.put("body", "芬达");//交易订单号param.put("out_trade_no", outTradeNo);//金额(分)param.put("total_fee", totalFee);param.put("spbill_create_ip", "127.0.0.1");param.put("notify_url", "https://www.baidu.com");//交易类型param.put("trade_type", "JSAPI");//用户标示param.put("openid", openid);- 至关重要的签名,在封装参数的最后一步进行,根据微信官方提供的工具类WXPayUtil可以实现;
String xmlParam = WXPayUtil.generateSignedXml(param, partnerkey);System.out.println("请求的参数:"+xmlParam);- 调用微信接口,需要传xml格式的参数,可以使用**WXPayUtil.generateSignedXml(param, partnerkey)**方法将HashMap类型的参数转换为xml类型,顺便将传入的参数按,秘钥加密封装进一个签名,调用该方法得出的参数就是带有签名的xml类型参数了。
- 直接调用该方法获得请求数据后,调用接口获得结果,这里我用的是一个HttpClient工具类,方便发送https请求,网上随处可以找到。
//2.发送请求HttpClient httpClient=new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");httpClient.setHttps(true);httpClient.setXmlParam(xmlParam);httpClient.post();//3.获取结果String xmlResult = httpClient.getContent();MapString, String mapResult = WXPayUtil.xmlToMap(xmlResult);System.out.println("微信返回结果"+mapResult);- 微信返回的结果,包括微信的签名,调起支付的prepay_id等数据
返回前台数据用于调起微信支付收银台
- 调用wx.requestPayment(OBJECT)发起微信支付
- Object参数说明
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| timeStamp | String | 是 | 时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间 |
| nonceStr | String | 是 | 随机字符串,长度为32个字符以下。 |
| package | String | 是 | 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=* |
| signType | String | 是 | 签名类型,默认为MD5,支持HMAC-SHA256和MD5。注意此处需与统一下单的签名类型一致 |
| paySign | String | 是 | 签名,具体签名方案参见微信公众号支付帮助文档; |
| success | Function | 否 | 接口调用成功的回调函数 |
| fail | Function | 否 | 接口调用失败的回调函数 |
| complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
- 必要的五个参数,除了随机字符串,和签名外其他都可自行获得。随机字符串推荐用微信工具类**WXPayUtil.generateNonceStr()**获得随机字符串。
- 签名的获得:
·签名的获得可以根据官方签名规则,自己去手动加密获得签名。
. 根据WXPayUtil工具类去加密WXPayUtil.generateSignature(repData,partnerkey),此方法就是对Map类型的参数repData,用partnerKey进行签名,并返回签名。 - 获得签名的注意事项
通过工具类获得签名时,有且只需五个参数,且要注意:- 跟提交到微信支付预订单时的参数不一样,这里需要注意区分大小写,此处均为驼峰写法,一定注意是appId,I是大写,其他参数也是一样。
- 一定要添上签名类型signType,看源码发现官方工具类默认就是按照MD5加密的,所以我一直以为不需要添加签名方式,因为调用接口时数据签名也未添加签名方式,此处一定区分开,否则把数据发送给前端调用会发生验证签名失败。
- 代码如下:
//返回前端数据if (mapResult.get("return_code").equals("SUCCESS")){//返回给APP端的参数,APP端再调起支付接口MapString,String repData = new HashMap();//注意参数要区分大小写repData.put("appId",appid);//repData.put("prepayid",mapResult.get("prepay_id"));String packag="prepay_id="+mapResult.get("prepay_id");repData.put("package",packag);//要添加签名方式repData.put("signType","MD5");repData.put("nonceStr",WXPayUtil.generateNonceStr());repData.put("timeStamp",String.valueOf(System.currentTimeMillis()/1000));//签名String sign = WXPayUtil.generateSignature(repData,partnerkey);repData.put("prepayid",mapResult.get("prepay_id"));repData.put("mch_id",partner);repData.put("sign",sign);repData.put("timestamp",repData.get("timeStamp"));return repData; - 前端根据返回的数据,一一对应调用方法就能调起微信支付收银台了
BUG总结
- 调用微信预订单接口失败
- 商户号未与小程序绑定
- 通知地址不是https类型
- 交易类型没指定为JSAPI
- 订单号重复
- 可以正常调用微信预订单接口,能获得微信支付返回的prepay_id,但是小程序调起收银台失败
- 参数错误,会返回调用支付jsapi缺少参数:total_fee,此时与签名没关系,需要检查方法参数,随机字符串和package对应的参数值,还有就是,下预订单使用的用户openid和拉起支付的用户,必须是同一个,不然会报错,我就是遇到这个错误。
- 支付验证签名失败,这个与获得签名有关系,返回的签名不正确
- 自己手动获取签名,要注意参数的顺序以及大小写
- 使用微信工具类获得签名时,也要注意大小写,并且在要签名的参数中加上签名方式repData.put(“signType”,“MD5”);。
总结
- 最后我把WXPayUtil工具类的maven地址贴出来
dependencygroupIdcom.github.wxpay/groupIdartifactIdwxpay-sdk/artifactIdversion0.0.3/version/dependency- 将整个后端发起预订单的代码贴出来,仅供参考,根据业务不同在变化
/** *创建预订单信息,发起支付 */@Overridepublic Map createNative(String outTradeNo, String totalFee ,String openid) {//1.参数封装Map param=new HashMap();//公众账号IDparam.put("appid", appid);//商户号param.put("mch_id", partner);//随机字符串param.put("nonce_str", WXPayUtil.generateNonceStr());param.put("body", "芬达");//交易订单号param.put("out_trade_no", outTradeNo);//金额(分)param.put("total_fee", totalFee);param.put("spbill_create_ip", "127.0.0.1");param.put("notify_url", "https://www.baidu.com");//交易类型param.put("trade_type", "JSAPI");//用户标示param.put("openid", openid);try {String xmlParam = WXPayUtil.generateSignedXml(param, partnerkey);System.out.println("请求的参数:"+xmlParam);//2.发送请求HttpClient httpClient=new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");httpClient.setHttps(true);httpClient.setXmlParam(xmlParam);httpClient.post();//3.获取结果String xmlResult = httpClient.getContent();MapString, String mapResult = WXPayUtil.xmlToMap(xmlResult);System.out.println("微信返回结果"+mapResult);//返回前端数据if (mapResult.get("return_code").equals("SUCCESS")){//返回给APP端的参数,APP端再调起支付接口MapString,String repData = new HashMap();repData.put("appId",appid);String packag="prepay_id="+mapResult.get("prepay_id");repData.put("package",packag);repData.put("signType","MD5");repData.put("nonceStr",WXPayUtil.generateNonceStr());repData.put("timeStamp",String.valueOf(System.currentTimeMillis()/1000));//签名String sign = WXPayUtil.generateSignature(repData,partnerkey);repData.put("prepayid",mapResult.get("prepay_id"));repData.put("mch_id",partner);repData.put("sign",sign);repData.put("timestamp",repData.get("timeStamp"));return repData;}} catch (Exception e) {e.printStackTrace();}return new HashMap();}前端示例代码
wx.requestPayment({'timeStamp': '','nonceStr': '','package': '','signType'
版权声明
即速应用倡导尊重与保护知识产权。如发现本站文章存在版权问题,烦请提供版权疑问、身份证明、版权证明、联系方式等发邮件至197452366@qq.com ,我们将及时处理。本站文章仅作分享交流用途,作者观点不等同于即速应用观点。用户与作者的任何交易与本站无关,请知悉。













