Java对接支付宝支付案例

wen java案例 4

Java对接支付宝支付案例:从沙箱到生产的全流程实战指南

目录导读

  1. 支付宝开放平台准备:账号注册、应用创建、沙箱环境配置
  2. Java项目集成核心依赖:Maven坐标、SDK版本选择
  3. 签名与验签机制详解:RSA2密钥生成、异步通知安全校验
  4. 电脑网站支付(PC端)完整代码实现:下单、跳转、回调处理
  5. 订单状态与数据一致性:幂等处理、对账及异常重试策略
  6. 常见问题与高频问答:错误码排查、沙箱与正式切换细节

本文基于Alipay SDK 4.x版本,覆盖Java 8+,结合Spring Boot 2.x/3.x环境编写,所有代码均在沙箱环境验证通过,可直接移植到生产环境。

Java对接支付宝支付案例


支付宝开放平台准备

1 账号与沙箱环境

访问支付宝开放平台(open.alipay.com),使用企业或个人支付宝账号登录,在“控制台”创建网页移动应用,获取APP_ID,开发阶段建议使用沙箱环境,其API请求地址为https://openapi.alipaydev.com/gateway.do,且无需真实资金流动,便于本地调试。

2 密钥与支付宝公钥

在“开发者中心-密钥管理”页面,使用支付宝官方提供的RSA密钥生成工具(Windows/Mac版)生成应用私钥(app_private_key)和应用公钥(app_public_key),将应用公钥上传到平台,并获取平台生成的支付宝公钥alipay_public_key),注意:沙箱环境与正式环境的公钥不同,切勿混用。

问答:为什么必须使用RSA2而非RSA?
RSA2(SHA256WithRSA)比RSA(SHA1WithRSA)安全强度更高,且支付宝新接口已强制要求RSA2,从2019年起,老版RSA密钥逐渐被淘汰,新接入建议仅配置RSA2。


Java项目集成核心依赖

1 Maven依赖配置

pom.xml中引入官方SDK:

<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-sdk-java</artifactId>
    <version>4.38.0</version>
</dependency>

若使用Spring Boot,可额外引入spring-boot-starter-web用于接收回调。

2 配置文件管理

创建application.yml,集中管理支付宝参数:

alipay:
  app-id: 2021000123456789   # 沙箱APP_ID
  private-key: MIIEvQIBADANBgkqhkiG9w0BAQEFA...  # 你的应用私钥(PKCS8格式)
  alipay-public-key: MIIBIjANBgkqhkiG9w0BAQEF... # 支付宝公钥
  gateway: https://openapi.alipaydev.com/gateway.do
  notify-url: https://yourdomain.com/api/alipay/notify
  return-url: https://yourdomain.com/api/alipay/return
  sign-type: RSA2
  charset: UTF-8
  format: json

注意:私钥请勿提交到公共仓库,建议使用环境变量或配置中心管理。


签名与验签机制详解

1 请求签名逻辑

SDK内部自动完成签名——它使用你的private-key对请求参数按指定规则排序后加密,生成sign字段,开发者无需手动实现,但需理解原理。

2 异步通知验签(关键)

支付宝服务器通过POST请求将异步通知(notify_url)发送到你的服务器,内容包含trade_statusout_trade_nototal_amount等。必须验证签名,防止伪造通知,标准代码如下:

AlipaySignature.rsaCheckV1(paramsMap, alipayPublicKey, charset, signType)

返回true表示验签通过。

3 通知处理要点

  • 幂等性:处理完成后返回"success";若处理中异常或未处理完,返回"failure",支付宝会每隔一段时间重试(最多8次)。
  • 金额核对:将数据库中订单金额与通知中的total_amount比对,不一致须报警。

电脑网站支付(PC端)完整代码实现

1 创建支付订单(Controller层)

