概述
詳細
概述
demo了介紹支付寶中當面付下屬的條碼支付、掃碼支付、訂單查詢、退款申請等接口的集成開發過程。
詳細
在移動支付行業中,支付寶一直占據龍頭行業,市場占有率也遙遙領先。在聚合支付系統中,移動支付服務商一定將支付寶的支付接口接入。條碼支付是支付寶在線下移動支付的一種收款方式。一般流程為消費者通過打開支付寶APP上的付款碼,然后商家使用掃碼槍或是掃碼盒子等條碼識別社保掃描消費者的條碼/二維碼,完成收款。消費者僅需要出示付款碼,所有收款操作是有商戶端完成。
業務的流程圖為:

消費者端流程:

本例子主要基於支付寶的沙箱環境對怎么接入支付寶當面付的一個流程及使用springboot對支付寶sdk的下單、查詢、退款等接口進行了一個封裝。
一.准備工作
首先登錄到支付寶螞蟻金服的開發平台https://open.alipay.com/platform/home.htm,使用支付寶手機APP即可授權登錄。登錄進去效果如下:

我們進入開發服務下面的研發服務,可以看到支付寶已經幫我們建好了沙箱應用,我們可以通過沙箱應用來模擬測試支付及查詢、退款等接口,可以看到:

應用公鑰可以使用SHA2生成,也可以使用SHA1生成,SHA2是支付寶推薦的方式,本例也采取SHA2生成應用公鑰,支付寶為我們提供了一個生成RSA密鑰的工具,地址為https://docs.open.alipay.com/291/105971/,里面有介紹簽名及驗簽的東西,如下圖所示:

接下來介紹一下支付提供的沙箱賬號,我們可以在里面進行任意金額的充值進行模擬測試。

我們可以使用安卓下載支付寶提供的沙箱支付寶應用進行賬號登錄。

