普通商户模式微信支付之APP支付统一下单过后的微信回调通知:
前言:
应用场景:支付完成后,微信会把相关支付结果及用户信息通过数据流的形式发送给商户,商户需要接收处理,并按文档规范返回应答。
首先说明一点:要成功进入微信回调支付结果通知必须注意的一点是要在app支付统一下单接口的参数中加入自己系统设置的回调路径;
如下图:
注意:
1、同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。
2、后台通知交互时,如果微信收到商户的应答不符合规范或超时,微信会判定本次通知失败,重新发送通知,直到成功为止(在通知一直不成功的情况下,微信总共会发起多次通知,通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m),但微信不保证通知最终一定能成功。
3、在订单状态不明或者没有收到微信支付结果通知的情况下,建议商户主动调用微信支付【查询订单API】确认订单状态。
话不多说了,直接上代码说明:
// controller层代码接口,此处的接口路径则为统一下单接口回调字段的参数
@RequestMapping(value = "/wxPayNotifyOfCoupon",method = RequestMethod.POST)
public void wxPayNotifyOfCoupon(HttpServletRequest request,HttpServletResponse response){
try {
wxPayService.wxPayNotify(request, response);
} catch (Exception e) {
log.error("微信支付回调处理出错!");
e.printStackTrace();
}
}
//微信支付统一下单之后的回调通知方法service层
public JSONObject wxPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
//解析结果存储在HashMap()
Map<String, String> map = new HashMap<String, String>();
//获取微信返回的数据
InputStream inputStream = request.getInputStream();
// 读取输入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
List<Element> elementList = root.elements();
// 遍历所有子节点
for (Element e : elementList) {
map.put(e.getName(), e.getText());
}
// 释放资源
inputStream.close();
//返回code
String return_code = map.get("return_code");
String result_code = map.get("result_code");
String out_trade_no = map.get("out_trade_no");//商户订单号号
String transaction_id = map.get("transaction_id");//微信订单号
String total_fee = map.get("total_fee"); //订单金额
String payAttach = map.get("attach");//附加数据,现在只有sessionId
log.info("进入微信回调成功"+out_trade_no);
//返回给微信结果,xml格式返回给微信服务成功或者失败
String xml = "";
//校验签名和订单金额,这里最好做一下安全校验,PaymentKit是微信sdk提供的工具类方法
if (PaymentKit.codeIsOK(return_code) && PaymentKit.codeIsOK(result_code)) {
ResBean<?> resBean = orderQuery(transaction_id); // 此处调用了一个查询订单的方法,用于验证这一笔支付订单是否成功,具体方法的代码在下面
if (PaymentKit.verifyNotify(map,mchSecret)){ // 此处校验签名
if ("SUCCESS".equals(resBean.getRes_content())) { // 查询订单结果返回SUCCESS则进行自己系统的相关订单的业务处理,比如修改订单状态等操作
log.info("微信支付成功,现在进行业务处理");
ReqUserGetBean reqUserGetBean = new ReqUserGetBean();
reqUserGetBean.setG_order_no(out_trade_no);
reqUserGetBean.setSession_id(payAttach);
reqUserGetBean.setG_pay_type(6);
reqUserGetBean.setG_u_payNum(BigDecimal.valueOf(Long.parseLong(total_fee)));
reqUserGetBean.setTransaction_id(transaction_id);
ResBean<Object> js = HttpTooler.httpsInvoke(javaUrl, "/userGetGoldInfo/finishPayFunction", reqUserGetBean);
if ("0000".equals(js.getRes_code())){ // 自己系统的业务处理成功之后,则给微信服务那边响应一个成功
log.info("微信支付回调业务处理数据成功!"+js.getRes_code());
xml = "<xml>\n" +
"<return_code><![CDATA[SUCCESS]]></return_code>\n" +
"<return_msg><![CDATA[OK]]></return_msg>\n" +
"</xml>";
}
else { // 失败则响应失败
log.error("修改订单状态出错"+js.getRes_desc());
log.error(js.getRes_content());
xml = "<xml>\n" +
"<return_code><![CDATA[FAIL]]></return_code>\n" +
"<return_msg><![CDATA[ERROR]]></return_msg>\n" +
"</xml>";
}
response.getWriter().write(xml);
xml = "<xml>\n" +
"<return_code><![CDATA[SUCCESS]]></return_code>\n" +
"<return_msg><![CDATA[OK]]></return_msg>\n" +
"</xml>";
}else {
log.info("支付失败!");
xml = "<xml>\n" +
"<return_code><![CDATA[FAIL]]></return_code>\n" +
"<return_msg><![CDATA[ERROR]]></return_msg>\n" +
"</xml>";
}
response.getWriter().write(xml);
}
} else {
log.info("支付失败!");
xml = "<xml>\n" +
"<return_code><![CDATA[FAIL]]></return_code>\n" +
"<return_msg><![CDATA[ERROR]]></return_msg>\n" +
"</xml>";
response.getWriter().write(xml);
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("out_trade_no",out_trade_no);
jsonObject.put("transaction_id",transaction_id);
return jsonObject;
}
//查询微信订单,普通商户查询
public ResBean<?> orderQueryOfCoupon(String transaction_id){
Map<String, String> mapSign = new LinkedHashMap<>();
mapSign.put("appid",appId);
mapSign.put("mch_id",mchId);
mapSign.put("nonce_str",Long.toString(System.currentTimeMillis() / 1000));
mapSign.put("transaction_id",transaction_id);
mapSign.put("sign",PayUtils.getSign(mapSign,mchSecret));
String post = HttpUtils.post("https://api.mch.weixin.qq.com/pay/orderquery", PaymentKit.toXml(mapSign));
Map<String, String> result = PaymentKit.xmlToMap(post);
String return_code = result.get("return_code");
String result_code = result.get("result_code");
String err_code = result.get("err_code");
String err_code_des = result.get("err_code_des");
ResBean<Object> resBean = new ResBean<>();
if (PaymentKit.codeIsOK(return_code)){
if (PaymentKit.codeIsOK(result_code)){
resBean.setRes_code("0000");
resBean.setRes_desc(result.get("trade_state_desc"));
resBean.setRes_content(result.get("trade_state"));
}else {
resBean.setRes_code("9999");
resBean.setRes_desc(err_code_des);
resBean.setRes_content(err_code);
}
}else {
resBean.setRes_code("9999");
resBean.setRes_desc(err_code_des);
resBean.setRes_content(err_code);
}
return resBean;
}
到此处微信支付统一下单之后的回调就完成了,接下来就是微信支付的退款操作了,下一篇踩坑记录继续讲解!