支付宝支付联调
本篇文章主要是针对支付宝官网的接口文档,进行说明,虽说文档很详细,也也有图例分析,也有代码示例,但这里还是按照MVC架构分析一下
流程如下
- 预支付
- 获取商品信息
- 获取二维码图片
- 用户扫码,确认支付
- 商家查看支付详情
- 库存充足,缓存没问题的情况下,直接获取支付结果
- 用户支付成功,交易成功
- 用户支付失败,交易取消
- 库存不足的情况下
- 有缓存限制,预先锁定商品
- 用户支付成功,交易成功
- 用户支付失败,交易取消
- 未做锁定商品
- 直接取消交易(用户支付成功,退款;支付失败取消交易)
- 有缓存限制,预先锁定商品
- 库存充足,缓存没问题的情况下,直接获取支付结果
- 退款
- 银行卡支付
- 其他渠道支付
- 部分退款(幂等性)
- 全额退款
- 对账
- 账单打印
其实,以上也就是常规的一些交易流程了,但是需要针对具体的业务进行具体的分析,例如高并发的缓存以及消息队列使用。以及常规情况下的网络延迟等问题都是需要考虑的,若仅仅作为测试使用,可以不需要考虑
整体流程
前置工作
建议用户准备自己的沙箱环境,进行测试
沙箱环境流程
沙箱App准备
因为使用的是沙箱环境,所以只能使用沙箱钱包进行扫码支付
有可能出现的问题:如果不用沙箱钱包支付,有可能导致二维码超时
配置类(静态)
public class AlipayConfig {
// 商户appid
public static String APPID = "";
// 私钥 pkcs8格式的
public static String RSA_PRIVATE_KEY = "";
// 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String notify_url = "http://https://openapi.alipaydev.com/gateway.do/alipay.trade.wap.pay-JAVA-UTF-8/notify_url.jsp";
// 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
public static String return_url = "http://https://openapi.alipaydev.com/gateway.do/alipay.trade.wap.pay-JAVA-UTF-8/return_url.jsp";
// 请求网关地址
public static String URL = "";
// 编码
public static String CHARSET = "UTF-8";
// 返回格式
public static String FORMAT = "json";
// 支付宝公钥
public static String ALIPAY_PUBLIC_KEY = "";
// 日志记录目录
public static String log_path = "/log";
// RSA2
public static String SIGNTYPE = "RSA2";
}
预支付
代码(AlipayTradePrecreateRequest)
@PostMapping("/payPer")
public void payPer(String WIDout_trade_no, String WIDsubject, String WIDtotal_amount, String WIDbody, HttpServletResponse response) throws AlipayApiException {
AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
AlipayTradePrecreateRequest alipay_request=new AlipayTradePrecreateRequest ();
// 封装请求支付信息
alipay_request . setBizContent ( "{" +
"\"out_trade_no\":\""+WIDout_trade_no+"\"," + //商户订单号
"\"total_amount\":\""+WIDtotal_amount+"\"," +
"\"subject\":\""+WIDsubject+"\"," +
"\"store_id\":\""+WIDbody+"\"," +
"\"timeout_express\":\"9000s\"}" );
AlipayTradePrecreateResponse response1 = client.execute (alipay_request);
List list= Arrays.asList(response1.getBody().split("\"qr_code\":"));
String[] list1= list.get(1).toString().split("},\"sign\"");
String a=list1[0].replace("\\","").replace("\"","");
QrConfig config = new QrConfig(180, 180);
// 设置边距,既二维码和背景之间的边距
config.setMargin(3);
// 高纠错级别
config.setErrorCorrection(ErrorCorrectionLevel.H);
//二维码内容
BufferedImage bufferedImage = QrCodeUtil.generate(
a,
config
);
try {
// 以JPEG格式向客户端发送
ServletOutputStream os = response.getOutputStream();
ImageIO.write(bufferedImage, "PNG", os);
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(WIDout_trade_no);
}
以上代码包含了一个二维码转换的工具类“Hutool”,工具类支持二维码定义中心logo
同时这里,并没有去解析JSON格式,仅仅作为测试使用,直接获取字符串分割
入参
- out_trade_no:商户订单号,需要保证商家系统不重复。
- total_amount:订单金额。
- subject:商品的标题/交易标题/订单标题/订单关键字等。不可使用特殊字符,如 /,=,& 等。
- store_id:商户门店编号。
- timeout_express:交易超时时间。
出参
- qr_code:订单二维码(有效时间 2 小时)以字符串的格式返回,开发者需要自己使用工具根据内容生成二维码图片。
查询交易
代码(AlipayTradeQueryRequest)
@GetMapping("/queryPay")
public void queryPay(String WIDout_trade_no) throws AlipayApiException {
AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);
AlipayTradeQueryRequest alipay_request = new AlipayTradeQueryRequest();
alipay_request.setBizContent("{" +
"\"out_trade_no\":\"2020123111227522\"}"); //设置业务参数
AlipayTradeQueryResponse response = client.execute(alipay_request);//通过alipayClient调用API,获得对应的response类
System.out.print(response.getBody());
}
这里的做法,建议前端轮询请求,当然,也可以放入消息队列,然后后台做监听处理,根据具体业务来看吧
不是高并发的情况,建议轮询,以做到用户体验最好
入参
- out_trade_no:支付时传入的商户订单号,与 trade_no 必填一个
- trade_no:支付时返回的支付宝交易号,与out_trade_no 必填一个。
返回
- code=10000,支付成功,流程结束
- code=10003,等待用户付款
- code=20000,网络超时,系统异常(根据需求,撤销交易或者继续等待)
撤销交易
代码(AlipayTradeCancelRequest )
@GetMapping("/refundPay")
public void refundPay(String WIDout_trade_no) throws AlipayApiException {
AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);
AlipayTradeCancelRequest alipay_request = new AlipayTradeCancelRequest ();
alipay_request.setBizContent("{" +
"\"out_trade_no\":\"20201231122418603\"}"); //设置业务参数
AlipayTradeCancelResponse response = client.execute(alipay_request);//通过alipayClient调用API,获得对应的response类
System.out.print(response.getBody());
}
说明
- 如果此订单用户支付失败,支付宝将关闭此订单。
- 如果此订单用户支付成功,支付宝将退还订单资金给用户。
- 仅发生支付系统超时或者支付结果未知时可调用本接口撤销交易,其他正常支付的单如需实现相同功能请调用alipay.trade.refund(统一收单交易退款接口)。
入参
- out_trade_no:支付时传入的商户订单号,与 trade_no 必填一个。
- trade_no:支付时返回的支付宝交易号,与out_trade_no 必填一个。
出参
- retry_flag:是否需要重试,Y/N。
- action:本次撤销触发的交易动作。
- close:关闭交易,无退款 。
- refund:产生了退款。
退款
流程图
代码(AlipayTradeRefundRequest)
AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);
AlipayTradeRefundRequest alipay_request = new AlipayTradeRefundRequest();
alipay_request.setBizContent("{" +
"\"out_trade_no\":\"20201231122418603\"," +
"\"out_request_no\":\"1000002\"," +
"\"refund_amount\":\"5\"}"); //设置业务参数
AlipayTradeRefundResponse response = client.execute(alipay_request);//通过alipayClient调用API,获得对应的response类
System.out.print(response.getBody());
}
说明
- 退款的途径按照支付途径原路返回。
- 支付渠道为花呗、余额等退款即时到账。
- 银行卡的退款时间以银行退款时间为准,一般情况下 2 小时内可到账。
- 开发者也可以在 商家中心 中退款。
- 退款是否成功可以根据同步响应的 fund_change 参数来判断,返回值为 Y 则表示退款成功。
- 退款接口会根据外部请求号 out_request_no 幂等返回,因此同一笔交易需要多次部分退款时,必须使用不同的 out_request_no。
入参
- out_trade_no:支付时传入的商户订单号,与trade_no必填一个
- trade_no:支付时返回的支付宝交易号,与out_trade_no必填一个
- out_request_no:本次退款请求流水号,部分退款时必传
- refund_amount:本次退款金额。
出参
- refund_fee:该笔交易已退款的总金额。
退款到银行卡
由于沙箱不支持银行卡操作,所以未进行测试
对账
流程图
代码
@GetMapping("/dataDataservice")
public void dataDataservice() throws AlipayApiException {
AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);
AlipayDataDataserviceBillDownloadurlQueryRequest alipay_request = new AlipayDataDataserviceBillDownloadurlQueryRequest ();
alipay_request.setBizContent("{" +
"\"bill_type\":\"trade\"," +
"\"bill_date\":\"2016-04-05\"}"); //设置业务参数
AlipayDataDataserviceBillDownloadurlQueryResponse response = client.execute(alipay_request);//通过alipayClient调用API,获得对应的response类
System.out.print(response.getBody());
}
入参
- bill_type:固定传入 trade。
- bill_date:需要下载的账单日期,最晚是当期日期的前一天。
出参
- bill_download_url:账单文件下载地址,有效时长:30 秒。
说明
下载账单,根据各自喜欢工具类可进行封装,这里不在提供,或者可以直接参考支付宝官网
以上就是支付宝支付接口对接了,后续会继续分享支付宝登录、QQ登录等案例