對(duì)于手機(jī)網(wǎng)站支付產(chǎn)生的交易,支付寶會(huì)根據(jù)原始支付API中傳入的異步通知地址notify_url,通過POST請(qǐng)求的形式將支付結(jié)果作為參數(shù)通知到商戶系統(tǒng)。
支付寶開發(fā)文檔:https://docs.open.alipay.com/203/105286/
這邊博客講的1.8后臺(tái)通知支付結(jié)果 notify_url

image.png
這個(gè)環(huán)節(jié)的業(yè)務(wù)邏輯處理為:收到支付寶的回調(diào)結(jié)果通知,先進(jìn)行簽名校驗(yàn),如果簽名校驗(yàn)結(jié)果是對(duì)的,然后進(jìn)行自己的業(yè)務(wù)邏輯處理(比如輯比如更新訂單支付信息成功,保存交易流水,修改訂單狀態(tài));
當(dāng)然支付寶的官方文檔還推薦在驗(yàn)簽通過之后還需要查詢這個(gè)支付單號(hào)在支付寶服務(wù)器的支付結(jié)果是否為成功,以這個(gè)結(jié)果為準(zhǔn);然后再進(jìn)行支付成功后的業(yè)務(wù)邏輯處理。主要是為了防止數(shù)據(jù)篡改和數(shù)據(jù)的冪等性處理。
項(xiàng)目中的具體代碼實(shí)現(xiàn):
controller層的處理:
/**
* @param request:
* @param response:
* @return java.lang.String
* @Description 支付寶回調(diào)
* @Author huangkeyuan
* @Date 16:24 2019-12-11
*/
@PostMapping("notify")
@ApiOperation("支付寶支付回調(diào),修改訂單支付狀態(tài)")
public String aliPayCertNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
Map<String, String> returnMap = new HashMap<>();
//獲取支付寶POST過來反饋信息轉(zhuǎn)換為Entry
Set<Map.Entry<String, String[]>> entries = request.getParameterMap().entrySet();
// 遍歷
for (Map.Entry<String, String[]> entry : entries) {
String key = entry.getKey();
StringBuffer value = new StringBuffer("");
String[] val = entry.getValue();
if (null != val && val.length > 0) {
for (String v : val) {
value.append(v);
}
}
returnMap.put(key, value.toString());
}
log.info("支付寶支付回調(diào),{}", returnMap.toString());
return paymentService.aliPayCertNotify(returnMap);
}
service層中的處理:
/**
* @param requestParams : 回調(diào)參數(shù)
* @return java.lang.String
* @Description 支付寶回調(diào)(公鑰證書方式)
* @Author huangkeyuan
* @Date 16:34 2019-12-09
*/
@PostMapping("alipay/notify")
@Override
public String aliPayCertNotify(@RequestParam Map<String, String> requestParams) {
log.info(">>>支付寶回調(diào)參數(shù):" + requestParams.toString());
Map<String, String> logMap = new HashMap<>();
try {
// 獲取支付寶的支付key
boolean flag = aliPayService.checkSignature(requestParams);
if (flag) {
log.info(">>>支付寶回調(diào)簽名認(rèn)證成功");
//商戶訂單號(hào)
String out_trade_no = requestParams.get("out_trade_no");
//交易狀態(tài)
String trade_status = requestParams.get("trade_status");
//交易金額
String amount = requestParams.get("total_amount");
//支付寶交易號(hào)
String trade_no = requestParams.get("trade_no");
if ("TRADE_SUCCESS".equals(trade_status) || "TRADE_FINISHED".equals(trade_status)) {
log.info("支付寶回調(diào)支付成功,trade_status:{}", trade_status);
/**
* 自己的業(yè)務(wù)處理
*/
// 執(zhí)行支付成功后的商城業(yè)務(wù)邏輯比如更新訂單支付信息成功,保存交易流水,修改訂單狀態(tài)
mlogger.info(PaymentStatusCode.ALI_PAY_NOTIFY_SUCCESS_CODE, PaymentStatusCode.ALI_PAY_NOTIFY_SUCCESS_MESSAGE, logMap);
// 修改訂單狀態(tài)成功
log.info("支付寶支付回調(diào)修改訂單、支付狀態(tài)成功,結(jié)果碼:" + trade_status + ",支付單號(hào):" + out_trade_no + "支付寶支付單號(hào):" + trade_no);
} else {
log.error("沒有處理支付寶回調(diào)業(yè)務(wù),支付寶交易狀態(tài):{},params:{}", trade_status, requestParams);
mlogger.info(PaymentStatusCode.ALI_PAY_NOTIFY_SERVER_RESPONSE_VALIDATION_ERRORB_CODE,
PaymentStatusCode.ALI_PAY_NOTIFY_SERVER_RESPONSE_VALIDATION_ERRORB_MESSAGE, logMap);
}
} else {
log.info("支付寶回調(diào)簽名認(rèn)證失敗,signVerified=false, params:{}", requestParams);
mlogger.info(PaymentStatusCode.ALI_PAY_NOTIFY_SERVER_INTERNAL_ERROR_CODE,
PaymentStatusCode.ALI_PAY_NOTIFY_SERVER_INTERNAL_ERROR_MESSAGE, logMap);
return "failure";
}
} catch (Exception e) {
log.error(e.getMessage(), e);
log.info("支付寶回調(diào)簽名認(rèn)證失敗,signVerified=false, params:{}", requestParams);
mlogger.info(PaymentStatusCode.ALI_PAY_NOTIFY_SERVER_INTERNAL_ERROR_CODE,
PaymentStatusCode.ALI_PAY_NOTIFY_SERVER_INTERNAL_ERROR_MESSAGE, logMap, e);
return "failure";
}
return "success";//請(qǐng)不要修改或刪除
}
third-party-service中的處理
/**
* @param requestParams :
* @return boolean
* @Description 收到支付寶的成功回調(diào)之后驗(yàn)證簽名是否正確
* @Author huangkeyuan
* @Date 17:01 2019-12-12
*/
@PostMapping("check/signature")
@Override
public boolean checkSignature(Map<String, String> requestParams) {
try {
String alipaypublickey = this.getAlipayPublicKey(aliPayConfig.getALIPAY_CERT_PATH());
log.info("讀取服務(wù)器的支付寶公鑰證書,{}", alipaypublickey);
//切記alipaypublickey是支付寶的公鑰,請(qǐng)去open.alipay.com對(duì)應(yīng)應(yīng)用下查看。
boolean flag = AlipaySignature.rsaCheckV1(requestParams, alipaypublickey, aliPayConfig.getCHARSET(),
aliPayConfig.getSIGN_TYPE());
return flag;
} catch (Exception e) {
return false;
}
}
遇到的問題
直接打印支付寶返回的參數(shù)是這樣的:
支付寶回調(diào)參數(shù):{gmt_create=[Ljava.lang.String;@362e073d, charset=[Ljava.lang.String;@1445a60e, seller_email=[Ljava.lang.String;@20f2aa67, subject=[Ljava.lang.String;@30c863fd, sign=[Ljava.lang.String;@76198d36, body=[Ljava.lang.String;@4fd5202d, buyer_id=[Ljava.lang.String;@7a410a22, invoice_amount=[Ljava.lang.String;@965491c, notify_id=[Ljava.lang.String;@33af053b, fund_bill_list=[Ljava.lang.String;@551d8f2b, notify_type=[Ljava.lang.String;@27ff9fb0, trade_status=[Ljava.lang.String;@4f11ffa, receipt_amount=[Ljava.lang.String;@4fbc4482, buyer_pay_amount=[Ljava.lang.String;@76e1ee89, app_id=[Ljava.lang.String;@2d38edfa, sign_type=[Ljava.lang.String;@21ba2968, seller_id=[Ljava.lang.String;@c0ff189, gmt_payment=[Ljava.lang.String;@7563d327, notify_time=[Ljava.lang.String;@1fdeb74c, version=[Ljava.lang.String;@6f5f3cb6, out_trade_no=[Ljava.lang.String;@1c2f1b6d, total_amount=[Ljava.lang.String;@77be0924, trade_no=[Ljava.lang.String;@1db0b448, auth_app_id=[Ljava.lang.String;@b1c81c4, buyer_logon_id=[Ljava.lang.String;@6f8c07b9, point_amount=[Ljava.lang.String;@68fcd445}
需要通過這樣數(shù)據(jù)處理才能轉(zhuǎn)換成我們常用的map結(jié)構(gòu),方便項(xiàng)目中數(shù)據(jù)分析和使用
Map<String, String> returnMap = new HashMap<>();
//獲取支付寶POST過來反饋信息轉(zhuǎn)換為Entry
Set<Map.Entry<String, String[]>> entries = request.getParameterMap().entrySet();
// 遍歷
for (Map.Entry<String, String[]> entry : entries) {
String key = entry.getKey();
StringBuffer value = new StringBuffer("");
String[] val = entry.getValue();
if (null != val && val.length > 0) {
for (String v : val) {
value.append(v);
}
}
returnMap.put(key, value.toString());
}