1. 程式人生 > >搞定支付接口—支付寶即時到賬支付接口詳細流程和代碼

搞定支付接口—支付寶即時到賬支付接口詳細流程和代碼

getc 配置 鍵值 writer his 僅供參考 ttr package art

搞定支付接口(一) 支付寶即時到賬支付接口詳細流程和java代碼

為避免你們和我一樣被支付接口搞得焦頭爛額,寫一個從申請開始到能收到錢為止的詳細教程,實際上各個語言都可以用來集成支付接口,我用java來舉例。


正所謂知己知彼,百戰不殆。首先,我們來看一看支付寶平臺給我們的說明。

  1. 打開支付寶
  2. 選擇商家平臺
  3. 選擇電腦支付

進行如上操作後,來到如下圖所示的頁面

技術分享圖片

沒有商家支付寶賬號的需要註冊,需要營業執照,經營信息,網址信息,聯系人等等數據(圖裏說的很詳細)

服務開通後,我們就可以集成了,我們點擊如何集成查看文檔

技術分享圖片

如圖所示,我們可以直接下載demo,進行快速集成,這是最方便的辦法了,我會采用這種方法,但使用即時到賬接口首先需要簽約,點擊如何簽約,支付寶就教你怎麽簽,無非就是填表,審核。但這一步很重要,因為我們需要生成的密鑰組成參數向支付寶發出請求(下面會詳細說)。

簽約成功之後,我們需要合作夥伴PID和MD5密鑰,在如下頁面獲取(圖我從官網文檔截得)
技術分享圖片


前期所有準備都做好了,再總結一下前期需要的東西

  1. 開通商家賬戶和即時到賬服務
  2. 下載demo
  3. pid和md5密鑰

我們來繼續,解壓demo,選擇java utf-8版本,導入項目

支付的流程為

  1. 買家點擊提交訂單
  2. 商家生成訂單,以key=value的形式向支付寶發送請求
  3. 支付寶接到請求後生成訂單
  4. 買家選擇掃碼或密碼支付完成後,支付寶同步或異步向商家發送請求,提示訂單完成

商家要傳遞給支付寶的參數列表在前面給的開發文檔中也能找到,支付寶提示的參數有必填和不必填兩種,可以自己選擇。

在demo src的com\alipay\config包下有AlipayConfig類。大部分參數可以在其中配置,在使用時直接用就可以了,為了維護方便,我們可以用配置文件的方法寫到文件裏,動態讀取。但是有一些參數需要註意:
訂單號需要自己隨機生成sign簽名是動態生成的

