easy支付官方文档:https://opendocs.alipay.com/open/009ys9
通用版文档:https://opendocs.alipay.com/open/02np94
一、 沙箱支付
1.1什么是沙箱支付
支付宝沙箱支付(Alipay Sandbox Payment)是支付宝提供的一个模拟支付环境,用于开发和测试支付宝支付功能的开发者工具。在真实的支付宝环境中进行支付开发和测试可能涉及真实资金和真实用户账户,而沙箱环境则提供了一个安全、隔离的环境,使开发者能够模拟支付过程,测试支付功能,而不会使用真实资金。
使用支付宝沙箱支付环境,开发者可以模拟各种支付场景,包括交易创建、支付请求、支付回调等,以验证支付功能的正确性和稳定性。沙箱环境中的所有交易和数据都是虚拟的,不会产生真实的交易或资金流动。
支付宝沙箱支付提供了开发者工具和接口,使开发者能够在模拟环境下进行支付流程的调试和测试。开发者可以在沙箱环境中创建测试账户、配置模拟的交易金额和状态,使用沙箱环境中的接口进行支付操作,并模拟支付回调接口接收支付结果。
通过使用支付宝沙箱支付,开发者可以更安全、更有效地进行支付功能的开发和测试,避免了对真实环境的影响和风险。一旦支付功能在沙箱环境中验证通过,开发者可以将其部署到真实的支付宝生产环境中,与真实用户进行交互和支付。
1.2配置沙箱账号
打开沙箱地址:登录 - 支付宝
需要获取:AppId、支付宝网关地址、应用私钥、支付宝公钥
1.3配置秘钥(自定义密钥)
下载安装支付宝开放平台开发助手:小程序文档 - 支付宝文档中心
安装完成之后,点击“支付宝开放平台开发助手”开始生成密钥。
选择密钥方式,选择RSA2
方式,最后点击生成密钥即可生成得到私钥和公钥。
1.4生成支付宝公钥
根据支付宝开放平台开发助手生成的应用公钥,生成支付宝公钥:
找到支付宝开放平台的沙箱应用一栏,选择“开发信息”接口加签方式中的自定义密钥方式,点击设置并查看按钮:
生成支付宝公钥,如下:
二、开发接入
2.1配置依赖
<!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-easysdk -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.35.79.ALL</version>
</dependency>
2.2配置AlipayConfig
开发文档:小程序文档 - 支付宝文档中心
第一步:修改沙箱支付配置参数:
alipay:
appId: xxx
appPrivateKey: xxx
alipayPublicKey: xxx
notifyUrl: http://xxx/alipay/notify
第二步:写配置类
@Component
@Data
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {
private String appId;
private String appPrivateKey;
private String alipayPublicKey;
private String notifyUrl;
}
2.3修改订单生成代码
@RestController
@RequestMapping("/alipay")
public class AliPayController {
// 支付宝沙箱网关地址
private static final String GATEWAY_URL = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";
private static final String FORMAT = "JSON";
private static final String CHARSET = "UTF-8";
//签名方式
private static final String SIGN_TYPE = "RSA2";
@Resource
private AliPayConfig aliPayConfig;
@Resource
private OrdersServiceImpl ordersService;
@GetMapping("/pay") // /alipay/pay?orderNo=xxx
public void pay(String orderNo, HttpServletResponse httpResponse) throws Exception {
// 查询订单信息
Orders orders = ordersService.selectByOrderNo(orderNo);
if (orders == null) {
return;
}
// 1. 创建Client,通用SDK提供的Client,负责调用支付宝的API
AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, aliPayConfig.getAppId(),
aliPayConfig.getAppPrivateKey(), FORMAT, CHARSET, aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);
// 2. 创建 Request并设置Request参数
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); // 发送请求的 Request类
request.setNotifyUrl(aliPayConfig.getNotifyUrl());
JSONObject bizContent = new JSONObject();
bizContent.set("out_trade_no", orders.getOrderNo()); // 我们自己生成的订单编号
bizContent.set("total_amount", orders.getTotal()); // 订单的总金额
bizContent.set("subject", orders.getGoodsName()); // 支付的名称
bizContent.set("product_code", "FAST_INSTANT_TRADE_PAY"); // 固定配置
request.setBizContent(bizContent.toString());
request.setReturnUrl("http://localhost:5173/orders"); // 支付完成后自动跳转到本地页面的路径
// 执行请求,拿到响应的结果,返回给浏览器
String form = "";
try {
form = alipayClient.pageExecute(request).getBody(); // 调用SDK生成表单
} catch (AlipayApiException e) {
e.printStackTrace();
}
httpResponse.setContentType("text/html;charset=" + CHARSET);
httpResponse.getWriter().write(form);// 直接将完整的表单html输出到页面
httpResponse.getWriter().flush();
httpResponse.getWriter().close();
}
@PostMapping("/notify") // 注意这里必须是POST接口
public void payNotify(HttpServletRequest request) throws Exception {
if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
System.out.println("=========支付宝异步回调========");
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
}
String sign = params.get("sign");
String content = AlipaySignature.getSignCheckContentV1(params);
boolean checkSignature = AlipaySignature.rsa256CheckContent(content, sign, aliPayConfig.getAlipayPublicKey(), "UTF-8"); // 验证签名
// 支付宝验签
if (checkSignature) {
// 验签通过
System.out.println("交易名称: " + params.get("subject"));
System.out.println("交易状态: " + params.get("trade_status"));
System.out.println("支付宝交易凭证号: " + params.get("trade_no"));
System.out.println("商户订单号: " + params.get("out_trade_no"));
System.out.println("交易金额: " + params.get("total_amount"));
System.out.println("买家在支付宝唯一id: " + params.get("buyer_id"));
System.out.println("买家付款时间: " + params.get("gmt_payment"));
System.out.println("买家付款金额: " + params.get("buyer_pay_amount"));
String tradeNo = params.get("out_trade_no");
String gmtPayment = params.get("gmt_payment");
String alipayTradeNo = params.get("trade_no");
// 更新订单状态为已支付,设置支付信息
Orders orders = ordersService.selectByOrderNo(tradeNo);
orders.setStatus("已支付");
orders.setPayTime(gmtPayment);
orders.setPayNo(alipayTradeNo);
ordersService.updateById(orders);
}
}
}
}
2.4退款功能
@GetMapping("/return")
public Result returnPay(AliPay aliPay) throws AlipayApiException {
// 7天无理由退款
String now = DateUtil.now();
Orders orders = ordersMapper.getByNo(aliPay.getTraceNo());
if (orders != null) {
// hutool工具类,判断时间间隔
long between = DateUtil.between(DateUtil.parseDateTime(orders.getPaymentTime()), DateUtil.parseDateTime(now), DateUnit.DAY);
if (between > 7) {
return Result.error("-1", "该订单已超过7天,不支持退款");
}
}
// 1. 创建Client,通用SDK提供的Client,负责调用支付宝的API
AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL,
aliPayConfig.getAppId(), aliPayConfig.getAppPrivateKey(), FORMAT, CHARSET,
aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);
// 2. 创建 Request,设置参数
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
JSONObject bizContent = new JSONObject();
bizContent.set("trade_no", aliPay.getAlipayTraceNo()); // 支付宝回调的订单流水号
bizContent.set("refund_amount", aliPay.getTotalAmount()); // 订单的总金额
bizContent.set("out_request_no", aliPay.getTraceNo()); // 我的订单编号
// 返回参数选项,按需传入
//JSONArray queryOptions = new JSONArray();
//queryOptions.add("refund_detail_item_list");
//bizContent.put("query_options", queryOptions);
request.setBizContent(bizContent.toString());
// 3. 执行请求
AlipayTradeRefundResponse response = alipayClient.execute(request);
if (response.isSuccess()) { // 退款成功,isSuccess 为true
System.out.println("调用成功");
// 4. 更新数据库状态
ordersMapper.updatePayState(aliPay.getTraceNo(), "已退款", now);
return Result.success();
} else { // 退款失败,isSuccess 为false
System.out.println(response.getBody());
return Result.error(response.getCode(), response.getBody());
}
}
2.5 真实应用支付配置
a. 修改支付成功拼接的url(无dev)
b.修改appid,修改成,真实应用的appid即可
https://opendocs.alipay.com/open/03k9zr?pathHash=38327ac8
https://opensupport.alipay.com/support/FAQ/f3ab72f1-af25-4f88-8ff5-fbb66be1aa11