APP接入支付寶支付之服務端實現
最近公司接了一個外包專案,開發過程中用到了呼叫微信和支付寶的第三方支付介面,因為之前沒用整合過,所以這次用到了之後就想總結一下分享給大家,這裡只介紹支付寶的APP支付和提現介面的服務端接入實現。
首先,要接入第三方的介面,最重要的還是先看官方文件,因為不管你從哪裡搜尋到的文章都是基於官方的文件API說明和使用方法。以前我剛做開發的時間遇到新的東西就喜歡百度找現成其他博主寫的教程然後拷過來改。後來發現如果官方API變動或者更新了的話那還是要根據說明官方API文件來的(因為我以前就遇到過這樣的坑!)。
先去 https://docs.open.alipay.com/204看一下大概的產品介紹和整個呼叫流程,這個也是蠻重要的。因為支付寶APP支付介面的呼叫是服務端和客戶端一起聯合完成的。
接入過程中IOS那邊遇到了點小問題,就是由於沒仔細看說明文件,他一開始把伺服器端生成訂單資訊的事情也做了,後來我跟他又對了一下他才恍然大悟,客戶端那邊其實只要拿到服務端傳過來的orderString再喚起支付寶就ok了。
第一步:企業商戶先在支付寶開放平臺建立應用,然後上傳商戶公鑰,之後會生成一個支付寶公鑰。關於公私鑰的生成和上傳請移步官方文件:https://docs.open.alipay.com/291/105972。
第二步:專案整合支付寶SDK
在pom.xml裡新增依賴:
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.3.87.ALL</version>
</dependency>
第三步:封裝一個配置資訊類
public class AlipayConfig { /** * 正式環境請求地址 */ public static String ALIPAY_URL = "https://openapi.alipay.com/gateway.do"; /** * 支付寶分配給開發者的應用ID * */ public static String APP_ID = "APP_ID"; /** * 支付介面名稱 */ public static String PAY_METHOD = "alipay.trade.app.pay"; /** * 提現介面名稱 */ public static String TRANSFER_METHOD = "alipay.fund.trans.toaccount.transfer"; /** * 僅支援JSON */ public static String FORMAT = "JSON"; /** * 請求使用的編碼格式 */ public static String CHARSET = "utf-8"; /** * 商戶生成簽名字串所使用的簽名演算法型別 */ public static String SIGN_TYPE = "RSA2"; /** * 支付寶公鑰 */ public static String ALIPAY_PUBLIC_KEY = "ALIPAY_PUBLIC_KEY"; /** * 商戶私鑰 */ public static String PRIVATE_KEY = "PRIVATE_KEY"; /** * 回撥地址 */ public static String CALLBACK_URL = "https://xxx.com/xxx/xx"; }
注意:伺服器端需要的公鑰是支付寶公鑰而不是商戶公鑰。伺服器端用商戶私鑰加密後將資料傳過去。支付寶那邊會根據appid找到你上傳的公鑰進行解密。解密成功會生成訂單資訊響應給我們的伺服器,然後專案整合的支付寶SDK會根據你配置的支付寶公鑰進行驗籤,沒丟擲異常就說明驗籤成功然後你就可以把orderString傳給客戶端。
第四步:開始寫呼叫的程式碼咯
// 例項化客戶端
AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.ALIPAY_URL, AlipayConfig.APP_ID,
AlipayConfig.PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY,
AlipayConfig.SIGN_TYPE);
// 例項化具體API對應的request類,類名稱和介面名稱對應,當前呼叫介面名稱:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
// SDK已經封裝掉了公共引數,這裡只需要傳入業務引數。以下方法為sdk的model入參方式(model和biz_content同時存在的情況下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setBody("使用者充值");
model.setSubject("XX平臺APP");
model.setOutTradeNo("自己系統內的訂單編號");// outtradeno 生存訂單
model.setTimeoutExpress("60m");
model.setTotalAmount("支付金額");
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
request.setNotifyUrl(AlipayConfig.CALLBACK_URL);//非同步回撥url
// 這裡和普通的介面呼叫不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
// System.out.println(response.getBody());//就是orderString 可以直接給客戶端請求,無需再做處理。
第五步:編寫非同步回撥介面將支付寶那邊返回的資料進行分析然後根據返回碼判斷支付成功還是失敗等編寫自己專案的剩下業務邏輯,這個我就不寫了。
/**
* @author:Jack
* @function:支付寶充值結果通知介面
* @date 2018年9月17日
*/
@RequestMapping(value = "/getAlipayNotify", produces = "application/json;charset=UTF-8", method = {
RequestMethod.GET, RequestMethod.POST })
public void getAlipayNotify(HttpServletRequest request) {
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對應應用下檢視。
try {
boolean flag = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET,
AlipayConfig.SIGN_TYPE);
if (flag) {
String trade_status = params.get("trade_status");
String out_trade_no = params.get("out_trade_no");
String trade_no = params.get("trade_no");
if ("TRADE_SUCCESS".equals(trade_status)) { // 交易支付成功的執行相關業務邏輯
} else if ("TRADE_CLOSED".equals(trade_status)) { // 未付款交易超時關閉,或支付完成後全額退款,執行相關業務邏輯
}
}
} catch (Exception e) {
e.printStackTrace();
}
}