支付寶手機網站支付接入(沙箱環境)


參考阿里雲文檔:https://docs.open.alipay.com/203/105285/

1.調用流程

手機網站支付產品包含兩類API:

  • 頁面跳轉類:需要從前端頁面以Form表單的形式發起請求,瀏覽器會自動跳轉至支付寶的相關頁面(一般是收銀台或簽約頁面),用戶在該頁面完成相關業務操作后再回跳到商戶指定頁面。例如本產品中的手機網站支付接口alipay.trade.wap.pay。
  • 系統調用類:直接從服務端發起HTTP請求,支付寶會同步返回請求結果。例如本產品中的交易查詢等配套API。
    調用流程:
  • 如上圖所示,用戶在商戶的H5網站下單支付后,商戶系統按照手機網站支付接口alipay.trade.wap.payAPI的參數規范生成訂單數據,然后在前端頁面通過Form表單的形式請求到支付寶。此時支付寶會自動將頁面跳轉至支付寶H5收銀台頁面,如果用戶手機上安裝了支付寶APP,則自動喚起支付寶APP。開發者需要關注安裝了支付寶和未安裝支付寶的兩種測試場景,對於在手機瀏覽器喚起H5頁面的模式下,如果安裝了支付寶卻沒有喚起,大部分原因是當前瀏覽器不在支付寶配置的白名單內。
  • 對於商戶app內嵌webview中的支付場景,建議集成支付寶App支付產品。或者您可以使用手機網站支付轉Native支付的方案,不建議在您的APP中直接接入手機網站支付。
  • 用戶在支付寶APP或H5收銀台完成支付后,會根據商戶在手機網站支付API中傳入的前台回跳地址return_url自動跳轉回商戶頁面,同時在URL請求中以Query String的形式附帶上支付結果參數,詳細回跳參數見“手機網站支付接口alipay.trade.wap.pay”前台回跳參數。

注意:在ios系統中,喚起支付寶App支付完成后,不會自動回到瀏覽器或商戶APP。用戶可手工切回到瀏覽器或商戶APP;支付寶H5收銀台會自動跳轉回商戶return_url指定的頁面。

  • 支付寶還會根據原始支付API中傳入的異步通知地址notify_url,通過POST請求的形式將支付結果作為參數通知到商戶系統,詳情見支付結果異步通知。
  • 除了正向支付流程外,支付寶也提供交易查詢、關閉、退款、退款查詢以及對賬等配套API。

特別注意:

  • 由於前台回跳的不可靠性,前台回跳只能作為商戶支付結果頁的入口,最終支付結果必須以異步通知或查詢接口返回為准,不能依賴前台回跳。
  • 商戶系統接收到異步通知以后,必須通過驗簽(驗證通知中的sign參數)來確保支付通知是由支付寶發送的。詳細驗簽規則參考異步通知驗簽。
  • 接受到異步通知並驗簽通過后,一定要檢查通知內容,包括通知中的app_id, out_trade_no, total_amount是否與請求中的一致,並根據trade_status進行后續業務處理

2.環境接入

2.1SDK包下載:

<dependency>
  <groupId>com.alipay.sdk</groupId>
  <artifactId>alipay-sdk-java</artifactId>
  <version>4.3.0.ALL</version>
</dependency>

2.2公私鑰文件配置


3.沙箱測試

沙箱環境提供測試賬戶:買家賬號,商戶賬戶。可自行充值

3.1java后端發送支付請求:

@RequestMapping("/pay")
public void pay(HttpServletResponse response, String amount) {
   String form = null;
   try {
       form = PayUtil.pay(amount);
   } catch (AlipayApiException e) {
       form = "pay error!";
       e.printStackTrace();
   }
   response.setContentType("text/html;charset=" + "utf-8");
   try {
       response.getWriter().write(form);//直接將完整的表單html輸出到頁面
       response.getWriter().flush();
       response.getWriter().close();
   } catch (IOException e) {
       e.printStackTrace();
   }

}

public static String pay(String amount) throws AlipayApiException {
   AlipayClient alipay_client = new DefaultAlipayClient(server_url, app_id, private_key, format, charset,   alipay_pubic_key, sign_type);
   AlipayTradeWapPayRequest alipay_request = new AlipayTradeWapPayRequest();
   AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
   model.setOutTradeNo(getOutOrderNo());
   model.setSubject(subject);
   model.setTotalAmount(amount);
   model.setTimeoutExpress(timeout_express);
   model.setProductCode(product_code);
   alipay_request.setBizModel(model);
   // 設置異步通知地址
   alipay_request.setNotifyUrl(notify_url);
   // 設置同步地址
   alipay_request.setReturnUrl(return_url);

   // 調用SDK生成表單
   AlipayResponse alipay_response = alipay_client.pageExecute(alipay_request);
   String form = alipay_response.getBody();
   System.out.println(alipay_response.isSuccess() + ":" + form);
   return form;

}

后端向支付寶發送支付請求,SDK將根據私鑰內容對請求進行簽名,支付寶根據提前配置的公鑰進行驗簽通過后響應。返回的字符內容前端以H5的形式展示,依據內容來看form表單自動提交至支付寶付款界面。登錄之前的沙箱買家賬戶進行支付即可。