package
com.alipay.config; /* * *類名:AlipayConfig *功能:基礎配置類 *詳細:設置帳戶有關信息及返回路徑 *版本:3.4 *修改日期:2016-03-08 *說明: *以下代碼只是為了方便商戶測試而提供的樣例代碼,商戶可以根據自己網站的需要,按照技術文檔編寫,並非一定要使用該代碼。 *該代碼僅供學習和研究支付寶接口使用,只是提供一個參考。 */ public class AlipayConfig { //↓↓↓↓↓↓↓↓↓↓請在這裏配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ // 合作身份者ID,簽約賬號,以2088開頭由16位純數字組成的字符串,查看地址:https://b.alipay.com/order/pidAndKey.htm public static String partner = "2088好幾個數字"; // 收款支付寶賬號,以2088開頭由16位純數字組成的字符串,一般情況下收款賬號就是簽約賬號 public static String seller_id = partner; // MD5密鑰,安全檢驗碼,由數字和字母組成的32位字符串,查看地址:https://b.alipay.com/order/pidAndKey.htm public static String key = "好長一串數字和字母"; // 服務器異步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問 public static String notify_url = "http://www.wechat.com/AliPayTest/pay_notify_url"; // 體會到我的幽默感了嗎 // 頁面跳轉同步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問 public static String return_url = "http://www.wechat.com/AliPayTest/pay_return_url"; // 簽名方式 public static String sign_type = "MD5"; // 調試用,創建TXT日誌文件夾路徑,見AlipayCore.java類中的logResult(String sWord)打印方法。 public static String log_path = "F:\\"; // 字符編碼格式 目前支持 gbk 或 utf-8 public static String input_charset = "utf-8"; // 支付類型 ,無需修改 public static String payment_type = "1"; // 調用的接口名,無需修改 public static String service = "create_direct_pay_by_user"; //↑↑↑↑↑↑↑↑↑↑請在這裏配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ //↓↓↓↓↓↓↓↓↓↓ 請在這裏配置防釣魚信息,如果沒開通防釣魚功能,為空即可 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ // 防釣魚時間戳 若要使用請調用類文件submit中的query_timestamp函數 public static String anti_phishing_key = ""; // 客戶端的IP地址 非局域網的外網IP地址,如:221.0.0.1 public static String exter_invoke_ip = ""; //↑↑↑↑↑↑↑↑↑↑請在這裏配置防釣魚信息,如果沒開通防釣魚功能,為空即可 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ }

寫一個配置類獲取配置

public class Property {
    private static Properties p = new Properties();
    static {
        InputStream in = AlipayConfig.class.getResourceAsStream("alipay.properties");
        try {
            p.load(in);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    static public String getProperty(String property) {
        return p.getProperty(property);
    }
}

然後將參數配置寫到alipay.properties的文件,有參數要修改的時候不用重新編譯代碼,只要修改配置文件就可以了。


前面主要是配置,按支付寶提供的文檔配置好各種參數後,配置這一步就完成了。

後面我們來講一講下訂單。

買家下訂單之後,我們接收請求參數,再加上配置的參數生成要發送給支付寶的訂單Map集合。

// 訂單號:
String out_trade_no = "test20170213145553";

//把請求參數打包成Map
Map<String, String> sParaTemp = new HashMap<>();
sParaTemp.put("service", AlipayConfig.service);
sParaTemp.put("partner", AlipayConfig.partner);
sParaTemp.put("seller_id", AlipayConfig.seller_id);
sParaTemp.put("_input_charset", AlipayConfig.input_charset);
sParaTemp.put("payment_type", AlipayConfig.payment_type);
sParaTemp.put("notify_url", AlipayConfig.notify_url);
sParaTemp.put("return_url", AlipayConfig.return_url);
sParaTemp.put("out_trade_no", out_trade_no);
sParaTemp.put("subject", subject);
sParaTemp.put("total_fee", total_fee);
sParaTemp.put("body", desc);

調用支付寶demo給的類的buildRequest靜態方法,將剛才的sParaTemp傳遞過去,生成String類型的字符串,這個字符串其實是個超鏈接,直接放地址欄上就直接將參數發送給支付寶了。

註:支付寶demo在幕後做的工作有很多,分為以下幾步,若不想用demo的可以自己在官網查閱文檔實現

  1. 組裝待簽名字符串

    • 篩選
      大部分支付寶接口中要剔除sign_type、sign兩個參數,個別接口只剔除sign參數。存在空值的參數必須剔除。
    • 排序
      在參數集合中,根據參數(不是參數對應的值)的第一個字符的鍵值ASCII碼遞增排序,如果遇到相同字符則按照第二個字符的鍵值ASCII碼遞增排序,以此類推。

    • 拼接
      在參數集合中,把每個參數及其值組合成“參數=參數值”的格式(在無線產品手機安全支付中,每個參數的組合格式是“參數=”參數值””),並且把這些參數用&字符連接起來

  2. 調用簽名函數

    • 簽名函數
      調用md5加密函數,對已經與MD5密鑰拼接好的新字符串做加密運算
  3. 簽名結果的用途

    • 得到的簽名結果也是一串字符串,這串字符串便是sign參數的值,把這串字符串賦值於sign參數。
String sHtmlText = AlipaySubmit.buildRequest(sParaTemp, "post", "確認");  // 這裏使用支付寶demo給的類來生成請求參數,這點支付寶比微信的文檔方便太多了

直接用response.write()或者我用的struts,用action跳轉到頁面再用字符串鏈接跳轉就行了。

PrintWriter out = response.getWriter();
out.print(sHtmlText);

struts 支付action:

context.put("jump", sHtmlText);
return "send";  // 跳轉給支付寶

struts.xml

<result name="send">/WEB-INF/jump.jsp</result>

jump.jsp:

${requestScope.jump }

這樣就會直接跳轉了。


支付寶接到參數就會生成二維碼,客戶支付後商戶後臺就會收到支付寶發送的返回參數,有sign驗證簽名,訂單號,價格等等信息,若出錯的話支付寶也會返回錯誤碼ILLEGAL_SIGN等,可在支付寶歷史公共錯誤碼頁面查看。

若支付成功,支付寶有同步和異步兩種方式回調商戶網站,這個看當初怎麽配置的,配置的時候會把回調地址寫在請求參數裏發給支付寶,若在自己的電腦上調試,一般會調用同步方法,在服務器上會調用異步方法。

// 服務器異步通知頁面路徑  需http://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問
public static String notify_url = "http://www.wechat.com/pay_notify_url";   // 請再次感受我的幽默感

// 頁面跳轉同步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義參數,必須外網可以正常訪問
public static String return_url = "http://www.wechat.com/pay_return_url";

假如你的配置是這樣寫的,支付寶就會調用同步urlhttp://www.wechat.com/pay_notify_url或者異步urlhttp://www.wechat.com/pay_return_url並附帶請求參數,你在接到請求參數後,需要和你自己的信息比對,若成功的話,就算這筆訂單完成了。

異步回調

public void notifyUrl() {
        Map<String, Object> requestParams = ActionContext.getContext().getParameters();
        Map<String, String> params = null;
        HttpServletResponse response = ServletActionContext.getResponse();
        response.setContentType("text/html;charset=utf-8");
        PrintWriter writer = null;
        try {
            writer = response.getWriter();
        } catch (IOException e) {
            log.warn("支付寶異步支付獲取輸出流失敗:" + e.getMessage());
            return;
        }
        try {
                params = tradeService.splitParam(requestParams);// 分割參數
        } catch (UnsupportedEncodingException e) {
            log.warn("alipay sign convert failed: " + e.getMessage());
            return ;
        }

        //獲取支付寶的通知返回參數,可參考技術文檔中頁面跳轉同步通知參數列表(以下僅供參考)//
        if (AlipayNotify.verify(params)){   //驗證成功
            if (trade_status.equals("TRADE_FINISHED") || trade_status.equals("TRADE_SUCCESS")) {  
                Order verifiedAlipay = tradeService.verifiedAlipay(seller_id, out_trade_no, total_fee);
                if (verifiedAlipay == null) {
                    log.warn("參數驗證失敗");
                    return; // 跳轉支付失敗頁
                }
                writer.print("success");    //請不要修改或刪除
                return;
            } else {  
                log.warn("沒有完成訂單");
                return; 
            }  
        } else {
            log.warn("支付寶異步支付驗證失敗");
            writer.print("fail");   //請不要修改或刪除
        }
    }

同步回調

public String returnUrl() {
        Map<String, Object> requestParams = ActionContext.getContext().getParameters();
        Map<String, String> params = null;
        try {
            params = tradeService.splitParam(requestParams);
            if (params == null) {
                log.warn("簽名驗證失敗-參數列表為空");
                return TRADEERROR;  // 跳轉支付失敗頁
            }
        } catch (UnsupportedEncodingException e) {
            log.warn("alipay sign convert failed: " + e.getMessage());
        }
        if (AlipayNotify.verify(params)) {// 驗證成功  
            if (trade_status.equals("TRADE_FINISHED") || trade_status.equals("TRADE_SUCCESS")) {  
                Order verifiedAlipay = tradeService.verifiedAlipay(seller_id, out_trade_no, total_fee);
                if (verifiedAlipay == null) {
                    log.warn("參數驗證失敗");
                    return TRADEERROR;  // 跳轉支付失敗頁
                }
                putSession(S_TRADE_FINISHED, verifiedAlipay);// 將支付詳情放入session域中,到頁面顯示
            } else {  
                log.warn("沒有完成訂單");
                return TRADEERROR;  // 跳轉支付失敗頁
            }  
        } else {// 驗證失敗  
            log.warn("簽名驗證失敗");
            return TRADEERROR;  // 跳轉支付失敗頁
        }  
        return TRADESUCCESS;
    }

然後就全部完畢了。

這個文章寫的並不太滿意,這是我做過支付寶接口很久以後才寫的文章,好多東西都記不起來了,之前記得還在官網看過支付寶支付流程的序列圖,那個很清晰,現在我也沒找到。
這幾天也一直在忙,每次都是寫幾個字就不得不忙別的了,斷斷續續前後也有點連不起來,以後有時間我會再把這篇文章細化修改一下,看了有不懂的地方也歡迎留言,我看到會盡量解答

搞定支付接口—支付寶即時到賬支付接口詳細流程和代碼