1. 程式人生 > >支付寶APP支付 ---伺服器開發

支付寶APP支付 ---伺服器開發

寫過微信支付再寫支付寶支付就好理解了很多。而且支付寶提供的sdk很好用,幾行程式碼就可以了~~,寫的程式碼還沒有測試,應該問題不大,如果有錯誤希望各位指正。

對幾個容易混淆的引數進行說明:
1. 應用私鑰: 通過工具生成,生成之後請儲存好,在支付寶開發平臺找不到。
2. 應用公鑰:通過工具生成,生成之後需要填寫到支付寶開發平臺中。
3. 支付寶公鑰:支付寶生成的,可以在支付寶開發平臺中看到。
如果對非對稱加密演算法很熟悉的應該很好理解這幾個引數。

這個圖是APP支付的一個流程說明,圖畫的比較詳細就不再敘述了。
這裡寫圖片描述
開始寫程式碼,因為我只幫別人寫一部分,所以只完成工具類,具體controller沒有,下面是引數封裝的工具類。

    /**
     * 請求引數組裝
     * 
     * @param outTradeNo  商戶網站唯一訂單號
     * @param totalAmount  訂單總金額,單位為元,精確到小數點後兩位,取值範圍[0.01,100000000]
     * @param subject  商品的標題/交易標題/訂單標題/訂單關鍵字等。
     * @param notifyUrl  回撥地址
     * @throws UnsupportedEncodingException 
     */
    public static Map<String, String> setParam(String
outTradeNo, String totalAmount, String subject, String notifyUrl) throws UnsupportedEncodingException { Map<String, String> map = new HashMap<String, String>(); map.put("app_id", Config.APP_ID); map.put("method", Config.PAY_METHOD); map.put("charset"
, Config.CHARSET); map.put("sign_type", Config.SIGN_TYPE); map.put("timestamp", Config.geTtimestamp()); map.put("version", "1.0"); map.put("notify_url", notifyUrl); // 業務請求引數封裝 Map<String, Object> biz_content = new HashMap<>(); biz_content.put("subject", URLEncoder.encode(subject, "UTF-8")); biz_content.put("out_trade_no", outTradeNo); biz_content.put("total_amount", totalAmount); biz_content.put("product_code", "QUICK_MSECURITY_PAY"); map.put("biz_content", biz_content.toString()); String sign = null; try { //呼叫支付寶SDK獲取簽名 RSA簽名params 待簽名引數map privateKey 私鑰 charset 簽名編碼格式 sign = AlipaySignature.rsaSign(map, Config.APP_PRIVATE_KEY, Config.CHARSET); } catch (AlipayApiException e) { e.printStackTrace(); System.out.println(e.getMessage()); logger.error("======簽名錯誤=====" + e.getMessage()); } map.put("sign", URLEncoder.encode(sign, "UTF-8")); return map; }

注意(很重要)

  • 商戶在請求引數中,自己附屬的一些額外引數,不要和支付寶系統中約定的key(下表中 公共請求引數\請求引數)重名,否則將可能導致未知的異常。需要對內容進行encode編碼處理。
    商戶支付請求引數的安全注意點:
  • 請求引數的sign欄位請務必在服務端完成簽名生成(不要在客戶端本地簽名);
  • 支付請求中的訂單金額total_amount,請務必依賴服務端,不要輕信客戶端上行的資料(客戶端本地上行資料在使用者手機環境中無法確保一定安全)。

伺服器接收非同步支付通知
對於App支付產生的交易,支付寶會根據原始支付API中傳入的非同步通知地址notify_url,通過POST請求的形式將支付結果作為引數通知到商戶系統。
另外需要注意的:
1.必須保證伺服器非同步通知頁面(notify_url)上無任何字元,如空格、HTML標籤、開發系統自帶丟擲的異常提示資訊等,
2.程式執行完後必須列印輸出“success”(不包含引號)。如果商戶反饋給支付寶的字元不是success這7個字元,支付寶伺服器會不斷重發通知,直到超過24小時22分鐘。

在收到支付寶的通知時需要進行驗籤和業務處理,驗籤支付寶的SDK也提供了 ,是不是很方便,

    /**
     * 驗籤
     * 校驗支付寶發過來的簽名是否正確,使用支付寶的公鑰驗籤
     * @param request
     * @return true 驗籤通過
     */
    public static boolean signVerified(HttpServletRequest request) {
        Enumeration<?> pNames = request.getParameterNames();
        Map<String, String> param = new HashMap<String, String>();
        try {
            while (pNames.hasMoreElements()) {
                String pName = (String) pNames.nextElement();
                param.put(pName, request.getParameter(pName));
            }
            boolean signVerified = AlipaySignature.rsaCheckV1(param, Config.ALIPAY_PUBLIC_KEY, Config.CHARSET); // 校驗簽名是否正確
            return signVerified;
        } catch (Exception e) {
            logger.error("============驗籤錯誤=============" + e.getMessage());
            System.out.println(e.getMessage());
            return false;
        }
    }

回撥的controller 只寫了一部分,僅供參考


    @RequestMapping(value = "/pay/notify", method = RequestMethod.POST)
    public void orderPayNotify(HttpServletRequest request, HttpServletResponse response) {
        logger.info("==============收到支付寶的非同步通知==========================");
        // 獲取到返回的所有引數 先判斷是否交易成功trade_status 再做簽名校驗
        if ("TRADE_SUCCESS".equals(request.getParameter("trade_status"))) {
            try {
                boolean signVerified = PayUtils.signVerified(request);
                if (signVerified) {
                    //  驗籤成功後
                    // 1、商戶需要驗證該通知資料中的out_trade_no是否為商戶系統中建立的訂單號,
                    // 2、判斷total_amount是否確實為該訂單的實際金額(即商戶訂單建立時的金額),
                    // 3、校驗通知中的seller_id(或者seller_email) 是否為out_trade_no這筆單據的對應的操作方(有的時候,一個商戶可能有多個seller_id/seller_email),
                    // 4、驗證app_id是否為該商戶本身。上述1、2、3、4有任何一個驗證不通過,則表明本次通知是異常通知,務必忽略。在上述驗證通過後商戶必須根據支付寶不同型別的業務通知,正確的進行不同的業務處理,並且過濾重複的通知結果資料。在支付寶的業務通知中,只有交易通知狀態為TRADE_SUCCESS或TRADE_FINISHED時,支付寶才會認定為買家付款成功。
                    // 對支付結果中的業務內容進行1\2\3\4二次校驗,校驗成功後在response中返回success,
                    logger.info("=====訂單支付成功:====" + request.getParameterMap().toString()); 
                    //通知支付寶後臺,已收到通知
                    response.getWriter().println("success");
                } else {
                    // TODO 驗籤失敗則記錄異常日誌,
                    logger.info("======驗籤失敗=======");
                }
            } catch (Exception e) {
                e.printStackTrace();
                logger.info("========通知處理失敗=========="+e.getMessage());
            }
        }else{
            logger.info("========交易失敗==========");
        }
     }

伺服器寫好了 ~