1. 概述
Stripe 是一个云服务,让企业和个人能够通过互联网接收支付。它同时提供客户端库(JavaScript 和原生移动端)和服务器端库(Java、Ruby、Node.js 等)。
Stripe 通过抽象层降低了支付处理的复杂性。我们不需要直接处理信用卡细节——而是使用代表扣款授权的令牌(token)。
本教程将创建一个 Spring Boot 示例项目,允许用户输入信用卡信息,然后通过 Stripe Java API 对指定金额进行扣款。
2. 依赖配置
要在项目中使用 Stripe Java API,需在 pom.xml 中添加依赖:
<dependency>
<groupId>com.stripe</groupId>
<artifactId>stripe-java</artifactId>
<version>4.2.0</version>
</dependency>
最新版本可在 Maven 中央仓库 查找。
示例项目使用 spring-boot-starter-parent:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.2</version>
</parent>
同时引入 Lombok 减少样板代码,Thymeleaf 作为模板引擎:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
⚠️ NetBeans 用户注意:需显式指定 Lombok 1.16.16 版本,Spring Boot 1.5.2 自带的版本会导致 NetBeans 报错。
3. API 密钥
与 Stripe 通信执行扣款前,需**注册 Stripe 账户 并获取密钥对**。
登录后访问 Stripe 仪表盘,左侧菜单选择 "API keys":
会看到两对密钥——测试密钥和正式密钥。保持此页面开启,后续需要使用这些密钥。
4. 整体流程
信用卡扣款分五步完成,涉及前端(浏览器)、后端(Spring Boot 应用)和 Stripe:
- 用户进入结账页面,点击 "Pay with Card"
- 弹出 Stripe Checkout 对话框,用户填写信用卡信息
- 用户点击 "Pay
" 后: - 信用卡信息发送至 Stripe
- 获取令牌(token)并追加到表单
- 表单提交金额、公钥、邮箱和令牌到后端
- 后端使用令牌、金额和私钥联系 Stripe
- 后端检查 Stripe 响应并向用户反馈结果
后续章节将详细展开每一步。
5. 结账表单
Stripe Checkout 是一个可定制、移动端友好、支持多语言的组件,用于渲染信用卡信息表单。通过配置 "checkout.js",它负责:
若需更灵活的表单控制,可使用 Stripe Elements
接下来分析表单控制器和表单本身。
5.1. 控制器
创建控制器准备结账表单所需的模型数据:
@Controller
public class CheckoutController {
@Value("${STRIPE_PUBLIC_KEY}")
private String stripePublicKey;
@RequestMapping("/checkout")
public String checkout(Model model) {
model.addAttribute("amount", 50 * 100); // 单位:分
model.addAttribute("stripePublicKey", stripePublicKey);
model.addAttribute("currency", ChargeRequest.Currency.EUR);
return "checkout";
}
}
✅ 关键点:
- 从 Stripe 仪表盘复制测试公钥,设为环境变量
STRIPE_PUBLIC_KEY
- 金额(单位:分)和货币仅为演示,实际应用应从产品/订单获取
- 密钥管理建议:测试/正式环境使用不同环境变量
⚠️ 安全提醒:私钥绝不能提交到版本控制系统!
5.2. 表单
通过配置表单和脚本实现支付功能:
<form action='/charge' method='POST' id='checkout-form'>
<input type='hidden' th:value='${amount}' name='amount' />
<label>价格:<span th:text='${amount/100}' /></label>
<!-- Thymeleaf 动态渲染 data-key/data-amount/data-currency -->
<script
src='https://checkout.stripe.com/checkout.js'
class='stripe-button'
th:attr='data-key=${stripePublicKey},
data-amount=${amount},
data-currency=${currency}'
data-name='Baeldung'
data-description='Spring 课程结账'
data-image
='https://www.baeldung.com/wp-content/themes/baeldung/favicon/android-chrome-192x192.png'
data-locale='auto'
data-zip-code='false'>
</script>
</form>
✅ 核心机制:
- "checkout.js" 在提交前自动向 Stripe 发送请求
- 返回的令牌(token)和用户邮箱作为隐藏字段 "stripeToken" 和 "stripeEmail" 追加到表单
- 脚本属性(如
data-amount
)仅用于显示(单位:分),需除以 100 显示实际金额 - 必须使用公钥(浏览器可见),绝不能使用私钥!
6. 扣款操作
后端需处理表单提交的 POST 请求。以下是扣款操作的核心类:
6.1. ChargeRequest 实体
定义扣款请求的 POJO:
@Data
public class ChargeRequest {
public enum Currency {
EUR, USD;
}
private String description;
private int amount;
private Currency currency;
private String stripeEmail;
private String stripeToken;
}
6.2. 服务层
创建 StripeService 与 Stripe 通信执行扣款:
@Service
public class StripeService {
@Value("${STRIPE_SECRET_KEY}")
private String secretKey;
@PostConstruct
public void init() {
Stripe.apiKey = secretKey;
}
public Charge charge(ChargeRequest chargeRequest)
throws AuthenticationException, InvalidRequestException,
APIConnectionException, CardException, APIException {
Map<String, Object> chargeParams = new HashMap<>();
chargeParams.put("amount", chargeRequest.getAmount());
chargeParams.put("currency", chargeRequest.getCurrency());
chargeParams.put("description", chargeRequest.getDescription());
chargeParams.put("source", chargeRequest.getStripeToken());
return Charge.create(chargeParams);
}
}
✅ 关键实现:
- 从环境变量
STRIPE_SECRET_KEY
读取私钥 - 初始化时设置全局 API 密钥
- 返回的 Charge 对象 包含操作 ID 等关键信息
6.3. 控制器
处理表单提交的控制器:
@Controller
public class ChargeController {
@Autowired
private StripeService paymentsService;
@PostMapping("/charge")
public String charge(ChargeRequest chargeRequest, Model model)
throws StripeException {
chargeRequest.setDescription("示例扣款");
chargeRequest.setCurrency(Currency.EUR);
Charge charge = paymentsService.charge(chargeRequest);
model.addAttribute("id", charge.getId());
model.addAttribute("status", charge.getStatus());
model.addAttribute("chargeId", charge.getId());
model.addAttribute("balance_transaction", charge.getBalanceTransaction());
return "result";
}
@ExceptionHandler(StripeException.class)
public String handleError(Model model, StripeException ex) {
model.addAttribute("error", ex.getMessage());
return "result";
}
}
✅ 流程解析:
ChargeRequest
自动绑定表单字段(amount/stripeEmail/stripeToken)- 成功时将 Charge 对象 的关键信息加入模型
- 异常处理器统一处理
StripeException
(可细分子类如CardException
) - 返回 "result" 视图展示结果
7. 结果展示
使用 Thymeleaf 模板展示扣款结果:
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml' xmlns:th='http://www.thymeleaf.org'>
<head>
<title>扣款结果</title>
</head>
<body>
<h3 th:if='${error}' th:text='${error}' style='color: red;'></h3>
<div th:unless='${error}'>
<h3 style='color: green;'>支付成功!</h3>
<div>交易ID: <span th:text='${id}' /></div>
<div>状态: <span th:text='${status}' /></div>
<div>扣款ID: <span th:text='${chargeId}' /></div>
<div>余额事务ID: <span th:text='${balance_transaction}' /></div>
</div>
<a href='/checkout.html'>重新结账</a>
</body>
</html>
8. 总结
本文展示了如何使用 Stripe Java API 实现信用卡扣款。未来可复用后端代码支持原生移动应用。
测试技巧:无需真实信用卡,使用 Stripe 测试卡号 即可验证完整流程。
扣款只是 Stripe Java API 的基础功能,官方 API 文档 涵盖了全部操作。
完整示例代码见 GitHub 项目。