1、基礎說明html
如今開發一個電商APP,最少不了的就是支付,目前最多見的支付有微信支付和支付寶支付,先來介紹支付寶APP支付,其實支付寶的文檔說明已經很清楚了,裏面有不少demo,你還能夠經過沙箱環境去調試支付。螞蟻金服開放平臺地址:https://open.alipay.com/developmentAccess/developmentAccess.htmjson
下面先貼出一張流程圖:api
第一步:用戶提交支付,APP去帶着訂單信息請求服務端服務器
第二步:服務端對訂單信息進行處理後去請求支付寶(這一步能夠設置異步回調和同步回調地址)獲取簽名後的訂單信息,個人理解就是預支付訂單信息,(支付寶不存在預付單,能夠理解爲預付單)微信
第三步:返回簽名後的訂單信息給APP客戶端cookie
第四步:APP客戶端攜帶預支付訂單信息喚起支付寶APP進行支付網絡
第五步:支付完成後,支付寶會同步回調和異步回調,其中異步回調是最重要的,也是回調到服務端的信息,同步回調由於客戶端APP和網絡的緣由,不是十分可靠。session
第六步:服務端接收到支付寶異步回調請求,根據請求信息去更新訂單信息app
第七步:APP客戶端經過支付寶交易查詢接口去查詢剛剛支付的訂單狀態異步
第八步:APP客戶端根據第七步的結果,處理相應的業務邏輯。例如交易成功顯示頁面A,交易失敗顯示頁面B。
做爲服務端,咱們須要作的是第二步、第三步、第五步,下面詳細介紹這幾步該如何實現。
第二步:APP客戶端提交訂單信息到服務端,服務端首先對訂單信息進行校驗,校驗經過後再調用alipay.trade.order.settle(統一收單交易結算接口),操做成功後會返回必要的預支付信息。
public String orderAliPay(String payAmount, String outTradeNo) {
String orderStr = "";
try {
// 實例化客戶端
AlipayClient alipayClient = new DefaultAlipayClient(aliPayUrl, APP_ID,
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支付大概就是這樣子,不懂得能夠留言我。