作为财务人员一定要熟练掌握的常用日期函数 WEEKDAY DATE(财务应该掌握的函数)
1699
2022-05-30
最近在工作中接入了一下微信小程序支付的功能,虽然说官方文档已经比较详细了,但在使用过程中还是踩了不少的坑,整理了一下大体的流程和代码分享出来。在开始使用小程序支付功能前,需要做好以下的准备工作:
申请微信小程序,配置小程序id及秘钥
申请用于支付的微信商户平台账号,配置商户号id及商户平台秘钥,并绑定小程序与该商户号
后端服务在正式环境下需要https域名,调试模式可以不需要
先引用一张小程序支付官方说明的流程图,可以看出小程序支付的主要逻辑集中在后端,前端只需要携带参数请求后端接口,然后根据后端接口返回的数据在前端唤起微信支付即可。
按照上面流程图中商户业务系统和微信支付系统主要交互步骤,对流程进行拆解说明。
1、获取用户openId
小程序前端调用wx.login()获取登录凭证code,后端调用接口获取用户的openid和session_key。注意这里在发起请求的时候需要携带小程序的appId和appSecret。
public OpenIdInfo code2Openid(String code){ String url = "https://api.weixin.qq.com/sns/jscode2session"; String param = "appid=" + mpCommonProperty.getAppid() + "&secret=" + mpCommonProperty.getAppsecret() + "&js_code=" + code + "&grant_type=authorization_code"; String rs = HttpUtils.sendGet(url, param); JSONObject json = JSONObject.parseObject(rs); if (json.get("errcode") == null) { String openid = json.getString("openid"); String sessionKey = json.getString("session_key"); OpenIdInfo openIdInfo = OpenIdInfo.builder() .openId(openid).sessionKey(sessionKey).build(); return openIdInfo; }else { log.error("get openid error"); return null; } }
需要注意每次调用接口都会刷新session_key的值,使之前的session_key失效,其他操作诸如解析用户手机号时会用到这个秘钥,为了避免该情况可以将用户的openid存储在业务系统的用户体系中。
2、调用支付统一下单
微信统一下单接口要求传递参数的形式为xml报文,因此需要先对参数进行拼接,这里仅列出了能够唤起小程序支付所需要的最小参数范围,更多的参数列表可以查看官方文档。
public String generateUniPayXml(UnifiedParam unifiedParam){ int money = (int) Math.ceil(unifiedParam.getTotalMoney() * 100); //转换为分,向上取整 Map
对其中几个参数进行说明:
out_trade_no:商户订单号,在我们的后台使用某种规则生成,不能重复
total_fee:订单总金额,需要注意单位为分,需要转
body:商品描述
notify_url:支付结果的回调接口地址,使用会在后面介绍
sign:签名,需要按照微信的规则生成,算法规则为去除值为空的元素,参数名ASCII字典序排序进行拼接,拼接API密钥,使用Md5进行加密:
签名方法如下:
public String signCommon(Map
以上步骤完成后,对外暴露的统一下单接口如下:
public Map
在调用后,会收到同步返回结果为一段xml报文,将其解析成Map后可供下一阶段使用,同步接口的返回值及错误码可以参考官方文档。
3、二次签名
在调用统一下单接口并收到微信的同步返回结果后,需要对其进行二次签名,需要进行签名的参数包括appId、timeStamp、nonceStr、package、signType。
public PrepayInfo secondSign(Map
二次签名完成后,将timeStamp、nonceStr、package、signType、paySign返回给前端,这里为了方便封装了一个对象用于返回,前端在收到参数后唤起微信支付。
4、接收支付通知
在前面介绍的统一下单的参数中,传入了商户后端的回调地址,在支付完成后,微信会向这个调用这个回调接口,通知支付结果。
@PostMapping("fallback") public void fallback(HttpServletRequest request,HttpServletResponse response) throws IOException { StringBuilder sb = new StringBuilder(); BufferedReader reader = null; try (InputStream inputStream = request.getInputStream()) { reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); String line = ""; while ((line = reader.readLine()) != null) { sb.append(line); } } catch (IOException e) { log.error("getBodyString错误"); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { log.error(ExceptionUtils.getMessage(e)); } } } String notifyXml=sb.toString(); Map
在接收到返回的报文后,需要用之前同样的签名算法,验证返回报文的真实性,并在验证真实性后再执行之后的业务逻辑,防止数据泄漏导致出现的虚假通知,造成资金损失。
微信在调用回调接口时,如果收到我们业务系统的应答不符合规范或超时,会判定本次通知失败,重新发送多次通知。在通知一直不成功的情况下,按照官方文档的说明,总计在24h4m内会调用15次回调接口。因此一定要按照规定返回成功接收的报文,从一定程度上也能降低系统的负载。
在测试中发现,不能使用直接返回String字符串的方式进行结果的返回,仍然会一直发起回调,必须使用HttpServletResponse写入返回。即使这么做了,还是建议大家在回调接口内部处理业务前再做一下幂等性的处理,防止多次执行回调逻辑造成业务系统的数据混乱。
小程序
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。