二、程序實現
1.首先創建springboot項目在pom.xml文件里面引入相關的依賴
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.15</version>
</dependency>
2.在application.yml文件添加如下配置:
server: port: 8080 alipay: app_id: xxxxx merchant_private_key: xxxxx alipay_public_key: xxxx notify_url: http://yourdomain:8080/notify_url return_url: http://yourdomain:8080/return_url sign_type: RSA2 charset: utf-8 gatewayUrl: https://openapi.alipaydev.com/gateway.do log_path: /tmp/
其中app_id為支付寶沙箱應用對應的app_id,merchant_private_key為商戶私鑰,alipay_public_key為支付寶公鑰,主要用來驗簽
3.主要代碼如下:
1)支付寶參數配置類:
public class AlipayConfig {
@Value("${alipay.app_id}")
public String app_id;
@Value("${alipay.merchant_private_key}")
public String merchant_private_key;
@Value("${alipay.alipay_public_key}")
public String alipay_public_key;
@Value("${alipay.notify_url}")
public String notify_url;
@Value("${alipay.return_url}")
public String return_url;
@Value("${alipay.sign_type}")
public String sign_type;
@Value("${alipay.charset}")
public String charset;
@Value("${alipay.gatewayUrl}")
public String gatewayUrl;
@Value("${alipay.log_path}")
public String log_path;
2)生成二維碼主要邏輯:
QrCodeResponse qrCodeResponse = new QrCodeResponse();
AlipayClient alipayClient =
new DefaultAlipayClient(alipayConfig.getGatewayUrl(), alipayConfig.getApp_id(), alipayConfig.getMerchant_private_key(),
"JSON", alipayConfig.getCharset(), alipayConfig.getAlipay_public_key(), alipayConfig.getSign_type());
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
request.setBizContent("{" +
"\"out_trade_no\":\""+model.getOutTradeNo()+"\"," +
"\"total_amount\":\""+model.getTotalAmount()+"\"," +
"\"subject\":\""+model.getSubject()+"\"," +
"\"timeout_express\":\"90m\"}");
request.setNotifyUrl(alipayConfig.getNotify_url());
AlipayTradePrecreateResponse alipayTradePrecreateResponse = null;
try {
alipayTradePrecreateResponse = alipayClient.execute(request);
} catch (AlipayApiException e) {
e.printStackTrace();
qrCodeResponse.setCode("500");
qrCodeResponse.setMsg("服務器內部錯誤");
return qrCodeResponse;
}
QrResponse qrResponse = JSON.parseObject(alipayTradePrecreateResponse.getBody(),QrResponse.class);
qrCodeResponse = qrResponse.getAlipay_trade_precreate_response();
return qrCodeResponse;
3)回調通知
Map<String, String> map = HttpRequestUtil.ParamstoMap(request);
QrServiceModel qrServiceEntity = new QrServiceModel();
qrServiceEntity.setIsreceive(false);
for (String key :map.keySet()) {
System.out.println("[ "+key + " = "+map.get(key)+" ]");
}
try {
boolean flag = AlipaySignature.rsaCheckV1(map,alipayConfig.getAlipay_public_key() ,alipayConfig.getCharset(),
alipayConfig.getSign_type());
String json = JSON.toJSONString(map);
logger.info("Alipay notify===>"+json);
if (flag) {
qrServiceEntity.setTran_starus(map.get("trade_status"));
return qrServiceEntity;
}
else {
return qrServiceEntity;
}
} catch (AlipayApiException e) {
e.printStackTrace();
return qrServiceEntity;
}
4)查詢訂單
AlipayClient alipayClient =
new DefaultAlipayClient(alipayConfig.getGatewayUrl(), alipayConfig.getApp_id(), alipayConfig.getMerchant_private_key(),
"JSON", alipayConfig.getCharset(), alipayConfig.getAlipay_public_key(), alipayConfig.getSign_type());
AlipayTradeQueryRequest aliqueryRequest = new AlipayTradeQueryRequest();
AlipayTradeQueryModel bizModel = new AlipayTradeQueryModel();
bizModel.setOutTradeNo(queryRequest.getOutTradeNo());
aliqueryRequest.setBizModel(bizModel);
/*alipayTradeQueryRequest.setBizContent("{" +
"\"out_trade_no\":\""+queryRequest.getOutTradeNo()+"\"" +
"}");*/
AlipayTradeQueryResponse response = new AlipayTradeQueryResponse();
try {
response = alipayClient.execute(aliqueryRequest);
if(response.getCode().equals("10000")){
System.out.println("業務處理成功!");
switch (response.getTradeStatus()) {
case "WAIT_BUYER_PAY":
logger.info("交易創建,等待買家付款");
break;
case "TRADE_CLOSED":
logger.info("未付款交易超時關閉,或支付完成后全額退款");
break;
case "TRADE_SUCCESS":
logger.info("交易支付成功");
break;
case "TRADE_FINISHED":
logger.info("交易結束,不可退款");
break;
default:
break;
}
}else if(response.getCode().equals("40004")){
logger.info("業務處理失敗!");
}else if(response.getCode().equals("20000")){
logger.info("系統異常!");
}
logger.info(response.getBody());
} catch (AlipayApiException e) {
e.printStackTrace();
}
QueryResponse queryResponse = JSON.parseObject(response.getBody(),QueryResponse.class);
return queryResponse.getAlipay_trade_query_response();
5)退款
AlipayClient alipayClient =
new DefaultAlipayClient(alipayConfig.getGatewayUrl(), alipayConfig.getApp_id(), alipayConfig.getMerchant_private_key(),
"JSON", alipayConfig.getCharset(), alipayConfig.getAlipay_public_key(), alipayConfig.getSign_type());
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
request.setBizContent(JSON.toJSONString(requestRequest));
AlipayTradeRefundResponse response = null;
try {
response = alipayClient.execute(request);
} catch (AlipayApiException e) {
e.printStackTrace();
}
if(response.isSuccess()){
RefundResponseSign refundResponseSign = JSON.parseObject(response.getBody(),RefundResponseSign.class);
return refundResponseSign.getAlipay_trade_refund_response();
}
return null;
三、項目結構圖

四、運行效果圖
本例子使用postman工具進行模擬測試。
1.生成二維碼效果圖:


2.退款接口效果圖:

3.退款查詢效果圖:

4.訂單查詢結果效果圖:

五、補充
本例子使用支付寶的沙箱環境展示了如何從零開始,使用螞蟻金服開放平台服務端SDK快速接入當面付產品,完成與支付寶對接的部分。測試回調可以使用花生殼工具進行一個內網穿透進行測試。在實際應用中,只要配置好appId,商戶私鑰以及支付寶公鑰即可完成本例子上述的功能。關於RSA密鑰工具可以從支付寶里下載,本例子demo里面也附帶了。
