自动续费不是玄学,是接口!——支付宝周期扣款 Java 实现详解

内容分享13小时前发布
0 0 0

💰 Java 接入支付宝周期扣款(代扣)全流程实战指南(终极完整版)

实现「自动续费」「会员周期扣款」「订阅支付」等功能的核心技术方案。
从签约 → 扣款 → 回调 → 解约 → 安全,企业级全流程实战解析。


🚀 一、功能概览

支付宝周期扣款(又称“代扣”)允许商户在用户授权后,
按照约定周期(如每月、每季、每年)自动从用户支付宝账户中扣款。

阶段 核心任务 关键接口 / 关键词
① 前期准备 创建应用、配置密钥、引入SDK APPID、RSA2、SDK
② 用户签约 引导用户授权代扣协议
alipay.user.agreement.page.sign
③ 发起扣款 根据签约号执行代扣请求
alipay.trade.pay
④ 异步通知 验签并同步订单状态 签名验证、返回
success
⑤ 解约与异常处理 用户解约 / 支付失败 / 重试
alipay.user.agreement.unsign

🔑 二、前期准备

1. 创建应用并获取 APPID

登录 支付宝开放平台,
创建应用并完成审核后,你将获得唯一的 APPID

2. 生成并配置密钥

使用支付宝提供的工具生成一对 RSA2(SHA256) 密钥。

上传 应用公钥 至开放平台 → 获取 支付宝公钥

妥善保管 应用私钥(仅服务端保存)。

3. 引入支付宝 SDK


pom.xml
中添加依赖:



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

📝 三、用户签约流程

周期扣款前,用户必须先授权(签约)。
通过 API 生成签约页面,引导用户完成授权后,获取
agreement_no



AlipayClient alipayClient = new DefaultAlipayClient(
    "https://openapi.alipay.com/gateway.do",
    APP_ID,
    APP_PRIVATE_KEY,
    "json",
    "UTF-8",
    ALIPAY_PUBLIC_KEY,
    "RSA2"
);
 
AlipayUserAgreementPageSignRequest request = new AlipayUserAgreementPageSignRequest();
request.setReturnUrl("https://your-domain.com/returnUrl");
request.setNotifyUrl("https://your-domain.com/signNotify");
 
request.setBizContent("{" +
    ""product_code":"GENERAL_WITHHOLDING_P1"," +
    ""personal_product_code":"CYCLE_PAY_AUTH_P1"," +
    ""sign_scene":"INDUSTRY|DEFAULT"," +
    ""external_agreement_no":"AGREE_001_20251031"," +
    ""promoter_user_id":"2088xxxx"" +
"}");
 
String signPageUrl = alipayClient.pageExecute(request).getBody();

💡 用户访问
signPageUrl
并完成授权后,支付宝会异步通知你的
signNotify
地址,
你需要从通知参数中解析出
agreement_no
(签约号)
,这是后续扣款的关键凭证。


💳 四、发起周期扣款请求

当用户签约成功后,即可在到期时间自动发起扣款。



AlipayTradePayRequest request = new AlipayTradePayRequest();
request.setNotifyUrl("https://your-domain.com/payNotify");
 
request.setBizContent("{" +
    ""out_trade_no": "ORDER_20251031_001"," +
    ""total_amount": 9.90," +
    ""subject": "会员续费"," +
    ""product_code": "GENERAL_WITHHOLDING"," +
    ""auth_confirm_mode": "COMPLETE"," +
    ""agreement_no": "" + agreementNo + """ +
"}");
 
AlipayTradePayResponse response = alipayClient.execute(request);
 
if (response.isSuccess()) {
    System.out.println("扣款成功!");
} else {
    System.out.println("扣款失败:" + response.getSubMsg());
}

⚙️ 注意

out_trade_no
必须全局唯一,用于幂等校验;

agreement_no
必须是有效签约号,否则请求会被拒绝。


📢 五、异步通知处理

无论是签约还是支付,支付宝都会向你指定的
notify_url
发送异步通知。
必须进行签名验证,并返回
"success"



