【微信支付】公众号支付

一.公众号支付介绍

公众号支付是用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块完成支付。应用场景有:

◆ 用户在微信公众账号内进入商家公众号,打开某个主页面,完成支付

◆ 用户的好友在朋友圈、聊天窗口等分享商家页面连接,用户点击链接打开商家页面,完成支付

◆ 将商户页面转换成二维码,用户扫描二维码后在微信浏览器中打开页面后完成支付

二.支付账户

商户在微信公众平台(申请扫码支付、公众号支付)或开放平台(申请APP支付)按照相应提示,申请相应微信支付模式。微信支付工作人员审核资料无误后开通相应的微信支付权限。微信支付申请审核通过后,商户在申请资料填写的邮箱中收取到由微信支付小助手发送的邮件,此邮件包含开发时需要使用的支付账户信息,如图2.1所示。

图2.1 微信审核通过邮件模板

2.1中的参数说明如2.2图所示:

图2.2 账户参数说明

我写微信公众号支付时,使用了mch_id、APPID、key三个参数。

三.接口规则

1.协议规则


传输方式 :为保证交易安全性,采用HTTPS传输

提交方式 :采用POST方法提交

数据格式 :提交和返回数据都为XML格式,根节点名为xml

字符编码 :统一采用UTF-8字符编码

签名算法 :MD5,后续会兼容SHA1、SHA256、HMAC等。

签名要求 :请求和接收数据均需要校验签名

证书要求 :调用申请退款、撤销订单接口需要商户证书

判断逻辑 :先判断协议字段返回,再判断业务返回,最后判断交易状态

2.参数规定


1、交易金额(重要)

交易金额默认为人民币交易,接口中参数支付金额单位为【分】,参数值不能带小数。对账单中的交易金额单位为【元】。

外币交易的支付金额精确到币种的最小单位,参数值不能带小数点。

2、交易类型

JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付,统一下单接口trade_type的传参可参考这里

MICROPAY--刷卡支付,刷卡支付有单独的支付接口,不调用统一下单接口

3、货币类型

货币类型的取值列表:

CNY:人民币

4、时间

标准北京时间,时区为东八区;如果商户的系统时间为非标准北京时间。参数值必须根据商户系统所在时区先换算成标准北京时间,例如商户所在地为0时区的伦敦,当地时间为2014年11月11日0时0分0秒,换算成北京时间为2014年11月11日8时0分0秒。

标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数。注意:部分系统取到的值为毫秒级,需要转换成秒(10位数字)。

5、时间戳(重要)

标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数。注意:部分系统取到的值为毫秒级,需要转换成秒(10位数字)。

6、商户订单号

商户支付的订单号由商户自定义生成,仅支持使用字母、数字、中划线-、下划线_、竖线|、星号*这些英文半角字符的组合,请勿使用汉字或全角等特殊字符。微信支付要求商户订单号保持唯一性(建议根据当前系统时间加随机序列来生成订单号)。重新发起一笔支付要使用原订单号,避免重复支付;已支付过或已调用关单、撤销(请见后文的API列表)的订单号不能重新发起支付。

等等。。。