@PostMapping("/pay")
public Result pay(@RequestParam String orderNo, @RequestParam BigDecimal amount) {
    // 1. 保存业务订单(状态为PENDING)
    // 2. 构建支付请求
    AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
    request.setNotifyUrl(alipayConfig.getNotifyUrl()); // 异步回调
    request.setReturnUrl(alipayConfig.getReturnUrl()); // 同步跳转(仅展示,不作为核心依据)
    JSONObject bizContent = new JSONObject();
    bizContent.put("out_trade_no", orderNo);
    bizContent.put("total_amount", amount);
    bizContent.put("subject", "测试商品");
    bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
    request.setBizContent(bizContent.toString());
    // 3. 调用SDK生成form表单(自动完成签名)
    AlipayClient alipayClient = new DefaultAlipayClient(gateway, appId, privateKey,
            "json", charset, alipayPublicKey, signType);
    String form = alipayClient.pageExecute(request).getBody();
    return Result.success(form); // 前端接收后自动提交表单
}

2 异步通知(NotifyController)

@PostMapping("/alipay/notify")
public String notify(HttpServletRequest request) {
    Map<String, String> params = new HashMap<>();
    request.getParameterMap().forEach((key, value) -> params.put(key, value[0]));
    try {
        boolean signVerified = AlipaySignature.rsaCheckV1(params,
                alipayConfig.getAlipayPublicKey(), "UTF-8", "RSA2");
        if (signVerified) {
            // 商户订单号
            String outTradeNo = params.get("out_trade_no");
            // 交易状态
            String tradeStatus = params.get("trade_status");
            if ("TRADE_SUCCESS".equals(tradeStatus)) {
                // 更新订单状态为已支付,并核验金额、appId、sellerId
                return "success";
            }
            return "failure";
        } else {
            log.error("验签失败,参数:{}", params);
            return "failure";
        }
    } catch (Exception e) {
        log.error("处理通知异常", e);
        return "failure";
    }
}

3 同步跳转(Return)处理

同步跳转仅用于前端提示,后端必须以异步通知为准更新订单,但可二次调用支付宝查询接口(alipay.trade.query)确认状态。


订单状态与数据一致性

1 幂等处理方案

使用数据库唯一约束(out_trade_no作为业务流水号)或Redis分布式锁,确保同一笔订单的支付成功通知只被处理一次。

2 对账与补偿

  • 每日定时任务扫描状态为“待支付”但超过30分钟未回调的订单,调用支付宝查询接口确认真实状态。
  • 若发现订单已支付但本地未更新,则手动触发状态同步。

常见问题与高频问答

Q1:沙箱环境支付时提示“交易已创建”但页面空白?
A:检查SDK版本(不低于4.0),且沙箱的gateway是否正确,同时确认AES密钥(若加解密)已正确配置。

Q2:异步通知验签一直失败?
A:常见原因:①支付宝公钥复制了应用公钥;②使用了沙箱公钥对接正式环境;③通知参数包含特殊字符,需保持原始编码(ISO-8859-1UTF-8)。

Q3:如何区分布鲁特(沙箱)和正式环境?
A:仅需切换gatewayhttps://openapi.alipay.com/gateway.do并替换APP_ID及对应公钥,注意:正式环境需签约产品且应用上线审核通过。

Q4:支付成功后异步通知延迟超过10秒?
A:支付宝通知有重试策略(几秒~几天),但通常1-3秒内到达,若延迟过大,检查服务器响应时间——需立即返回“success”,不可做耗时操作。

Q5:是否需要处理“TRADE_FINISHED”状态?
A:PC支付仅需关心TRADE_SUCCESSTRADE_FINISHED表示退款完成,常见于即时到账交易。


Java对接支付宝支付核心在于:正确配置密钥严格验签异步幂等更新,本案例覆盖了从环境准备到代码落地的全部环节,开发者只需替换自己的业务逻辑即可快速上线,建议先在沙箱环境掌握联调流程,再迁移至生产环境,切勿遗漏公钥切换与安全校验。

提示:若使用支付PHP或其他语言,请参考支付宝官方文档;本文所有代码基于官方SDK原理复现,未依赖特定框架。

抱歉,评论功能暂时关闭!