SPRING 5 分钟 4,852 字

Spring Boot 集成支付宝沙箱支付

0阅读

关键词:Spring Boot、支付宝、沙箱、PC 网页支付、Java17、Maven
源码仓库:https://github.com/yourname/spring-alipay-demo(文中附目录结构)


一、为什么选择“沙箱”先跑通?

  1. 0 成本:支付宝提供永久免费的沙箱环境,无需企业认证。
  2. 全链路:从下单 → 支付 → 异步通知 → 同步回调,和线上流程 100% 一致。
  3. 好调试:沙箱支持“买家余额”固定 100,000,可随意“付款”测试。

二、5 步完成接入

步骤 内容 预计耗时
① 注册沙箱账号,获取 3 秘钥 2 min
② 新建 Spring Boot 项目,引入 SDK 2 min
③ 写配置文件 & 启动类 2 min
④ 3 个接口:下单 / 同步回调 / 异步通知 3 min
⑤ 启动 & 体验支付 1 min

三、详细实战

3.1 沙箱账号 & 密钥

登录 支付宝开放平台 → 开发者中心 → 沙箱环境
记录下面 3 个值,后面 application.yml 会用到:

  • APP_ID:9021000132681525(举例)
  • 商户私钥:用官方工具生成,保存为 appPrivateKey.txt
  • 支付宝公钥:平台自动给出,复制即可

3.2 项目骨架

使用 Spring Initializr 勾选 Spring Web + Java17,得到:

spring-alipay
├─ src
│  ├─ main
│  │  ├─ java
│  │  │  └─ com.example.alipay
│  │  │     ├─ SpringAlipayApplication.java
│  │  │     ├─ controller
│  │  │     ├─ service
│  │  │     └─ config
│  │  └─ resources
│  │     └─ application.yml
└─ pom.xml

3.3 Maven 依赖(完整 pom)

<project ...>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.4</version>
    </parent>

    <groupId>com.example</groupId>
    <artifactId>spring-alipay</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>17</java.version>
    </properties>

    <dependencies>
        <!-- web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 支付宝官方 SDK(推荐组合) -->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.22.110.ALL</version>
        </dependency>
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-easysdk</artifactId>
            <version>2.2.0</version>
        </dependency>
    </dependencies>
</project>

3.4 application.yml

alipay:
  appId: 9021000132681525
  appPrivateKey: MIIEvQIBADANB...      # 一行私钥,去掉头尾和换行
  alipayPublicKey: MIIBIjANBgkqhk...  # 一行公钥
  notifyUrl: http://localhost:8080/notify
  returnUrl: http://localhost:8080/callback
  gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do
  charset: utf-8
  signType: RSA2

3.5 启动类

@SpringBootApplication
public class SpringAlipayApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringAlipayApplication.class, args);
    }
}

3.6 Service 层

@Service
public class AlipayService {

    @Value("${alipay.appId}") private String appId;
    @Value("${alipay.appPrivateKey}") private String appPrivateKey;
    @Value("${alipay.alipayPublicKey}") private String alipayPublicKey;
    @Value("${alipay.notifyUrl}") private String notifyUrl;
    @Value("${alipay.returnUrl}") private String returnUrl;
    @Value("${alipay.gatewayUrl}") private String gatewayUrl;
    @Value("${alipay.charset}") private String charset;
    @Value("${alipay.signType}") private String signType;

    public String pay(String outTradeNo, String subject, String totalAmount) throws AlipayApiException {
        AlipayClient client = new DefaultAlipayClient(
                gatewayUrl, appId, appPrivateKey, "json", charset, alipayPublicKey, signType);

        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setReturnUrl(returnUrl);
        request.setNotifyUrl(notifyUrl);
        request.setBizContent("{" +
                "\"out_trade_no\":\"" + outTradeNo + "\"," +
                "\"total_amount\":\"" + totalAmount + "\"," +
                "\"subject\":\"" + subject + "\"," +
                "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
        return client.pageExecute(request).getBody(); // 返回自动提交的 form 表单
    }
}

3.7 Controller 层

① 下单接口(GET)

@RestController
@RequiredArgsConstructor
public class AlipayController {
    private final AlipayService alipayService;

    @GetMapping("/pay")
    public void pay(@RequestParam String outTradeNo,
                    @RequestParam String subject,
                    @RequestParam String totalAmount,
                    HttpServletResponse response) throws Exception {
        String form = alipayService.pay(outTradeNo, subject, totalAmount);
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().write(form);
        response.getWriter().flush();
    }
}

浏览器访问:
http://localhost:8080/pay?outTradeNo=202601031200&subject=VIP1个月&totalAmount=0.01

② 同步回调(return_url)

@RestController
public class CallbackController {
    @GetMapping("/callback")
    public String callback() {
        return "支付成功(同步)";
    }
}

③ 异步通知(notify_url)

@RestController
public class NotifyController {

    @PostMapping("/notify")
    public String notify(HttpServletRequest request) throws Exception {
        Map<String, String> params = new HashMap<>();
        request.getParameterMap().forEach((k, v) -> params.put(k, v[0]));

        // 使用 EasySDK 验签
        if (Factory.Payment.Common().verifyNotify(params)) {
            String tradeStatus = params.get("trade_status");
            if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
                // TODO: 更新订单、发货、加积分...
                System.out.println("---- 异步通知 ----");
                System.out.println("商户订单号:" + params.get("out_trade_no"));
                System.out.println("支付宝交易号:" + params.get("trade_no"));
                System.out.println("交易金额:" + params.get("total_amount"));
            }
            return "success"; // 必须返回 success,否则支付宝会重发 25h
        }
        return "fail";
    }
}

四、启动 & 测试

  1. 启动 Spring Boot,控制台出现 Started SpringAlipayApplication。
  2. 浏览器访问第 3.7 节的 /pay 链接,页面自动跳转到支付宝沙箱收银台。
  3. 用沙箱买家账号(平台给出)登录 → 输入支付密码 → 支付成功。
  4. 观察 IDEA 控制台:
    • 同步回调:支付成功(同步)
    • 异步通知:打印订单号、金额等信息。

五、常见坑汇总

现象 原因 解决方案
验签失败 公钥 / 私钥弄反;换行符未去掉 复制成一行,私钥=你自己的,公钥=支付宝的
notify 不进来 内网穿透失效;返回不是 success 用 https://natapp.cn 或 https://localhost.run,确保外网能 POST
沙箱提示“参数异常” 金额格式带了人民币符号 totalAmount 传纯数字,如 0.01
同步回调没数据 return_url 只负责展示,业务写 notify ✅ 正确

六、拓展:如何切到线上?

  1. 替换 gatewayUrl 为 https://openapi.alipay.com/gateway.do
  2. 把 appId、appPrivateKey、alipayPublicKey 换成线上值。
  3. notifyUrl、returnUrl 换成 https 可外网访问的域名。
  4. 上线前务必打开“签名验证”和“AES 密钥”增强安全。