一、项目背景与技术选型
1. 场景需求
构建一个支持用户注册、商品浏览、购物车管理、订单支付全流程的在线书店系统,核心难点在于支付系统安全接入与RESTful API规范设计。
2. 技术栈组合
- 后端框架:SSM(Spring + Spring MVC + MyBatis)
- 支付接口:支付宝沙箱环境(模拟真实支付场景)
- 安全协议:OAuth2.0(用户鉴权) + HTTPS(数据传输加密)
- 工具链:Postman(接口测试)、Swagger(API文档)
二、环境搭建与项目初始化
1. 支付宝沙箱配置
- 登录支付宝开放平台,进入「沙箱环境」
- 获取关键参数:
APP_ID
(应用ID)APP_PRIVATE_KEY
(应用私钥)ALIPAY_PUBLIC_KEY
(支付宝公钥)
- 下载支付宝SDK(alipay-sdk-java)
<!-- pom.xml 添加支付宝SDK依赖 -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.35.5.ALL</version>
</dependency>
2. SSM框架整合
// Spring配置类示例
@Configuration
@EnableWebMvc
@ComponentScan("com.bookstore")
@Import({DataSourceConfig.class, MyBatisConfig.class})
public class AppConfig extends WebMvcConfigurerAdapter {
// 配置视图解析器、静态资源等
}
三、核心功能实现与代码详解
1. 用户模块(OAuth2.0鉴权)
// OAuth2.0令牌端点
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@PostMapping("/token")
public ResponseEntity<?> login(@RequestParam String username,
@RequestParam String password) {
// 1. 校验用户名密码
// 2. 生成JWT令牌
String token = Jwts.builder()
.setSubject(username)
.signWith(SignatureAlgorithm.HS512, SECRET_KEY)
.compact();
return ResponseEntity.ok(new TokenResponse(token));
}
}
2. 商品与订单模块(RESTful API设计)
// 商品查询接口
@RestController
@RequestMapping("/api/products")
public class ProductController {
@Autowired
private ProductService productService;
@GetMapping
public ResponseEntity<List<Product>> listProducts(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return ResponseEntity.ok(productService.getProducts(page, size));
}
}
// 订单创建接口
@PostMapping("/orders")
public ResponseEntity<Order> createOrder(@RequestBody OrderRequest request) {
// 验证用户权限、库存扣减
Order order = orderService.createOrder(request);
return ResponseEntity.created(URI.create("/orders/" + order.getId())).body(order);
}
3. 支付宝支付模块(关键代码)
支付请求封装
public class AlipayService {
public String createPayForm(Order order) throws AlipayApiException {
AlipayClient client = new DefaultAlipayClient(
"https://openapi.alipaydev.com/gateway.do",
APP_ID,
APP_PRIVATE_KEY,
"json",
"UTF-8",
ALIPAY_PUBLIC_KEY,
"RSA2"
);
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setReturnUrl("http://localhost:8080/pay/success");
request.setNotifyUrl("http://your-domain.com/pay/notify"); // 异步通知地址
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", order.getOrderNo());
bizContent.put("total_amount", order.getTotalAmount());
bizContent.put("subject", "在线书店订单支付");
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
request.setBizContent(bizContent.toString());
return client.pageExecute(request).getBody();
}
}
支付结果异步通知处理
@PostMapping("/pay/notify")
public String handleAlipayNotify(HttpServletRequest request) {
Map<String, String> params = convertRequestToMap(request);
boolean signVerified = AlipaySignature.rsaCheckV1(
params,
ALIPAY_PUBLIC_KEY,
"UTF-8",
"RSA2");
if (signVerified) {
String tradeStatus = params.get("trade_status");
if ("TRADE_SUCCESS".equals(tradeStatus)) {
String orderNo = params.get("out_trade_no");
orderService.updateOrderStatus(orderNo, OrderStatus.PAID);
return "success";
}
}
return "failure";
}
四、接口调试与常见问题排查
1. Postman测试支付流程
-
获取访问令牌
POST /api/auth/token Content-Type: application/x-www-form-urlencoded username=test&password=123456
-
创建订单
POST /api/orders Authorization: Bearer {token} Content-Type: application/json { "productIds": [1, 3], "shippingAddress": "北京市海淀区" }
-
发起支付
GET /api/pay/{orderId}
2. 常见错误解决方案
-
Q:支付宝返回“无效签名”
- 检查密钥是否正确(注意区分应用公钥与支付宝公钥)
- 确认加密算法是否为RSA2
-
Q:异步通知未触发
- 确保服务器能被外网访问(可用ngrok做内网穿透)
- 检查支付宝沙箱中的“通知地址”白名单