代码主体写完后,还有不可或缺的部分需要补充完整,即接收支付结果通知,官方文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7&index=8
目录:
微信小程序接入微信支付(一):大概流程与准备需知
微信小程序接入微信支付(二):后台调用统一下单接口
微信小程序接入微信支付(三):小程序端调用支付接口
微信小程序接入微信支付(四):接收支付结果通知与沙箱测试
支付结果通知:
微信支付官方会调用我们“notify_url” 提供地接口来进行异步地通知每笔订单的支付结果。如果我们提供的接口出现问题,则会按照一定的频率多次通知过来。此外当我们接收到通知后,需要根据通知内容进行处理,并及时把结果回调给微信支付官方。
简单提供下我的代码:
/**
* 暂定为 获取支付结果通知接口 ,根据接收到的通知,处理支付结果
*
* @return
* @throws Exception
*/
@PostMapping("/getresult")
@ResponseBody
public String getResult(@RequestBody String res) throws Exception {
String errMsg = "Unknown error";
String xmlMsg = "<xml>"+
"<return_code>"+"FAIL"+"</return_code>"+
"<return_msg>"+errMsg+"</return_msg>"+
"</xml>";
//接收到的xml格式字符串转map
Map<String, String> resultMap = xmlToMap(res);
String return_code;
if (resultMap.containsKey("return_code")) {
return_code = resultMap.get("return_code");
}
else {
errMsg = "No 'return_code' in XML";
throw new Exception(String.format("GETRESULT No `return_code` in XML: %s", res));
}
if (return_code.equals("FAIL")) {
errMsg = "return_code is FAIL";
throw new Exception("GETRESULT return_code : fail from wx_pay :" + res);
}
else if (return_code.equals("SUCCESS")) {
LOG.info("----getresult success order_no: " + resultMap.get("out_trade_no"));
//TODO 签名验证支付结果通知
//查询本地该订单
Order order =orderservice.selectOrdersByExample(Long.parseLong(resultMap.get("out_trade_no")), null, null, null).get(0);
if(order.getOrder_state() != 0 && resultMap.get("time_end") != null) {
//订单状态--已支付, 微信通知支付结果--支付成功 返回成功
xmlMsg ="<xml>"+
"<return_code>"+"SUCCESS"+"</return_code>"+
"<return_msg>"+"OK"+"</return_msg>"+
"</xml>";
return xmlMsg;
}else if(order.getOrder_state() != 0 && resultMap.get("time_end") == null) {
//订单状态--已支付, 微信通知支付结果--支付未成功 不做操作返回成功
xmlMsg ="<xml>"+
"<return_code>"+"SUCCESS"+"</return_code>"+
"<return_msg>"+"OK"+"</return_msg>"+
"</xml>";
return xmlMsg;
}else if(order.getOrder_state() == 0 && resultMap.get("time_end") != null){
//订单状态--待付款, 微信通知支付结果--支付成功 更改订单状态为1--待发货 返回成功
orderservice.updateOrder(Long.parseLong(resultMap.get("out_trade_no")), null, 1);
xmlMsg ="<xml>"+
"<return_code>"+"SUCCESS"+"</return_code>"+
"<return_msg>"+"OK"+"</return_msg>"+
"</xml>";
return xmlMsg;
}else {
//其余情况,先按已处理解决,返回成功
xmlMsg ="<xml>"+
"<return_code>"+"SUCCESS"+"</return_code>"+
"<return_msg>"+"OK"+"</return_msg>"+
"</xml>";
return xmlMsg;
}
//TODO 处理数据时建议使用数据锁进行并发控制
}
return xmlMsg;
}
相关外部方法可在前面章节中查看:微信小程序接入微信支付(二):后台调用统一下单接口
建议对接受的通知进行签名认证,处理数据时使用数据锁进行并发控制。
沙箱测试:
当我们代码写完后需要进行测试,微信支付官方提供专门的沙箱环境用于测试,不会产生金额交易。
官方文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=23_1&index=2
我们只需要在调用接口的URL地址中加入/sandboxnew,
例如统一下单接口:https://api.mch.weixin.qq.com/pay/unifiedorder
可改为https://api.mch.weixin.qq.com/sanboxnew/pay/unifiedorder 就能访问到沙箱环境,但是使用沙箱环境时,我们不能使用商户自己的key,而是通过后台调用-获取验签秘钥API接口来获取沙箱环境专用的key。
//沙箱环境下需先请求获取key
Map<String, String> testMap = new HashMap<>();
testMap.put("mch_id", mchId);
testMap.put("nonce_str",getRandomString());
//生成符合规格的签名串
String stringTestSignTemp = getParamStr(testMap,realKey);
//进行MD5运算,并转为大写,获得sign参数的值
String signTestValue = MD5(stringTestSignTemp.toString()).toUpperCase();
//把sign放入map中
testMap.put("sign",signTestValue);
//map转义为xml格式
String requestTestParam = mapToXml(testMap);
LOG.info("request sandbox API key - [parameters]:" +requestTestParam);
System.out.println("request sandbox API key - [parameters]:" +requestTestParam);
//发送请求
String testResult = sendPostParam(sandBoxUrl, requestTestParam);
System.out.println("request sandbox API key - [results]:" +testResult);
LOG.info("request sandbox API key - [results]:" +testResult);
//将返回的结果从xml字符串转义为map
Map<String, String> testResultMap = xmlToMap(testResult);
if(testResultMap.get("return_code") != null && testResultMap.get("return_code") == "SUCCESS") {
sandKey = testResultMap.get("sandbox_signkey");
System.out.println("----sandbox key: " + sandKey);
LOG.info("---sandbox key:" + sandKey);
}else {
return null;
}
!注意:
我们可以根据沙箱环境的反馈来修改我们的代码以及参数,但是当我们发现自己明明没有什么错误时,沙箱环境依旧报错,那么我们可以转到正式环境去测试了。。。。。。就像有些网友说的,这个沙箱环境一步一个坑,bug满天飞。当转到正式环境时,你就会发现原来自己没错。。。。。。说多了都是泪