微信掃碼支付4-支付回撥
阿新 • • 發佈:2020-11-01
一、準備
1、配置ngrok
將ngrok對映到本地8170埠,並啟動
2、新增工具類
在common_util中新增工具類StreamUtils.java
public class StreamUtils { private static int _buffer_size = 1024; /** * InputStream流轉換成String字串 * @param inStream InputStream流 * @param encoding 編碼格式 * @return String字串 */ public static String inputStream2String(InputStream inStream, String encoding){ String result = null; ByteArrayOutputStream outStream = null; try { if(inStream != null){ outStream = new ByteArrayOutputStream(); byte[] tempBytes = new byte[_buffer_size]; int count = -1; while((count = inStream.read(tempBytes, 0, _buffer_size)) != -1){ outStream.write(tempBytes, 0, count); } tempBytes = null; outStream.flush(); result = new String(outStream.toByteArray(), encoding); outStream.close(); } } catch (Exception e) { result = null; } finally { try { if(inStream != null) { inStream.close(); inStream = null; } if(outStream != null) { outStream.close(); outStream = null; } } catch (IOException e) { e.printStackTrace(); } } return result; } }
二、支付回撥
1、回撥方法
該連結是通過【統一下單API】中提交的引數notify_url設定,如果連結無法訪問,商戶將無法接收到微信通知。
參考文件:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_7&index=8
ApiWeixinPayController
@Autowired private WeixinPayProperties weixinPayProperties; @Autowired private OrderService orderService; /** * 支付回撥:注意這裡是【post】方式 */ @PostMapping("callback/notify") public String wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("callback/notify 被呼叫"); // 獲得通知結果 ServletInputStream inputStream = request.getInputStream(); String notifyXml = StreamUtils.inputStream2String(inputStream, "utf-8"); System.out.println("xmlString = " + notifyXml); // 定義響應物件 HashMap<String, String> returnMap = new HashMap<>(); // 簽名驗證:防止偽造回撥 if (WXPayUtil.isSignatureValid(notifyXml, weixinPayProperties.getPartnerKey())) { // 解析返回結果 Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyXml); //判斷支付是否成功 if("SUCCESS".equals(notifyMap.get("result_code"))){ // 校驗訂單金額是否一致 String totalFee = notifyMap.get("total_fee"); String outTradeNo = notifyMap.get("out_trade_no"); Order order = orderService.getOrderByOrderNo(outTradeNo); if(order != null && order.getTotalFee().intValue() == Integer.parseInt(totalFee)){ // 判斷訂單狀態:保證介面呼叫的冪等性,如果訂單狀態已更新直接返回成功響應 // 冪等性:無論呼叫多少次結果都是一樣的 if(order.getStatus() == 1){ returnMap.put("return_code", "SUCCESS"); returnMap.put("return_msg", "OK"); String returnXml = WXPayUtil.mapToXml(returnMap); response.setContentType("text/xml"); log.warn("通知已處理"); return returnXml; }else{ // 更新訂單支付狀態,並返回成功響應 orderService.updateOrderStatus(notifyMap); returnMap.put("return_code", "SUCCESS"); returnMap.put("return_msg", "OK"); String returnXml = WXPayUtil.mapToXml(returnMap); response.setContentType("text/xml"); log.info("支付成功,通知已處理"); return returnXml; } } } } // 校驗失敗,返回失敗應答 returnMap.put("return_code", "FAIL"); returnMap.put("return_msg", ""); String returnXml = WXPayUtil.mapToXml(returnMap); response.setContentType("text/xml"); log.warn("校驗失敗"); return returnXml; }
2、更新訂單狀態
更新訂單支付狀態並記錄支付日誌,將微信返回的支付結果全部記錄進資料庫的json欄位中
介面:OrderService
void updateOrderStatus(Map<String, String> map);
實現:OrderServiceImpl
@Autowired private PayLogMapper payLogMapper; @Transactional(rollbackFor = Exception.class) @Override public void updateOrderStatus(Map<String, String> map) { //更新訂單狀態 String orderNo = map.get("out_trade_no"); Order order = this.getOrderByOrderNo(orderNo); order.setStatus(1);//支付成功 baseMapper.updateById(order); //記錄支付日誌 PayLog payLog = new PayLog(); payLog.setOrderNo(orderNo); payLog.setPayTime(new Date()); payLog.setPayType(1);//支付型別 payLog.setTotalFee(Long.parseLong(map.get("total_fee")));//總金額(分) payLog.setTradeState(map.get("result_code"));//支付狀態 payLog.setTransactionId(map.get("transaction_id")); payLog.setAttr(new Gson().toJson(map)); payLogMapper.insert(payLog); }