Java对接支付宝功能(二)当面付预下单

支付宝当面付预下单流程介绍以及生成二维码核心代码的源码分析

当面付预下单

支付流程

接入指引

官方文档提供了接入的详细指引,调用流程和注意事项的介绍

这里放一张支付流程

加载alipay SDK jar包

首先,需要在项目中添加alipay-sdk-java和alipay-trade-sdk这两个包

将本地jar包通过maven发布到服务器上

为了读取在“/src/main/webapp/WEB-INF/lib”路径下的jar包,在pom文件中添加maven插件的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<compilerArguments>
<extdirs>${project.basedir}/src/main/webapp/WEB-INF/lib</extdirs>
</compilerArguments>
</configuration>
</plugin>
</plugins>

支付宝生成二维码核心代码

修改自com.alipay.demo.trade.Main支付宝官方demo

1. 设置支付相关参数

外部订单号,订单标题,总金额,不可打折金额,卖家支付宝账号ID,订单描述,商户操作员编号,商户门店编号,业务扩展参数,支付超时,商品明细列表等参数

1
outTradeNo, subject, totalAmount, undiscountableAmount, sellerId, body, operatorId, storeId, extendParams, timeoutExpress, goodsDetailList 

2. 创建扫码支付请求builder,将上述参数通过调用链进行设置

​ 这里需要注意notifyUrl字段,支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置

1
2
3
AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder().setXXX(aaa).setYYY(bbb)
.setNotifyUrl(PropertiesUtil.getProperty("alipay.callback.url"))
// alipay.callback.url=希望回调通知的地址

3. 初始化tradeService

从配置文件读取支付宝网关名,appId,商户私钥,格式(json),字符集(utf-8),支付宝公钥,签名类型等信息

这里用到了com.alipay.demo.trade包中的Configs和AlipayTradeServiceImpl来生成tradeService

1
2
3
4
5
6
7
8
9
10
11
12
private AlipayTradeServiceImpl init_tradeService() {
/** 一定要在创建AlipayTradeService之前调用Configs.init()设置默认参数
* Configs会读取classpath下的zfbinfo.properties文件配置信息,如果找不到该文件则确认该文件是 * 否在classpath目录
*/
Configs.init("alipayinfo.properties");

/** 使用Configs提供的默认参数
* AlipayTradeService可以使用单例或者为静态成员对象,不需要反复new
*/
tradeService = new AlipayTradeServiceImpl.ClientBuilder().build();
return tradeService;
}

4. 当面付预下单

调用预下单方法,传入之前生成的builder对象,tradePrecreate内部会调用AlipayClient的execute方法,进行远程调用,返回一个response对象

1
AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder); 

5.判断下单是否成功

5.1 预下单成功,生成二维码到指定路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private void trade_precreate_success(AlipayF2FPrecreateResult result, String path) {
// 简单打印应答
AlipayTradePrecreateResponse response = result.getResponse();
dumpResponse(response);
// 本地生成二维码存放文件夹
File folder = new File(path);
if (!folder.exists()) {
folder.setWritable(true);
folder.mkdirs();
}
/*
生成二维码流程
1. 根据外部订单号(outTradeNo)生成二维码存放路径(qrPath)
2. 生成二维码到qrPath
*/
String qrPath = String.format(path + "/qr-%s.png", response.getOutTradeNo());
String qrFileName = String.format("qr-%s.png", response.getOutTradeNo());

// 生成二维码图片到本地指定路径
File imageFile = ZxingUtils.getQRCodeImge(response.getQrCode(), 256, qrPath);
try {
// 将本地路径的二维码图片上传到ftp服务器
FTPUtil.uploadFile(Lists.newArrayList(imageFile));
} catch (IOException e) {
logger.error("上传二维码异常", e);
}
logger.info("qrPath:" + qrPath);
// 生成二维码的ftp Url
String qrUrl = PropertiesUtil.getProperty("ftp.server.http.prefix") + imageFile.getName();
resultMap.put("qrUrl", qrUrl);
}

流程总结整理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
// 1. 设置支付相关参数,具体可以参考demo中的说明
outTradeNo, subject, totalAmount, undiscountableAmount, sellerId, body, operatorId, storeId, extendParams, timeoutExpress, goodsDetailList

// 2. 创建扫码支付请求builder,设置请求参数
AlipayTradePrecreateRequestBuilder builder = new AlipayTradePrecreateRequestBuilder()
.setSubject(subject).setTotalAmount(totalAmount).setOutTradeNo(outTradeNo) .setUndiscountableAmount(undiscountableAmount).setSellerId(sellerId).setBody(body)
.setOperatorId(operatorId).setStoreId(storeId).setExtendParams(extendParams)
.setTimeoutExpress(timeoutExpress)
.setNotifyUrl(PropertiesUtil.getProperty("alipay.callback.url"))//支付宝服务器主动通知商户服务器里指定的页面http路径,根据需要设置
.setGoodsDetailList(goodsDetailList);

// 3. 初始化tradeService
tradeService = init_tradeService();

// 4. 当面付预下单
AlipayF2FPrecreateResult result = tradeService.tradePrecreate(builder);

// 5. 根据下单返回结果进行后续处理
switch (result.getTradeStatus()) {

case SUCCESS:
logger.info("支付宝预下单成功: )");

// 5.1 预下单成功,生成二维码到指定路径
trade_precreate_success(result, path);
return ServerResponse.createBySuccess(resultMap);

case FAILED:
logger.error("支付宝预下单失败!!!");
return ServerResponse.createByErrorMessage("支付宝预下单失败!!!");

case UNKNOWN:
logger.error("系统异常,预下单状态未知!!!");
return ServerResponse.createByErrorMessage("系统异常,预下单状态未知!!!");

default:
logger.error("不支持的交易状态,交易返回异常!!!");
return ServerResponse.createByErrorMessage("不支持的交易状态,交易返回异常!!!");
}
}