3.安全规范-算法(重要)  (微信支付接口签名校验工具


1、签名算法

第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

特别注意以下重要规则:

◆ 参数名ASCII码从小到大排序(字典序);

◆ 如果参数的值为空不参与签名;

◆ 参数名区分大小写;

◆ 验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值作校验。

◆ 微信接口可能增加字段,验证签名时必须支持增加的扩展字段

第二步,在stringA最后拼接上key得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue。

◆ key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置

举例如下:

图3.1 传送参数

第一步:对参数按照key=value的格式,并按照参数名ASCII字典序排序如下:

图3.2 ASCII字典序排序

第二步:拼接API密钥:

图3.3 拼接密钥

最终得到最终发送的数据:

图3.4 发送的数据

2、生成随机数算法

微信支付API接口协议中包含字段nonce_str,主要保证签名不可预测。我们推荐生成随机数算法如下:调用随机数函数生成,将得到的值转换为字符串。

四.实践(重要)

1.统一下单

◆ 两个必传参数 :goodsId(商品id)  openid(用户标识)

◆ 生成订单号封装成对象,并插入到订单表中

图4.1 订单数据表

◆ 请求下单时微信必须传递的参数

图 4.2.1 微信下单参数介绍
图 4.2.2 微信下单参数介绍

◆ 请求数据先插入表wxpay_request以便查询

图 4.3 请求记录表

◆ 正式下单 

WXPay wxPay =new WXPay(wxPayConfig);

Map resp = wxPay.unifiedOrder(order);

上两行是微信公众号支付的核心(重要)

其中WXPayConfig这个接口需要我们自己来实现

图 4.4 WXPayConfig接口

上图中的5个抽象方法是需要我们自己创建MyConfig类来实现的

其中的getCertStream()可直接返回null即可,但是getWXPayDomain()此方法实现不能返回null,否则会报如下错误:

图 4.5 微信支付内部源码

getWXPayDomain()方法返回的是一个IWXPayDomain接口,我们创建一个WXPayDomain类来实现这个接口,其中IWXPayDomain中的信息如下图:

图 4.6   IWXPayDomain接口

其中report(String s, long l, Exception e)实现但是不做处理,getDomain方法返回

new DomainInfo(WXPayConstants.DOMAIN_API, true);即可

此时,万事具备,只欠下单操作了:

WXPay wxPay =new WXPay(wxPayConfig);

Map resp = wxPay.unifiedOrder(order);

在这个我说明一下在这里栽的坑。下单的时候,微信那边是要穿spbill_create_ip这个参数的,

这个参数微信给的解释是:

APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。

我在本地测试时,获取本地IP一直报错,后来不得已,将这个参数写死,就可以了,最后写完整个功能之后将写死的放开,在测试环境上毫无问题,自豪感爆棚。。。哈哈。。

下单成功之后,返回结果如下图所示:

图 4.6 微信下单返回

赶紧将微信返回的数据保存到数据库wxpay_response

图 4.7 下单成功存库

如果微信返回的return_code为SUCCESS,说明下单成功,如果这里没有成功就不要往后写了,赶紧回过头看看。。返回成功继续下面的操作。。

签名

图 4.8 微信签名

按照微信介绍的来,记住timeStamp时间戳要以分为单位传递

String.valueOf(System.currentTimeMillis() /1000);

signType:MD5

nonceStr:WXPayUtil.generateNonceStr()

String sign = WXPayUtil.generateSignature(param, key); (重要)

上面一句话生成签名,大功告成。。

◆ 微信内H5调起支付

图 4.9 前端调微信支付所需参数

将上一步生成的数据,以接口的方式返回给前端,前端调起微信支付即可。。

2.支付回调

◆  我们在下单的时候已经将notify_url通知地址传递给了微信端,微信会回调过来

StringwxpayResult(@Context HttpServletRequest request, @Context HttpServletResponse response);

通过这样的方式接口微信端的回调即可。。

Map notifyMap = WXPayUtil.xmlToMap(resultXml);

将微信返回的数据解析成Map类型数据来做处理

1>通过微信返回的out_trade_no(订单号)查询我们内部订单是否存在

2>状态是否时未支付,如果以支付直接返回即可

3>(重要)签名认证

WXPay.isPayResultNotifySignatureValid(Map reqData)

4>将微信返回的数据保存到wxpay_result表中

图 4.10  微信支付回调表

5>微信所有的处理就完了,下面就是你们自己的业务逻辑处理了。。。

很高心和大家一起学习,当然我也是有大佬帮助过的,后期我会更新一些工作中碰到的问题,希望和大家一起进步。。

所有的委屈,都是因为自己能力不够!! 

                                                                                        - 2018.08.23 20:44

推荐阅读更多精彩内容