搞定支付接口—支付寶即時到賬支付接口詳細流程和代碼
搞定支付接口(一) 支付寶即時到賬支付接口詳細流程和java代碼
為避免你們和我一樣被支付接口搞得焦頭爛額,寫一個從申請開始到能收到錢為止的詳細教程,實際上各個語言都可以用來集成支付接口,我用java來舉例。
正所謂知己知彼,百戰不殆。首先,我們來看一看支付寶平臺給我們的說明。
- 打開支付寶
- 選擇商家平臺
- 選擇電腦支付
進行如上操作後,來到如下圖所示的頁面
沒有商家支付寶賬號的需要註冊,需要營業執照,經營信息,網址信息,聯系人等等數據(圖裏說的很詳細)
服務開通後,我們就可以集成了,我們點擊如何集成查看文檔
如圖所示,我們可以直接下載demo,進行快速集成,這是最方便的辦法了,我會采用這種方法,但使用即時到賬接口首先需要簽約,點擊如何簽約,支付寶就教你怎麽簽,無非就是填表,審核。但這一步很重要,因為我們需要生成的密鑰組成參數向支付寶發出請求(下面會詳細說)。
簽約成功之後,我們需要合作夥伴PID和MD5密鑰,在如下頁面獲取(圖我從官網文檔截得)
前期所有準備都做好了,再總結一下前期需要的東西:
- 開通商家賬戶和即時到賬服務
- 下載demo
- pid和md5密鑰
我們來繼續,解壓demo,選擇java utf-8版本,導入項目
支付的流程為
- 買家點擊提交訂單
- 商家生成訂單,以key=value的形式向支付寶發送請求
- 支付寶接到請求後生成訂單
- 買家選擇掃碼或密碼支付完成後,支付寶同步或異步向商家發送請求,提示訂單完成
商家要傳遞給支付寶的參數列表在前面給的開發文檔中也能找到,支付寶提示的參數有必填和不必填兩種,可以自己選擇。
在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的可以自己在官網查閱文檔實現
組裝待簽名字符串
- 篩選
大部分支付寶接口中要剔除sign_type、sign兩個參數,個別接口只剔除sign參數。存在空值的參數必須剔除。排序
在參數集合中,根據參數(不是參數對應的值)的第一個字符的鍵值ASCII碼遞增排序,如果遇到相同字符則按照第二個字符的鍵值ASCII碼遞增排序,以此類推。拼接
在參數集合中,把每個參數及其值組合成“參數=參數值”的格式(在無線產品手機安全支付中,每個參數的組合格式是“參數=”參數值””),並且把這些參數用&字符連接起來調用簽名函數
- 簽名函數
調用md5加密函數,對已經與MD5密鑰拼接好的新字符串做加密運算簽名結果的用途
- 得到的簽名結果也是一串字符串,這串字符串便是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;
}
然後就全部完畢了。
這個文章寫的並不太滿意,這是我做過支付寶接口很久以後才寫的文章,好多東西都記不起來了,之前記得還在官網看過支付寶支付流程的序列圖,那個很清晰,現在我也沒找到。
這幾天也一直在忙,每次都是寫幾個字就不得不忙別的了,斷斷續續前後也有點連不起來,以後有時間我會再把這篇文章細化修改一下,看了有不懂的地方也歡迎留言,我看到會盡量解答
搞定支付接口—支付寶即時到賬支付接口詳細流程和代碼