Spring Boot + MyBatis 集成支付宝支付流程
核心流程
- 商户系统生成订单
- 调用支付宝创建预支付订单
- 用户跳转支付宝完成支付
- 支付宝异步通知支付结果
- 商户处理支付结果更新订单状态
- 支付宝同步跳转回商户页面
代码实现示例(电脑网站支付)
1. 添加依赖
<!-- pom.xml -->
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis & MySQL -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 支付宝SDK -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.35.0.ALL</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
2. 支付宝配置类
@Configuration
public class AlipayConfig {
@Value("${alipay.app_id}")
private String appId;
@Value("${alipay.merchant_private_key}")
private String merchantPrivateKey;
@Value("${alipay.alipay_public_key}")
private String alipayPublicKey;
@Value("${alipay.notify_url}")
private String notifyUrl;
@Value("${alipay.return_url}")
private String returnUrl;
@Value("${alipay.gateway_url}")
private String gatewayUrl;
@Value("${alipay.sign_type}")
private String signType;
@Value("${alipay.charset}")
private String charset;
@Bean
public AlipayClient alipayClient() {
return new DefaultAlipayClient(
gatewayUrl,
appId,
merchantPrivateKey,
"json",
charset,
alipayPublicKey,
signType
);
}
}
3. 实体类和Mapper
// 订单实体
@Data
public class Order {
private Long id;
private String orderNo; // 商户订单号
private BigDecimal amount;// 支付金额
private Integer status; // 0-待支付, 1-已支付
private LocalDateTime createTime;
}
// MyBatis Mapper
@Mapper
public interface OrderMapper {
@Insert("INSERT INTO orders(order_no, amount, status, create_time) " +
"VALUES(#{orderNo}, #{amount}, 0, NOW())")
@Options(useGeneratedKeys = true, keyProperty = "id")
void insert(Order order);
@Update("UPDATE orders SET status = #{status} WHERE order_no = #{orderNo}")
void updateStatus(@Param("orderNo") String orderNo, @Param("status") int status);
}
4. 支付服务类
@Service
public class PayService {
@Autowired private AlipayClient alipayClient;
@Autowired private OrderMapper orderMapper;
@Value("${alipay.return_url}") private String returnUrl;
@Value("${alipay.notify_url}") private String notifyUrl;
// 创建支付订单
public String createPayOrder(Order order) throws AlipayApiException {
orderMapper.insert(order); // 保存订单到数据库
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setReturnUrl(returnUrl);
request.setNotifyUrl(notifyUrl);
// 构造业务参数
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", order.getOrderNo());
bizContent.put("total_amount", order.getAmount());
bizContent.put("subject", "商品支付");
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY"); // 电脑网站支付
request.setBizContent(bizContent.toString());
return alipayClient.pageExecute(request).getBody();
}
// 处理异步通知
public boolean handleNotify(Map<String, String> params) throws AlipayApiException {
// 1. 验证签名
boolean signVerified = AlipaySignature.rsaCheckV1(
params,
alipayPublicKey, // 注入支付宝公钥
charset,
signType
);
if (!signVerified) return false;
// 2. 验证交易状态
String tradeStatus = params.get("trade_status");
if (!"TRADE_SUCCESS".equals(tradeStatus)) return false;
// 3. 更新订单状态
String orderNo = params.get("out_trade_no");
orderMapper.updateStatus(orderNo, 1); // 更新为已支付
return true;
}
}
5. 控制器
@RestController
@RequestMapping("/pay")
public class PayController {
@Autowired private PayService payService;
// 创建支付订单
@PostMapping("/create")
public String createOrder(@RequestParam BigDecimal amount)
throws AlipayApiException {
Order order = new Order();
order.setOrderNo(UUID.randomUUID().toString().replace("-", ""));
order.setAmount(amount);
return payService.createPayOrder(order); // 返回支付页面表单
}
// 支付宝异步通知(需公网可访问)
@PostMapping("/notify")
public String alipayNotify(HttpServletRequest request)
throws UnsupportedEncodingException, AlipayApiException {
Map<String, String> params = parseRequestParams(request);
boolean success = payService.handleNotify(params);
return success ? "success" : "failure"; // 通知支付宝处理结果
}
// 支付宝同步跳转
@GetMapping("/return")
public String alipayReturn(HttpServletRequest request) {
// 简单展示支付结果(实际需要验签和状态检查)
return "支付完成!订单号:" + request.getParameter("out_trade_no");
}
// 解析请求参数
private Map<String, String> parseRequestParams(HttpServletRequest request) {
// 转换参数Map(参考支付宝示例代码)
}
}
6. 配置文件
# application.properties
# 支付宝配置
alipay.app_id=2021000123456789
alipay.merchant_private_key=MIIEvQIBADANB...
alipay.alipay_public_key=MIIBIjANBgkq...
alipay.notify_url=http://your-domain.com/pay/notify
alipay.return_url=http://your-domain.com/pay/return
alipay.gateway_url=https://openapi.alipay.com/gateway.do
alipay.sign_type=RSA2
alipay.charset=UTF-8
# MySQL配置
spring.datasource.url=jdbc:mysql://localhost:3306/alipay_demo
spring.datasource.username=root
spring.datasource.password=123456
关键流程说明
生成商户订单
- 生成唯一订单号(推荐雪花算法)
- 保存订单到数据库(状态=待支付)
调用支付宝接口
- 使用
AlipayTradePagePayRequest
构建请求 - 关键参数:订单号、金额、支付标题、回调地址
- 使用
接收异步通知
- 必须验证签名(防止伪造请求)
- 检查 trade_status 是否为 TRADE_SUCCESS
- 更新订单状态(注意处理幂等性)
安全注意事项
- 支付金额需与订单金额比对(防止金额篡改)
- 敏感操作记录日志
- 异步通知处理需要保证幂等性
扩展功能
- 订单超时关闭:定时任务扫描未支付订单
- 支付结果查询:通过 trade_no 调用支付宝查询接口
- 退款功能:使用
AlipayTradeRefundRequest
提示:实际开发中需要:
- 替换为正式支付宝账户
- 配置公网可访问的域名
- 添加完整的错误处理
- 实现参数解析工具方法
- 添加数据库事务管理