3.2支付回調接口和 結果頁面回調接口

@RequestMapping("/notify")
public void alipayNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {

   PrintWriter writer = response.getWriter();
   //獲取支付寶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] + ",";
       }
       //亂碼解決,這段代碼在出現亂碼時使用。如果mysign和sign不相等也可以使用這段代碼轉化
       //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
       params.put(name, valueStr);
   }
   //獲取支付寶的通知返回參數,可參考技術文檔中頁面跳轉同步通知參數列表(以下僅供參考)//

   String out_trade_no = "";
   String trade_no = "";
   String trade_status = "";

   try {
       //商戶訂單號

       out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");

       //支付寶交易號

       trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");

       //交易狀態
       trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");

   } catch (UnsupportedEncodingException e) {
       e.printStackTrace();
   }

   //獲取支付寶的通知返回參數,可參考技術文檔中頁面跳轉同步通知參數列表(以上僅供參考)//
   //計算得出通知驗證結果
   //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
   boolean verify_result = false;
   try {
       verify_result = AlipaySignature.rsaCheckV1(params, PayUtil.alipay_pubic_key, PayUtil.charset, "RSA2");
   } catch (AlipayApiException e) {
       e.printStackTrace();
   }

   if (verify_result) {//驗證成功
       //////////////////////////////////////////////////////////////////////////////////////////
       //請在這里加上商戶的業務邏輯程序代碼
       System.out.println("商戶的業務邏輯程序代碼-notify:" + out_trade_no + " trade_status:" + trade_status);

       //——請根據您的業務邏輯來編寫程序(以下代碼僅作參考)——

       if (trade_status.equals("TRADE_FINISHED")) {
           //判斷該筆訂單是否在商戶網站中已經做過處理
           //如果沒有做過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程序
           //請務必判斷請求時的total_fee、seller_id與通知時獲取的total_fee、seller_id為一致的
           //如果有做過處理,不執行商戶的業務程序
           System.out.println("TRADE_FINISHED");
           //注意:
           //如果簽約的是可退款協議,退款日期超過可退款期限后(如三個月可退款),支付寶系統發送該交易狀態通知
           //如果沒有簽約可退款協議,那么付款完成后,支付寶系統發送該交易狀態通知。
       } else if (trade_status.equals("TRADE_SUCCESS")) {
           //判斷該筆訂單是否在商戶網站中已經做過處理
           //如果沒有做過處理,根據訂單號(out_trade_no)在商戶網站的訂單系統中查到該筆訂單的詳細,並執行商戶的業務程序
           //請務必判斷請求時的total_fee、seller_id與通知時獲取的total_fee、seller_id為一致的
           //如果有做過處理,不執行商戶的業務程序
           System.out.println("TRADE_SUCCESS");
           //注意:
           //如果簽約的是可退款協議,那么付款完成后,支付寶系統發送該交易狀態通知。
       }

       //——請根據您的業務邏輯來編寫程序(以上代碼僅作參考)——
       //writer.clear();
       writer.println("success");    //請不要修改或刪除

       //////////////////////////////////////////////////////////////////////////////////////////
   } else {//驗證失敗
       writer.println("fail");
   }
}

支付回調時,首先進行驗簽操作,驗證成功后根據提供的訂單號,支付狀態做相應的業務處理。

@RequestMapping("/returnUrl")
public void alipayReturn(HttpServletRequest request, HttpServletResponse response) throws IOException {
    PrintWriter writer = response.getWriter();
    //獲取支付寶GET過來反饋信息
    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] + ",";
        }
        //亂碼解決,這段代碼在出現亂碼時使用。如果mysign和sign不相等也可以使用這段代碼轉化
        try {
            valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        params.put(name, valueStr);
    }


    String out_trade_no = "";
    String trade_no = "";
    try {
        //獲取支付寶的通知返回參數,可參考技術文檔中頁面跳轉同步通知參數列表(以下僅供參考)//
        //商戶訂單號
        out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");

        //支付寶交易號
        trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }

    System.out.println("商戶的業務邏輯程序代碼-return_url:" + out_trade_no);

    //獲取支付寶的通知返回參數,可參考技術文檔中頁面跳轉同步通知參數列表(以上僅供參考)//
    //計算得出通知驗證結果
    //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
    boolean verify_result = false;
    try {
        verify_result = AlipaySignature.rsaCheckV1(params, PayUtil.alipay_pubic_key, PayUtil.charset, "RSA2");
    } catch (AlipayApiException e) {
        e.printStackTrace();
    }

    if (verify_result) {//驗證成功
        //////////////////////////////////////////////////////////////////////////////////////////
        //請在這里加上商戶的業務邏輯程序代碼

        //該頁面可做頁面美工編輯
        //out.clear();
        writer.println("check success<br />");
        //——請根據您的業務邏輯來編寫程序(以上代碼僅作參考)——

        //////////////////////////////////////////////////////////////////////////////////////////
    } else {
        //該頁面可做頁面美工編輯
        //out.clear();
        writer.println("check fail");
    }
}

結果頁面回調時,首先進行驗簽操作,驗證成功后根據提供的訂單號,做相應的業務處理,並可以控制跳轉的結果頁面。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM