1.支付分对接时注意的坑
创建支付分订单API https://api.mch.weixin.qq.com/v3/payscore/serviceorder
修改订单金额API https://api.mch.weixin.qq.com/v3/payscore/serviceorder/{out_order_no}/modify
取消支付分订单API https://api.mch.weixin.qq.com/v3/payscore/serviceorder/{out_order_no}/cancel
完结支付分订单API https://api.mch.weixin.qq.com/v3/payscore/serviceorder/{out_order_no}/complete
注:划删除线的部分是在url上拼接path的,并且传输时param不可包含 out_order_no这个参数。
所以,我作了如下处理:
回调处理 :
@PostMapping("/confirmNotify")
@ResponseBody
public JSONObjectconfirmNotify(HttpServletRequest request){
try{
ServletInputStream servletInputStream = request.getInputStream();
int contentLength = request.getContentLength();
byte[] callBackInBytes =new byte[contentLength];
servletInputStream.read(callBackInBytes, 0, contentLength);
String callBackIn =new String(callBackInBytes, StandardCharsets.UTF_8);
logger.info("【微信支付分回调】{}" , callBackIn);
JSONObject notifyIn = JSONObject.parseObject(callBackIn);
if (notifyIn ==null) {
logger.info("支付回调失败,参数不正确,反序列化失败");
}
//解密回调信息
assert notifyIn !=null;
JSONObject resource = notifyIn.getJSONObject("resource");
byte[] key = (wxConfig.IV3KEY).getBytes(StandardCharsets.UTF_8);
ApiV3Util aesUtil =new ApiV3Util(key);
String decryptToString = aesUtil.decryptToString(resource.getString("associated_data").getBytes(StandardCharsets.UTF_8), resource.getString("nonce").getBytes("UTF-8"), resource.getString("ciphertext"));
if (StringUtils.isEmpty(decryptToString)) {
logger.info("支付回调失败,参数解密错误");
}
logger.info("【支付分支付回调解密结果:】" + decryptToString);
// 用户确认成功
if ("PAYSCORE.USER_CONFIRM".equals(notifyIn.get("event_type"))) {
JSONObject json=JSONObject.parseObject(decryptToString);
if("USER_CONFIRM".equals(json.getString("state_description"))){
logger.info("用户确认成功[【YES】],解密数据{}",json);
return payPointService.receiveBack(0,json);
}
}
// 支付成功
if ("PAYSCORE.USER_PAID".equals(notifyIn.get("event_type"))) {
JSONObject json=JSONObject.parseObject(decryptToString);
if("MCH_COMPLETE".equals(json.getString("state_description"))){
logger.info("用户支付成功[【YES】],解密数据{}",json);
return payPointService.receiveBack(1,json);
}
}
}catch (Exception e) {
logger.error("微信支付回调处理异常," + e.toString());
e.printStackTrace();
}
return null;
}
注意:此处的IPV3key是IPV3支付密钥,从商户获取。
回调包含了用户确认支付分免押和支付回调,
用户确认即可执行业务操作,例如:使用免押充电宝的弹出,使用共享单车的开锁等。
支付回调则需要根据扣款金额校验,微信API都是以分为单位
使用传输时乘以100,使用BigDecimal.multiply(new BigDecimal(100)).setScale(0);
解密时除以100,使用BigDecimal.divide(new BigDecimal(100));
小数点可以自己控制,如果使用int或double容易造成精度丢失,涉及金钱务必使用BigDecimal;
另外如有扣费需要存储扣费凭证(交易单号,支付分API使用基础的微信退款),包裹了很多层
json数据为解密后的支付订单回调数据;
JSONObject collection = JSONObject.parseObject(JSONObject.toJSONString(json.get("collection")));
JSONArray details = JSONObject.parseArray(collection.getString("details"));
String finish_transaction_id =null;
if (details.size() ==1) {
for (Object de : details) {
JSONObject jsons = JSONObject.parseObject(JSONObject.toJSONString(de));
finish_transaction_id = jsons.getString("transaction_id");
}
}
再把finish_transaction_id存储;