支付宝沙箱支付实战:从零到一构建Spring Boot支付服务

📅2026/7/14 12:52:22 👁️次浏览
支付宝沙箱支付实战:从零到一构建Spring Boot支付服务
1. 支付宝沙箱环境准备第一次接触支付宝支付的开发者可能会被繁琐的文档和配置吓到但沙箱环境就像是一个安全的游乐场让你可以尽情测试支付功能而不必担心真实资金流动。我刚开始对接时也踩了不少坑这里把最关键的几个配置点梳理出来。首先需要准备三个核心参数应用公钥、应用私钥和支付宝网关。这些在沙箱环境中都能免费获取。打开支付宝开放平台官网用个人账号登录后在控制台找到沙箱选项。这里你会看到系统自动生成的APPID和应用密钥。重要提示建议使用自定义密钥而非系统默认密钥。点击设置应用公钥后会跳转到密钥生成工具下载页面。根据你的操作系统下载对应版本我用的Windows版工具解压后直接运行就能生成密钥对。# 示例密钥格式实际使用时替换为你生成的密钥 -----BEGIN PUBLIC KEY----- 你的应用公钥内容 -----END PUBLIC KEY----- -----BEGIN RSA PRIVATE KEY----- 你的应用私钥内容 -----END RSA PRIVATE KEY-----生成密钥时有个小技巧密钥长度建议选择RSA22048位这是目前最安全的加密方式。记得把生成的两组密钥分别保存到项目的安全目录中我通常会在resources下创建alipay文件夹专门存放这些敏感信息。2. Spring Boot项目基础配置新建一个Spring Boot项目时我习惯先用Spring Initializr生成基础结构。支付模块需要额外添加两个关键依赖!-- 支付宝官方SDK -- dependency groupIdcom.alipay.sdk/groupId artifactIdalipay-sdk-java/artifactId version4.38.10.ALL/version /dependency !-- 处理回调的Web支持 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency配置文件application.yml的设置很关键这里分享我的模板alipay: app-id: 你的沙箱APPID merchant-private-key: 你的应用私钥 alipay-public-key: 支付宝公钥 notify-url: http://你的域名/api/alipay/notify return-url: http://你的域名/payment/return sign-type: RSA2 charset: UTF-8 gateway-url: https://openapi-sandbox.dl.alipaydev.com/gateway.do特别注意notify-url必须是外网可访问的地址。开发时我用过内网穿透工具但稳定性很差。后来改用云服务器做测试环境效果就好多了。如果必须本地调试可以试试支付宝提供的回调测试工具。3. 支付核心代码实现3.1 订单实体设计订单表结构设计要考虑支付的必要字段这是我的基础模型Data TableName(alipay_order) public class AlipayOrder { TableId(type IdType.AUTO) private Long id; private String orderNo; // 商户订单号 private String tradeNo; // 支付宝交易号 private BigDecimal amount; private String subject; // 订单标题 private String body; // 商品描述 private Integer status; // 0-待支付 1-已支付 2-已退款 private LocalDateTime createTime; private LocalDateTime payTime; }建议订单号不要用自增ID我遇到过并发问题。现在改用时间戳随机数的生成方式public static String generateOrderNo() { DateTimeFormatter dtf DateTimeFormatter.ofPattern(yyyyMMddHHmmss); String timePart LocalDateTime.now().format(dtf); String randomPart String.valueOf(new Random().nextInt(9000) 1000); return timePart randomPart; }3.2 支付模板封装创建AlipayTemplate工具类来封装支付逻辑这是核心中的核心Component ConfigurationProperties(prefix alipay) Data public class AlipayTemplate { private String appId; private String merchantPrivateKey; private String alipayPublicKey; private String notifyUrl; private String returnUrl; private String signType; private String charset; private String gatewayUrl; public String pay(AlipayOrder order) throws AlipayApiException { // 1. 创建支付客户端 AlipayClient client new DefaultAlipayClient( gatewayUrl, appId, merchantPrivateKey, json, charset, alipayPublicKey, signType); // 2. 设置请求参数 AlipayTradePagePayRequest request new AlipayTradePagePayRequest(); request.setReturnUrl(returnUrl); request.setNotifyUrl(notifyUrl); // 3. 构造业务参数 JSONObject bizContent new JSONObject(); bizContent.put(out_trade_no, order.getOrderNo()); bizContent.put(total_amount, order.getAmount()); bizContent.put(subject, order.getSubject()); bizContent.put(body, order.getBody()); bizContent.put(product_code, FAST_INSTANT_TRADE_PAY); request.setBizContent(bizContent.toString()); // 4. 发起请求 return client.pageExecute(request).getBody(); } }踩坑提醒bizContent必须用JSON格式我最初用字符串拼接导致签名失败。另外product_code这个参数必须写对支付宝文档里容易忽略这点。4. 控制器与回调处理4.1 支付入口接口RestController RequestMapping(/payment) public class PaymentController { Autowired private AlipayTemplate alipayTemplate; PostMapping(/create) public String createOrder(RequestBody OrderDTO orderDTO) { AlipayOrder order new AlipayOrder(); // 数据转换逻辑... return alipayTemplate.pay(order); } }4.2 异步通知处理支付宝的异步通知是最容易出问题的环节这是我的处理方案PostMapping(/notify) public String notify(HttpServletRequest request) { MapString, String params convertRequestParams(request); try { // 1. 验证签名 boolean signVerified AlipaySignature.rsaCheckV1( params, alipayPublicKey, charset, signType); if(!signVerified) { return failure; } // 2. 处理业务逻辑 String tradeStatus params.get(trade_status); if(TRADE_SUCCESS.equals(tradeStatus)) { String orderNo params.get(out_trade_no); String tradeNo params.get(trade_no); // 更新订单状态... } return success; } catch (Exception e) { log.error(支付宝回调处理异常, e); return failure; } } private MapString, String convertRequestParams(HttpServletRequest request) { MapString, String params new HashMap(); MapString, String[] requestParams request.getParameterMap(); for (String name : requestParams.keySet()) { String[] values requestParams.get(name); String valueStr ; for (int i 0; i values.length; i) { valueStr (i values.length - 1) ? valueStr values[i] : valueStr values[i] ,; } params.put(name, valueStr); } return params; }重要经验异步通知必须返回success字符串否则支付宝会重试通知。我遇到过因为返回格式不对导致重复通知的情况。另外验证签名一定要做这是资金安全的第一道防线。5. 前端对接与测试技巧5.1 前端支付触发最简单的调用方式function toPay(orderId) { window.location.href /payment/create?orderId${orderId}; }更推荐的做法是通过API获取支付表单axios.post(/payment/create, {orderId: 123}) .then(response { document.body.innerHTML response.data; document.forms[0].submit(); });5.2 沙箱测试账号支付宝沙箱提供了测试用的买家账号账号abxcdb1234sandbox.com密码111111支付密码111111测试技巧金额建议用0.01元测试测试不同支付场景支付成功、支付失败、重复支付使用Fiddler或Charles抓包分析请求6. 生产环境切换当测试完成后只需要修改两处配置即可上线将gateway-url改为正式环境地址gateway-url: https://openapi.alipay.com/gateway.do替换为正式的APPID和密钥建议做好环境隔离我的做法是通过Spring Profile来区分配置# application-prod.yml alipay: app-id: 正式APPID gateway-url: https://openapi.alipay.com/gateway.do最后提醒上线前一定要申请支付宝的当面付等产品权限沙箱环境只是用于技术验证。记得查看支付宝的费率说明不同行业的结算周期和手续费可能不同。