支付寶APP支付
一、基礎說明
現在開發一個電商APP,最少不了的就是支付,目前最常見的支付有微信支付和支付寶支付,先來介紹支付寶APP支付,其實支付寶的文件說明已經很清楚了,裡面有很多demo,你還可以通過沙箱環境去除錯支付。螞蟻金服開放平臺地址:https://open.alipay.com/developmentAccess/developmentAccess.htm
下面先貼出一張流程圖:
第一步:使用者提交支付,APP去帶著訂單資訊請求服務端
第二步:服務端對訂單資訊進行處理後去請求支付寶(這一步可以設定非同步回撥和同步回撥地址)獲取簽名後的訂單資訊,我的理解就是預支付訂單資訊,(支付寶不存在預付單,可以理解為預付單)
第三步:返回簽名後的訂單資訊給APP客戶端
第四步:APP客戶端攜帶預支付訂單資訊喚起支付寶APP進行支付
第五步:支付完成後,支付寶會同步回撥和非同步回撥,其中非同步回撥是最重要的,也是回撥到服務端的資訊,同步回撥因為客戶端APP和網路的原因,不是十分可靠。
第六步:服務端接收到支付寶非同步回撥請求,根據請求資訊去更新訂單資訊
第七步:APP客戶端通過支付寶交易查詢介面去查詢剛剛支付的訂單狀態
第八步:APP客戶端根據第七步的結果,處理相應的業務邏輯。例如交易成功顯示頁面A,交易失敗顯示頁面B。
- 服務端支付實現
作為服務端,我們需要做的是第二步、第三步、第五步,下面詳細介紹這幾步該如何實現。
第二步:APP客戶端提交訂單資訊到服務端,服務端首先對訂單資訊進行校驗,校驗通過後再呼叫alipay.trade.order.settle(統一收單交易結算介面),操作成功後會返回必要的預支付資訊。
public String orderAliPay(String payAmount, String outTradeNo) {
String orderStr = "";
try {
// 例項化客戶端
APP_PRIVATE_KEY, "json", CHARSET, APP_PUBLIC_KEY, "RSA2");
// 例項化具體API對應的request類,類名稱和介面名稱對應,當前呼叫介面名稱:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
// SDK已經封裝掉了公共引數,這裡只需要傳入業務引數。以下方法為sdk的model入參方式(model和biz_content同時存在的情況下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
// model.setPassbackParams(URLEncoder.encode(body.toString()));
// 描述資訊 新增附加資料
model.setSubject("x"); // 商品標題
model.setOutTradeNo(outTradeNo); // 商家訂單編號
model.setTimeoutExpress("30m"); // 超時關閉該訂單時間
model.setTotalAmount(payAmount); // 訂單總金額
model.setProductCode("QUICK_MSECURITY_PAY"); // 銷售產品碼,商家和支付寶簽約的產品碼,為固定值QUICK_MSECURITY_PAY
request.setBizModel(model);
request.setNotifyUrl(notifyUrl); // 回撥地址
try {
// 這裡和普通的介面呼叫不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient
.sdkExecute(request);
orderStr = response.getBody();
logger.info("支付寶支付預處理-商戶訂單號:" + outTradeNo);
logger.info("支付寶支付預處理-結果:" + response.isSuccess());
// 可以直接給客戶端請求,無需再做處理。
} catch (AlipayApiException e) {
e.printStackTrace();
}
} catch (Exception e) {
logger.error("Exception", e);
}
return orderStr;
}
引數說明:
payAmount支付金額
outTradeNo:訂單流水號(系統唯一)
aliPayUrl 支付寶支付介面https://openapi.alipay.com/gateway.do
APP_ID 支付寶分配給開發者的應用ID
APP_PRIVATE_KEY 應用私密匙
APP_PUBLIC_KEY 應用公密匙
notifyUrl 非同步回撥地址 必須外網環境下可以正常訪問的地址
正確的返回結果是這樣的:
{
"alipay_trade_order_settle_response": {
"code": "10000",
"msg": "Success",
"trade_no": "2015070921001004130000127421"
},
"sign": "ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE"
}
把這個資訊返回給APP開發人員就行了。如果返回資訊錯誤,就要參考具體的返回碼:https://docs.open.alipay.com/api_1/alipay.trade.order.settle
https://docs.open.alipay.com/54/106370/
- 服務端回撥實現
@RequestMapping(value = "/aliPayNotify", produces = "text/html;charset=UTF-8", method = RequestMethod.POST)
public String aliPayNotify(HttpServletRequest request,HttpServletResponse response) {
logger.info("支付寶支付完成回撥,進入 aliPayNotify 方法");
Map<String, String[]> requestParams = request.getParameterMap();
// 獲取支付寶POST過來反饋資訊
Map<String, String> params = new HashMap<String, String>();
logger.info("遍歷支付成功後支付寶返回的引數requestParams,進行設值");
for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
String name = (String) iter.next();
String[] values = (String[]) 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);
}
獲取返回資訊後,需要對資訊進行簽名進行驗證:
//獲取支付寶POST過來反饋資訊
Map<String,String> params = new HashMap<String,String>();
Map requestParams = request.getParameterMap();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
String name = (String) iter.next();
String[] values = (String[]) 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);
}
//切記alipaypublickey是支付寶的公鑰,請去open.alipay.com對應應用下檢視。
//boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
boolean flag = AlipaySignature.rsaCheckV1(params, alipaypublicKey, charset,"RSA2")
簽名校驗通過後再進行訂單更新業務邏輯處理,注意支付寶建議服務端返回success狀態
支付寶是用POST方式傳送通知資訊,因此該頁面中獲取引數的方式,如:request.Form(“out_trade_no”) $_POST[‘out_trade_no’];
支付寶主動發起通知,該方式才會被啟用;
只有在支付寶的交易管理中存在該筆交易,且發生了交易狀態的改變,支付寶才會通過該方式發起伺服器通知(即時到賬交易狀態為“等待買家付款”的狀態預設是不會發送通知的);
伺服器間的互動,不像頁面跳轉同步通知可以在頁面上顯示出來,這種互動方式是不可見的;
第一次交易狀態改變(即時到賬中此時交易狀態是交易完成)時,不僅會返回同步處理結果,而且伺服器非同步通知頁面也會收到支付寶發來的處理結果通知;
程式執行完後必須列印輸出“success”(不包含引號)。如果商戶反饋給支付寶的字元不是success這7個字元,支付寶伺服器會不斷重發通知,直到超過24小時22分鐘。一般情況下,25小時以內完成8次通知(通知的間隔頻率一般是:4m,10m,10m,1h,2h,6h,15h);
程式執行完成後,該頁面不能執行頁面跳轉。如果執行頁面跳轉,支付寶會收不到success字元,會被支付寶伺服器判定為該頁面程式執行出現異常,而重發處理結果通知;
cookies、session等在此頁面會失效,即無法獲取這些資料;
該方式的除錯與執行必須在伺服器上,即網際網路上能訪問;
該方式的作用主要防止訂單丟失,即頁面跳轉同步通知沒有處理訂單更新,它則去處理;
當商戶收到伺服器非同步通知並打印出success時,伺服器非同步通知引數notify_id才會失效。也就是說在支付寶傳送同一條非同步通知時(包含商戶並未成功打印出success導致支付寶重發數次通知),伺服器非同步通知引數notify_id是不變的。
支付寶APP支付大概就是這樣子,不懂得可以留言我。