@PostMapping("/payNotify")
public String handlePayNotify(HttpServletRequest request) {
    Map<String, String> params = new HashMap<>();
    request.getParameterMap().forEach((k, v) -> params.put(k, v[0]));
 
    try {
        boolean signVerified = AlipaySignature.rsaCheckV1(
            params, ALIPAY_PUBLIC_KEY, "UTF-8", "RSA2");
 
        if (signVerified && "TRADE_SUCCESS".equals(params.get("trade_status"))) {
            String outTradeNo = params.get("out_trade_no");
            // 幂等性处理:防止重复回调
            // TODO: 更新订单状态、记录日志
            return "success";
        }
    } catch (AlipayApiException e) {
        e.printStackTrace();
    }
 
    return "failure";
}

⚠️ 返回 “success” 才表示处理完成,否则支付宝会重试推送。
建议记录所有通知日志以便追踪。


🧩 六、异常与解约机制

支付宝周期扣款必须支持「解约」与「支付失败重试」。

1. 用户主动解约

用户可在支付宝端取消授权,你也可调用解约接口:



AlipayUserAgreementUnsignRequest request = new AlipayUserAgreementUnsignRequest();
request.setBizContent("{" +
    ""agreement_no":"" + agreementNo + """ +
"}");
AlipayUserAgreementUnsignResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
    System.out.println("解约成功");
}

2. 常见扣款失败场景与解决方案

失败原因 建议措施
用户账户余额不足 提示用户充值后重试
协议已失效或解约 引导用户重新签约
超出支付额度 与支付宝申请提高额度
网络异常 增加重试队列与幂等机制

⏰ 七、定期任务与重试策略

对于订阅或会员业务,可结合定时任务自动执行代扣。



@Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行
public void autoRenew() {
    List<UserAgreement> expiringList = agreementService.findExpiring();
    for (UserAgreement a : expiringList) {
        try {
            alipayService.autoCharge(a);
        } catch (Exception e) {
            retryQueue.push(a);
        }
    }
}

✅ 重试策略建议:

每笔订单最多重试 3 次

使用延时队列 / 消息队列(如 RabbitMQ、RocketMQ)

按交易状态幂等更新


🧠 八、沙箱环境与联调建议

支付宝提供了 沙箱环境 用于测试签约、扣款与回调。
访问 https://sandbox.alipaydev.com/ 即可。

测试流程:

创建沙箱应用 → 获取测试 APPID

使用沙箱钱包账号登录签约页

模拟签约成功 → 获得测试
agreement_no

触发扣款请求 → 查看回调日志

确认验签、业务状态、重试逻辑均正确


🛡️ 九、安全与合规要点

风险点 建议
密钥安全 私钥仅存储在服务端;禁用明文配置
通信安全 强制启用 HTTPS
签名验证 所有异步回调必须验签
幂等机制 基于
out_trade_no
防重复执行
日志追踪 全链路记录签约、支付、通知

💡 建议对所有支付请求与回调加入链路 ID,方便问题排查。


📘 十、完整流程总结

阶段 操作 结果
准备阶段 配置密钥、SDK、回调地址 获取 APPID、API 可用
签约阶段 用户授权代扣协议 获取
agreement_no
扣款阶段 定时/手动发起代扣 支付完成
通知阶段 验签并更新状态 状态同步一致
异常阶段 解约、失败重试、日志 系统稳健可靠

🎯 十一、最佳实践建议

签约和扣款分离 —— 避免在签约回调中立即发起支付。

日志与幂等并行控制 —— 保证交易结果一致。

使用沙箱反复测试 —— 尤其关注回调重复推送场景。

安全优先 —— 任何涉及密钥的逻辑都应脱敏、加密。

关注官方文档更新 —— 支付宝开放平台接口可能有版本调整。


🏁 十二、一句话总结

周期扣款的本质是「一次签约,多次自动支付」——
用户授权的是信任,系统要做到的是安全、稳定、幂等


© 版权声明

相关文章

暂无评论

none
暂无评论...