1. 程式人生 > >支付寶APP支付

支付寶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 {
        // 例項化客戶端
        

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支付大概就是這樣子,不懂得可以留言我。