上一篇講了小程序支付的過程,接下來就是支付結果通知
官方文檔:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_7
注意:
支付通知的url 是通過【統一下單API】中提交的參數notify_url設置,如果鏈接無法訪問,商戶將無法接收到微信通知。
通知url必須為直接可訪問的url,不能攜帶參數。示例:notify_url:“https://pay.weixin.qq.com/wxpay/pay.action”
在前面的支付的參數中設置了支付結果的URL——baseUrl+"/notify"
所以支付通知會發到我自己服務器下的這個路徑下,會接收到類似如下的xml字符串(如果正常的話,即result_code 和return_code都為SUCCESS)
解析這個xml,可以得到transaction_id,out_trade_no等關鍵信息。
為了保證返回信息是否正確,我們可以去驗證其正確性。
方法是對參數進行加密獲取的簽名,然后比對返回的簽名和我們生成的簽名是否一致,若不一致就表明返回的支付通知被修改,不過一般不會出現這種情況。
注意:
可能是微信方面覺得一次不一定能通知到,所以支付通知可能會發多次,所以我們在收到正確的通知之后,需要給小程序官方返回一段xml,表示收到,之后就不會再收到啦。
整個支付通知的處理的代碼如下
/** * 支付完成通知 * @param request * @param response * @return * @throws Exception */ @RequestMapping(value = "/notify",method = RequestMethod.POST) public String notify(HttpServletRequest request, HttpServletResponse response) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream)request.getInputStream())); String line = null; StringBuilder sb = new StringBuilder(); while((line = br.readLine())!=null){ sb.append(line); } //解析並給微信發回收到通知確認 Map map = PayUtils.doXMLParse(sb.toString()); String returnCode = map.get("return_code").toString(); if(returnCode.equals("SUCCESS")){ String resultCode = map.get("result_code").toString(); if(resultCode.equals("SUCCESS")){ SortedMap<String, String> packageParams = new TreeMap<String, String>(); packageParams.put("appid", map.get("appid").toString()); packageParams.put("attach", map.get("attach").toString()); packageParams.put("bank_type", map.get("bank_type").toString()); packageParams.put("cash_fee", map.get("cash_fee").toString()); packageParams.put("fee_type", map.get("fee_type").toString()); packageParams.put("is_subscribe", map.get("is_subscribe").toString()); packageParams.put("mch_id", map.get("mch_id").toString()); packageParams.put("nonce_str", map.get("nonce_str").toString()); packageParams.put("openid", map.get("openid").toString()); packageParams.put("out_trade_no", map.get("out_trade_no").toString()); packageParams.put("result_code", map.get("result_code").toString()); packageParams.put("return_code", map.get("return_code").toString()); packageParams.put("time_end", map.get("time_end").toString()); packageParams.put("total_fee", map.get("total_fee").toString()); packageParams.put("trade_type", map.get("trade_type").toString()); packageParams.put("transaction_id", map.get("transaction_id").toString()); String sign = PayUtils.createSign(packageParams,key); String originSign = map.get("sign").toString(); if(sign.equals(originSign)){ //簽名一致,保存支付流水 String xml="<xml>" +"<return_code>SUCCESS</return_code>" +"<return_msg>OK</return_msg>" +"</xml>"; ProfPayLog payLog = new ProfPayLog(); payLog.setCreatedAt(new Date()); payLog.setSource(Source.WeiXin); DecimalFormat df = new DecimalFormat("######0.00"); payLog.setTotalFee(String.valueOf(df.format((Double.valueOf(map.get("total_fee").toString())/100)))); payLog.setTradeNo(map.get("out_trade_no").toString()); payLog.setTransactionId(map.get("transaction_id").toString()); String attach = map.get("attach").toString();//userId+"#wx#"+activityId payLog.setUserId(attach.split("#wx#")[0]); payLog.setType(ProfPayLog.Type.Pay); WxappUser user = wxappUserService.find(Long.valueOf(attach.split("#wx#")[0])); WxappActivity activity = wxappActivityService.find(Long.valueOf(attach.split("#wx#")[1])); WxappActivityApply activityApply = wxappActivityApplyService.findActivityApplyByUserAndActivity(user, activity); if(activityApply.getPayLogId() != null){ System.out.println("=========已經完成了存儲支付流水========="); return xml; }else{ System.out.println("=========完成第一次保存支付流水========="); payLog = wxappPayService.save(payLog); //在活動申請表中關聯上支付流水的id activityApply.setPayLogId(String.valueOf(payLog.getId())); wxappActivityApplyService.save(activityApply); return xml; } }else{ String xml="<xml>" +"<return_code>FAIL</return_code>" +"<return_msg>簽名不一致</return_msg>" +"</xml>"; return xml; } }else{ String xml="<xml>" +"<return_code>FAIL</return_code>" +"<return_msg>支付通知失敗</return_msg>" +"</xml>"; return xml; } } else { String xml="<xml>" +"<return_code>FAIL</return_code>" +"<return_msg>支付通知失敗</return_msg>" +"</xml>"; return xml; } }