訂單支付成功后,需要更改訂單狀態
支付寶有兩種回調方式
-
同步回調:可以直接用request獲取訂單傳回的數據,利用簽名驗證是否正確再去修改訂單狀態,但這種方式不推薦也不好,如果瀏覽器不小心關閉或者用戶關閉,導致頁面跳轉不了也就無法修改訂單數據
-
異步通知:只要支付成功以后就會給我們指定的地址發送一個請求還會帶上之前成功的數據,收到以后再去修改訂單,比較可靠
對於PC交易用戶支付完成,支付寶會根據API傳入的notify_url,通過post請求的形式將支付結果作為參數通知到商戶系統,例如一些支付參數簽名,業務參數支付時間流水號等等
只要我們訂單支付成功,支付寶就會發送通知告訴我們訂單支付成功了,我們要回復通知不然支付寶會一直嘗試給我們發送通知,這也是相當於分布式事務中的最大努力通知機制
環境搭建
要讓支付寶訪問到我們,就要讓我們的服務能夠讓外網訪問到,因此要指定一個地址用來處理成功后支付的請求
#支付成功的異步通知頁面
gulimall.alipay.notify_url=http://yjcpds.natappfree.cc/payed/notify
異步回調方法,驗證成功就修改訂單狀態
@RequestMapping("/payed/notify")
public String handleAlipayed(PayAsyncVo vo, HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException {
Map<String, String[]> map = request.getParameterMap();
// for(String key : map.keySet()){
// String value = request.getParameter(key);
// System.out.println("參數名:"+key+"-->參數值:"+value);
// }
//阿里驗簽方法
Map<String, String> params = new HashMap<String, String>();
Map<String, String[]> requestParams = request.getParameterMap();
for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
String name = (String) iter.next();
String[] values = requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
//亂碼解決,這段代碼在出現亂碼時使用
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayTemplate.getAlipay_public_key(),
alipayTemplate.getCharset(), alipayTemplate.getSign_type());
if (signVerified) {
System.out.println("簽名驗證成功...");
String result = orderService.handlePayResult(vo);
return result;
} else {
System.out.println("簽名驗證失敗...");
return "error";
}
}
內網穿透聯調
需要把外網地址 http://yjcpds.natappfree.cc映射到我們內網主機的order.gulimall.com中
先去設置內網穿透映射的內網地址
進入到內網,內網配置了host地址,進入了虛擬機80端口
nginx監聽到80端口,然后根據請求路徑需要轉給訂單服務,但是由於請求頭的原因找不到訂單服務,因此進行精准匹配,把這個payed請求,直接轉給訂單服務,nginx還需要識別請求進來的主機名,需要配置內網穿透映射的主機名
最后編寫響應成功修改訂單的邏輯
@Override
public String handlePayResult(PayAsyncVo vo) {
//1.保存交易流水
PaymentInfoEntity infoEntity = new PaymentInfoEntity();
infoEntity.setAlipayTradeNo(vo.getTrade_no());
infoEntity.setOrderSn(vo.getOut_trade_no());
infoEntity.setPaymentStatus(vo.getTrade_status());
infoEntity.setCallbackTime(vo.getNotify_time());
paymentInfoService.save(infoEntity);
//2.修改訂單狀態
if(vo.getTrade_status().equals("TRADE_SUCCESS")||vo.getTrade_status().equals("TRADE_FINISHED")){
//支付成功
String outTradeNo = vo.getOut_trade_no();
this.baseMapper.updateOrderStatus(outTradeNo,OrderStatusEnum.PAYED.getCode());
}
return "success";
}
到此整個流程就完畢了,支付成功利用異步回調方法修改訂單狀態,完成整個支付流程
收單
1、訂單在支付頁,不支付,一直刷新,訂單過期了才支付,訂單狀態改為已支付了,但是庫存解鎖了
-
使用支付寶自動收單功能解決。只要一段時間不支付,就不能支付了
在下單接口中增加一個參數,超時關閉訂單支付
2、由於時延等問題。訂單解鎖完成,正在解鎖庫存的時候,異步通知才到
訂單快要過期的時候,我們正好支付了,但是訂單正好過期了,庫存也解鎖了
-
訂單解鎖,手動調用收單
3、網絡阻塞問題,訂單支付成功的異步通知一直不到達
- 查詢訂單列表時,ajax獲取當前未支付的訂單狀態,查詢訂單狀態時,再獲取一下支付寶此訂單的狀態
4、其他各種問題
- 每天晚上閑時下載支付寶對賬單,一一進行對賬