前言
最近在工作中需要使用支付寶App支付,在初次使用過程中也不可避免的出現了一些問題,那么本次隨筆主要是概述支付寶app支付服務端的整個實現過程以及就服務端出現的一些問題做一些總結。
1.準備工作
1.1 入駐螞蟻金服開放平臺
https://open.alipay.com/platform/home.htm
1.2 創建應用
首先需要創建一個應用



然后需要設置應用公鑰。

下載支付寶密鑰生成器。生成成功之后會有商戶應用公鑰和私鑰,將公鑰復制到這里, 私鑰請妥善保存。下載地址:https://docs.open.alipay.com/291/106097/。保存設置之后會顯示支付寶公鑰,請妥善保存。

最后提交審核,等待。
注意:如果應用審核通過上線之后,支付寶公鑰忘記后可通過進入應用詳情頁,按如下圖所示查看支付寶公鑰。

2.Maven依賴
首先需要下載SDK,https://docs.open.alipay.com/54/104509。
完成之后,需要切換命令行,進入SDK所在目錄,執行如下命令。如果命令無法執行,請百度如何配置maven環境變量,配置好之后再執行。
mvn install:install-file -DgroupId=com.alipay.sdk -DartifactId=alipay-sdk-JAVA -Dversion=3.1.0 -Dpackaging=jar -Dfile=SDK文件名.jar
groupId:可以自己定義,pom文件依賴依據與此
artifactId:可以自己定義,pom文件依賴依據與此
version:可以自己定義,pom文件依賴依據與此
packaging:打包方式(jar)
file:文件的路徑的路徑
在pom.xml中引入依賴,如下。
<!-- 支付寶支付相關start -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.1.0</version>
</dependency>
<!-- 支付寶支付相關end -->
3.配置文件中配置支付寶相關參數
#支付寶支付相關配置
#支付寶分配給開發者的應用Id
aliPayAppId=XXX
#賣家支付寶用戶號(對應異步通知返回參數seller_id)(可以不配置,只是異步通知時為了進一步校驗而配置)
aliPaySellerId=XXX
#賣家支付寶賬號(對應異步通知返回參數seller_email)(可以不配置,只是異步通知時為了進一步校驗而配置)
alipayAccount=XXX
#商戶應用公鑰
rsaPublicKey=XXX
#商戶應用私鑰(注意,如果是Java語言,需要使用pkcs8格式的私鑰,避免出現不可預知的錯誤)
rsaPrivatKey=XXX
#支付寶公鑰
rsaAlipayPublicKey=XXX
#加密方式
signType=XXX
#僅支持JSON
alipayFormat=json
#請求使用的編碼格式,如utf-8,gbk,gb2312等
alipayCharset=utf-8
4.生成Android/ target=_blank class=infotextkey>安卓端需要的orderString信息的接口方法
/**
*app支付
*
*@author lp
*@date 2019/1/4 16:32
*/
@ApiOperation("app支付")
@RequestMapping(value = "alipay", method = RequestMethod.POST)
public String alipay(@RequestBody CombinedPaymentDto dto, HttpServletResponse response, HttpServletRequest request) {
response.setHeader("Access-Control-Allow-Origin", "*");
// 獲取項目中實際的訂單的信息
// 此處是相關業務代碼
// 獲取配置文件中支付寶相關信息(可以使用自己的方式獲取)
String aliPayGateway = PropertiesUtils.getInstace("config/webService.properties").getProperty("aliPayGateway");
String aliPayAppId = PropertiesUtils.getInstace("config/webService.properties").getProperty("aliPayAppId");
String rsaPublicKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaPublicKey");
String rsaPrivatKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaPrivatKey");
String rsaAlipayPublicKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaAlipayPublicKey");
String signType = PropertiesUtils.getInstace("config/webService.properties").getProperty("signType");
String alipayFormat = PropertiesUtils.getInstace("config/webService.properties").getProperty("alipayFormat");
String alipayCharset = PropertiesUtils.getInstace("config/webService.properties").getProperty("alipayCharset");
// 開始使用支付寶SDK中提供的API
AlipayClient alipayClient = new DefaultAlipayClient(aliPayGateway, aliPayAppId, rsaPrivatKey, alipayFormat, alipayCharset, rsaAlipayPublicKey, signType);
// 注意:不同接口這里的請求對象是不同的,這個可以查看螞蟻金服開放平臺的API文檔查看
AlipayTradeAppPayRequest alipayRequest = new AlipayTradeAppPayRequest();
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setBody("XXX");
model.setSubject("XXX");
// 唯一訂單號 根據項目中實際需要獲取相應的
model.setOutTradeNo("");
// 支付超時時間(根據項目需要填寫)
model.setTimeoutExpress("30m");
// 支付金額(項目中實際訂單的需要支付的金額,金額的獲取與操作請放在服務端完成,相對安全)
model.setTotalAmount("");
model.setProductCode("QUICK_MSECURITY_PAY");
alipayRequest.setBizModel(model);
// 支付成功后支付寶異步通知的接收地址url
alipayRequest.setNotifyUrl("XXX/getAlipayNotifyInfo");
// 注意:每個請求的相應對象不同,與請求對象是對應。
AlipayTradeAppPayResponse alipayResponse = null;
try {
alipayResponse = alipayClient.sdkExecute(alipayRequest);
} catch (AlipayApiException e) {
e.printStackTrace();
}
// 返回支付相關信息(此處可以直接將getBody中的內容直接返回,無需再做一些其他操作)
return alipayResponse.getBody();
}
5.支付成功后服務端接收支付寶發來的異步通知的接口方法
/**
*接收支付寶異步通知消息
*
*@author lp
*@date 2019/1/4 17:19
*/
@ApiOperation("接收支付寶異步通知消息")
@RequestMapping(value = "getAlipayNotifyInfo", method = RequestMethod.POST)
public String getAlipayNotifyInfoOfCombinedPayment(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
response.setHeader("Access-Control-Allow-Origin", "*");
// 解決POST請求中文亂碼問題(推薦使用此種方式解決中文亂碼,因為是支付寶發送異步通知使用的是POST請求)
request.setCharacterEncoding("UTF-8");
//獲取支付寶POST過來反饋信息
Map<String,String> params = new HashMap<>();
Map<String,String[]> requestParams = request.getParameterMap();
for (Iterator<String> 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] + ",";
}
// 官方demo中使用如下方式解決中文亂碼,在此本人不推薦使用,可能會出現中文亂碼解決無效的問題。
// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
params.put(name, valueStr);
}
// 支付寶公鑰(請注意,不是商戶公鑰)
String rsaAlipayPublicKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaAlipayPublicKey");
String signType = PropertiesUtils.getInstace("config/webService.properties").getProperty("signType");
String alipayCharset = PropertiesUtils.getInstace("config/webService.properties").getProperty("alipayCharset");
boolean signVerified = false;
try {
//調用SDK驗證簽名
signVerified = AlipaySignature.rsaCheckV1(params, rsaAlipayPublicKey, alipayCharset, signType);
if(signVerified) {
// 驗證通知后執行自己項目需要的業務操作
// 一般需要判斷支付狀態是否為TRADE_SUCCESS
// 更嚴謹一些還可以判斷 1.appid 2.sellerId 3.out_trade_no 4.total_amount 等是否正確,正確之后再進行相關業務操作。
// 成功要返回success,不然支付寶會不斷發送通知。
return "success";
}
// 驗簽失敗 筆者在這里是輸出log,可以根據需要做一些其他操作
// 失敗要返回fail,不然支付寶會不斷發送通知。
return "fail";
} catch (AlipayApiException e) {
e.printStackTrace();
// 驗簽異常 筆者在這里是輸出log,可以根據需要做一些其他操作
return "fail";
}
}