用户下单Java微服务后端架构实战

1. 架构概述

用户下单系统是电商平台和租赁平台的核心模块,需要支持商品信息查询、押金验证、库存扣减、优惠计算、优惠券使用和订单生成等关键功能。本篇文章将深入讲解如何基于Java微服务架构实现一个高性能、高可用、数据一致性的用户下单系统。

1.1 系统架构图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
用户端 → 用户网关 → 订单服务 → 目录服务/用户服务

身份认证

校验用户是否存在有效订单

商品信息查询

请求用户押金信息

判断押金金额是否足额

商品扣库存

优惠计算

优惠券使用标记

订单生成

返回下单信息

1.2 核心组件

  • 用户网关(User Gateway):负责用户请求的接入、身份认证、请求路由
  • 订单服务(Order Service):负责订单管理、订单校验、订单生成、流程编排
  • 目录服务(Catalog Service):负责商品信息管理、库存管理、优惠计算
  • 用户服务(User Service):负责用户押金信息查询、优惠券使用标记
  • 数据库(MySQL):持久化订单信息、商品信息、库存信息
  • 分布式锁(Redisson):保证库存扣减和订单生成的并发安全
  • 分布式事务(Seata):保证下单流程的原子性和一致性

2. 用户网关服务实现

2.1 用户网关服务核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/**
* 用户网关服务
* 负责用户请求的接入、身份认证、请求路由
*/
@RestController
@RequestMapping("/api/user/gateway")
@Slf4j
public class UserGatewayController {

@Autowired
private AuthService authService;

@Autowired
private OrderServiceClient orderServiceClient;

/**
* 用户下单请求
* 请求参数:商品Id/商品数量/用户Id/优惠券Ids/优惠项
*/
@PostMapping("/order/create")
public Result<OrderCreateResult> createOrder(
@RequestHeader("Authorization") String token,
@RequestBody OrderCreateRequest request) {

try {
// 1. 身份认证
UserInfo userInfo = authService.authenticate(token);
if (userInfo == null) {
return Result.error("身份认证失败");
}

// 2. 设置用户ID
request.setUserId(userInfo.getUserId());

// 3. 调用订单服务创建订单
OrderCreateResult result = orderServiceClient.createOrder(request);

if (!result.isSuccess()) {
return Result.error(result.getMessage());
}

log.info("用户下单成功: userId={}, orderId={}, orderNo={}",
userInfo.getUserId(), result.getOrderId(), result.getOrderNo());

return Result.success(result);

} catch (Exception e) {
log.error("用户下单失败: error={}", e.getMessage(), e);
return Result.error("下单失败: " + e.getMessage());
}
}
}

2.2 身份认证服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/**
* 身份认证服务
*/
@Service
@Slf4j
public class AuthService {

@Autowired
private RedisTemplate<String, Object> redisTemplate;

@Autowired
private UserServiceClient userServiceClient;

/**
* 身份认证
* 验证Token有效性
*/
public UserInfo authenticate(String token) {
try {
// 1. 从Token中解析用户信息
String userId = parseToken(token);
if (StringUtils.isEmpty(userId)) {
return null;
}

// 2. 从缓存中获取用户信息
String userCacheKey = "user:info:" + userId;
UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(userCacheKey);

if (userInfo != null) {
return userInfo;
}

// 3. 缓存未命中,调用用户服务查询
userInfo = userServiceClient.getUserInfo(userId);

// 4. 将用户信息写入缓存
if (userInfo != null) {
redisTemplate.opsForValue().set(userCacheKey, userInfo, 30, TimeUnit.MINUTES);
}

return userInfo;

} catch (Exception e) {
log.error("身份认证失败: token={}, error={}", token, e.getMessage(), e);
return null;
}
}

/**
* 解析Token
*/
private String parseToken(String token) {
// JWT Token解析逻辑
if (StringUtils.isEmpty(token) || !token.startsWith("Bearer ")) {
return null;
}

String jwtToken = token.substring(7);
// 解析JWT获取userId
return extractUserIdFromJWT(jwtToken);
}

private String extractUserIdFromJWT(String jwtToken) {
// JWT解析实现
// 实际实现需要使用JWT库
return "user123";
}
}

3. 订单服务实现

3.1 订单服务核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/**
* 订单服务
* 负责订单管理、订单校验、订单生成、流程编排
*/
@Service
@Slf4j
public class OrderService {

@Autowired
private OrderMapper orderMapper;

@Autowired
private CatalogServiceClient catalogServiceClient;

@Autowired
private UserServiceClient userServiceClient;

@Autowired
private RedissonClient redissonClient;

/**
* 创建订单
* 完整的下单流程
*/
@GlobalTransactional(rollbackFor = Exception.class)
public OrderCreateResult createOrder(OrderCreateRequest request) {
String lockKey = "order:create:lock:" + request.getUserId();
RLock lock = redissonClient.getLock(lockKey);

try {
if (lock.tryLock(10, TimeUnit.SECONDS)) {
// 1. 校验用户是否存在有效订单,如果有不允许下单
if (hasValidOrder(request.getUserId(), request.getProductId())) {
return OrderCreateResult.failed("用户存在有效订单,不允许重复下单");
}

// 2. 商品(换电/保险套餐)信息查询
ProductInfo productInfo = catalogServiceClient.getProductInfo(request.getProductId());
if (productInfo == null) {
return OrderCreateResult.failed("商品信息不存在");
}

// 3. 请求用户押金信息,押金金额是否大于商品押金金额
UserDepositInfo depositInfo = userServiceClient.getUserDepositInfo(
request.getUserId(), request.getProductId());

// 4. 判断押金金额是否足额,不足不允许下单。足额进行订单金额计算
if (depositInfo == null || depositInfo.getDepositAmount() == null) {
return OrderCreateResult.failed("用户押金信息不存在");
}

if (depositInfo.getDepositAmount().compareTo(productInfo.getDepositAmount()) < 0) {
return OrderCreateResult.failed("押金金额不足,商品押金: " +
productInfo.getDepositAmount() + ", 用户押金: " +
depositInfo.getDepositAmount());
}

// 5. 商品扣库存
StockDeductRequest stockRequest = new StockDeductRequest();
stockRequest.setProductId(request.getProductId());
stockRequest.setQuantity(request.getQuantity());

StockDeductResult stockResult = catalogServiceClient.deductStock(stockRequest);
if (!stockResult.isSuccess()) {
return OrderCreateResult.failed("商品库存不足: " + stockResult.getMessage());
}

// 6. 优惠计算(优惠券Ids/商品Ids/商品数量/优惠项)
DiscountCalculateRequest discountRequest = new DiscountCalculateRequest();
discountRequest.setProductIds(Arrays.asList(request.getProductId()));
discountRequest.setQuantities(Arrays.asList(request.getQuantity()));
discountRequest.setCouponIds(request.getCouponIds());
discountRequest.setDiscountItems(request.getDiscountItems());
discountRequest.setOriginalAmount(productInfo.getPrice()
.multiply(new BigDecimal(request.getQuantity())));

DiscountCalculateResult discountResult =
catalogServiceClient.calculateDiscount(discountRequest);
if (!discountResult.isSuccess()) {
// 回滚库存
catalogServiceClient.rollbackStock(stockRequest);
return OrderCreateResult.failed("优惠计算失败: " + discountResult.getMessage());
}

// 7. 优惠券使用标记请求
if (request.getCouponIds() != null && !request.getCouponIds().isEmpty()) {
CouponUseRequest couponRequest = new CouponUseRequest();
couponRequest.setUserId(request.getUserId());
couponRequest.setCouponIds(request.getCouponIds());
couponRequest.setOrderAmount(discountResult.getFinalAmount());

CouponUseResult couponResult = userServiceClient.useCoupons(couponRequest);
if (!couponResult.isSuccess()) {
// 回滚库存
catalogServiceClient.rollbackStock(stockRequest);
return OrderCreateResult.failed("优惠券使用失败: " + couponResult.getMessage());
}
}

// 8. 订单生成
Order order = generateOrder(request, productInfo, discountResult, depositInfo);
orderMapper.insert(order);

log.info("订单生成成功: orderId={}, orderNo={}, userId={}, amount={}",
order.getId(), order.getOrderNo(), request.getUserId(),
discountResult.getFinalAmount());

// 9. 构建返回结果
OrderCreateResult result = new OrderCreateResult();
result.setSuccess(true);
result.setOrderId(order.getId());
result.setOrderNo(order.getOrderNo());
result.setAmount(discountResult.getFinalAmount());
result.setOriginalAmount(discountResult.getOriginalAmount());
result.setDiscountAmount(discountResult.getDiscountAmount());
result.setMessage("下单成功");

return result;

} else {
return OrderCreateResult.failed("下单操作超时,请稍后再试");
}
} catch (Exception e) {
log.error("创建订单失败: userId={}, productId={}, error={}",
request.getUserId(), request.getProductId(), e.getMessage(), e);
return OrderCreateResult.failed("下单失败: " + e.getMessage());
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}

/**
* 校验用户是否存在有效订单,如果有不允许下单
*/
private boolean hasValidOrder(Long userId, Long productId) {
List<Order> validOrders = orderMapper.selectValidOrdersByUserIdAndProductId(
userId, productId);
return !validOrders.isEmpty();
}

/**
* 订单生成
*/
private Order generateOrder(OrderCreateRequest request, ProductInfo productInfo,
DiscountCalculateResult discountResult,
UserDepositInfo depositInfo) {
Order order = new Order();
order.setOrderNo(generateOrderNo());
order.setUserId(request.getUserId());
order.setProductId(request.getProductId());
order.setProductName(productInfo.getProductName());
order.setQuantity(request.getQuantity());
order.setOriginalAmount(discountResult.getOriginalAmount());
order.setDiscountAmount(discountResult.getDiscountAmount());
order.setFinalAmount(discountResult.getFinalAmount());
order.setDepositAmount(depositInfo.getDepositAmount());
order.setCouponIds(String.join(",", request.getCouponIds() != null ?
request.getCouponIds() : Collections.emptyList()));
order.setStatus(OrderStatus.UNPAID.getCode());
order.setCreateTime(new Date());
order.setUpdateTime(new Date());

return order;
}

/**
* 生成订单号
*/
private String generateOrderNo() {
return "ORD" + System.currentTimeMillis() + RandomUtils.nextInt(10000, 99999);
}
}

4. 目录服务实现

4.1 目录服务核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
/**
* 目录服务
* 负责商品信息管理、库存管理、优惠计算
*/
@Service
@Slf4j
public class CatalogService {

@Autowired
private ProductMapper productMapper;

@Autowired
private ProductStockMapper productStockMapper;

@Autowired
private DiscountRuleMapper discountRuleMapper;

@Autowired
private RedissonClient redissonClient;

/**
* 商品(换电/保险套餐)信息查询
*/
public ProductInfo getProductInfo(Long productId) {
try {
Product product = productMapper.selectById(productId);
if (product == null) {
return null;
}

ProductInfo info = new ProductInfo();
info.setProductId(product.getId());
info.setProductName(product.getProductName());
info.setProductCode(product.getProductCode());
info.setProductType(product.getProductType());
info.setPrice(product.getPrice());
info.setDepositAmount(product.getDepositAmount());
info.setDescription(product.getDescription());

return info;

} catch (Exception e) {
log.error("查询商品信息失败: productId={}, error={}",
productId, e.getMessage(), e);
return null;
}
}

/**
* 商品信息查询处理
*/
public ProductInfoQueryResult queryProductInfo(ProductInfoQueryRequest request) {
try {
ProductInfo productInfo = getProductInfo(request.getProductId());

ProductInfoQueryResult result = new ProductInfoQueryResult();
result.setSuccess(productInfo != null);
result.setProductInfo(productInfo);
result.setMessage(productInfo != null ? "查询成功" : "商品信息不存在");

return result;

} catch (Exception e) {
log.error("商品信息查询处理失败: productId={}, error={}",
request.getProductId(), e.getMessage(), e);
return ProductInfoQueryResult.failed("查询失败: " + e.getMessage());
}
}

/**
* 商品扣库存
*/
@Transactional(rollbackFor = Exception.class)
public StockDeductResult deductStock(StockDeductRequest request) {
String lockKey = "stock:lock:" + request.getProductId();
RLock lock = redissonClient.getLock(lockKey);

try {
if (lock.tryLock(10, TimeUnit.SECONDS)) {
// 1. 查询商品库存
ProductStock stock = productStockMapper.selectByProductId(request.getProductId());
if (stock == null) {
return StockDeductResult.failed("商品库存信息不存在");
}

// 2. 检查库存是否充足
if (stock.getAvailableStock() < request.getQuantity()) {
return StockDeductResult.failed("商品库存不足,当前库存: " +
stock.getAvailableStock() + ", 需要数量: " + request.getQuantity());
}

// 3. 扣减库存
stock.setAvailableStock(stock.getAvailableStock() - request.getQuantity());
stock.setReservedStock(stock.getReservedStock() + request.getQuantity());
stock.setUpdateTime(new Date());
productStockMapper.updateById(stock);

log.info("商品扣库存成功: productId={}, quantity={}, availableStock={}",
request.getProductId(), request.getQuantity(),
stock.getAvailableStock());

// 4. 构建返回结果
StockDeductResult result = new StockDeductResult();
result.setSuccess(true);
result.setProductId(request.getProductId());
result.setDeductedQuantity(request.getQuantity());
result.setRemainingStock(stock.getAvailableStock());
result.setMessage("库存扣减成功");

return result;

} else {
return StockDeductResult.failed("库存操作超时,请稍后再试");
}
} catch (Exception e) {
log.error("商品扣库存失败: productId={}, quantity={}, error={}",
request.getProductId(), request.getQuantity(), e.getMessage(), e);
return StockDeductResult.failed("库存扣减失败: " + e.getMessage());
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}

/**
* 回滚库存
*/
@Transactional(rollbackFor = Exception.class)
public void rollbackStock(StockDeductRequest request) {
String lockKey = "stock:lock:" + request.getProductId();
RLock lock = redissonClient.getLock(lockKey);

try {
if (lock.tryLock(10, TimeUnit.SECONDS)) {
ProductStock stock = productStockMapper.selectByProductId(request.getProductId());
if (stock != null) {
stock.setAvailableStock(stock.getAvailableStock() + request.getQuantity());
stock.setReservedStock(stock.getReservedStock() - request.getQuantity());
stock.setUpdateTime(new Date());
productStockMapper.updateById(stock);

log.info("库存回滚成功: productId={}, quantity={}",
request.getProductId(), request.getQuantity());
}
}
} catch (Exception e) {
log.error("库存回滚失败: productId={}, quantity={}, error={}",
request.getProductId(), request.getQuantity(), e.getMessage(), e);
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}

/**
* 优惠计算(优惠券Ids/商品Ids/商品数量/优惠项)
*/
public DiscountCalculateResult calculateDiscount(DiscountCalculateRequest request) {
try {
BigDecimal originalAmount = request.getOriginalAmount();
BigDecimal totalDiscount = BigDecimal.ZERO;
List<DiscountItem> discountItems = new ArrayList<>();

// 1. 商品优惠计算
if (request.getDiscountItems() != null && !request.getDiscountItems().isEmpty()) {
for (DiscountItem item : request.getDiscountItems()) {
BigDecimal discount = calculateItemDiscount(item, originalAmount);
totalDiscount = totalDiscount.add(discount);
discountItems.add(item);
}
}

// 2. 优惠券优惠计算
if (request.getCouponIds() != null && !request.getCouponIds().isEmpty()) {
for (Long couponId : request.getCouponIds()) {
CouponDiscountResult couponResult = calculateCouponDiscount(
couponId, originalAmount, request.getProductIds());
if (couponResult.isSuccess()) {
totalDiscount = totalDiscount.add(couponResult.getDiscountAmount());
DiscountItem discountItem = new DiscountItem();
discountItem.setType("COUPON");
discountItem.setCouponId(couponId);
discountItem.setDiscountAmount(couponResult.getDiscountAmount());
discountItems.add(discountItem);
}
}
}

// 3. 计算最终金额
BigDecimal finalAmount = originalAmount.subtract(totalDiscount);
if (finalAmount.compareTo(BigDecimal.ZERO) < 0) {
finalAmount = BigDecimal.ZERO;
}

// 4. 构建返回结果
DiscountCalculateResult result = new DiscountCalculateResult();
result.setSuccess(true);
result.setOriginalAmount(originalAmount);
result.setDiscountAmount(totalDiscount);
result.setFinalAmount(finalAmount);
result.setDiscountItems(discountItems);
result.setMessage("优惠计算成功");

return result;

} catch (Exception e) {
log.error("优惠计算失败: error={}", e.getMessage(), e);
return DiscountCalculateResult.failed("优惠计算失败: " + e.getMessage());
}
}

/**
* 计算商品优惠
*/
private BigDecimal calculateItemDiscount(DiscountItem item, BigDecimal originalAmount) {
// 根据优惠类型计算优惠金额
// 这里简化处理,实际应该根据优惠规则计算
return item.getDiscountAmount() != null ? item.getDiscountAmount() : BigDecimal.ZERO;
}

/**
* 计算优惠券优惠
*/
private CouponDiscountResult calculateCouponDiscount(Long couponId,
BigDecimal originalAmount,
List<Long> productIds) {
// 查询优惠券信息并计算优惠
// 这里简化处理,实际应该查询优惠券信息
CouponDiscountResult result = new CouponDiscountResult();
result.setSuccess(true);
result.setDiscountAmount(BigDecimal.ZERO);
return result;
}
}

5. 用户服务实现

5.1 用户服务核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/**
* 用户服务
* 负责用户押金信息查询、优惠券使用标记
*/
@Service
@Slf4j
public class UserService {

@Autowired
private UserDepositMapper userDepositMapper;

@Autowired
private UserCouponMapper userCouponMapper;

@Autowired
private RedissonClient redissonClient;

/**
* 请求用户押金信息,押金金额是否大于商品押金金额
*/
public UserDepositInfo getUserDepositInfo(Long userId, Long productId) {
try {
// 1. 查询用户押金
UserDeposit deposit = userDepositMapper.selectByUserIdAndProductId(userId, productId);

// 2. 构建返回结果
UserDepositInfo info = new UserDepositInfo();
if (deposit != null && DepositStatus.PAID.getCode().equals(deposit.getStatus())) {
info.setHasDeposit(true);
info.setDepositAmount(deposit.getAmount());
info.setDepositId(deposit.getId());
} else {
info.setHasDeposit(false);
info.setDepositAmount(BigDecimal.ZERO);
}

return info;

} catch (Exception e) {
log.error("查询用户押金信息失败: userId={}, productId={}, error={}",
userId, productId, e.getMessage(), e);
return null;
}
}

/**
* 请求用户押金信息处理
*/
public UserDepositInfoQueryResult queryUserDepositInfo(
UserDepositInfoQueryRequest request) {
try {
UserDepositInfo depositInfo = getUserDepositInfo(
request.getUserId(), request.getProductId());

UserDepositInfoQueryResult result = new UserDepositInfoQueryResult();
result.setSuccess(depositInfo != null);
result.setDepositInfo(depositInfo);
result.setMessage(depositInfo != null ? "查询成功" : "押金信息不存在");

return result;

} catch (Exception e) {
log.error("用户押金信息查询处理失败: userId={}, productId={}, error={}",
request.getUserId(), request.getProductId(), e.getMessage(), e);
return UserDepositInfoQueryResult.failed("查询失败: " + e.getMessage());
}
}

/**
* 优惠券使用标记请求
*/
@Transactional(rollbackFor = Exception.class)
public CouponUseResult useCoupons(CouponUseRequest request) {
String lockKey = "coupon:use:lock:" + request.getUserId();
RLock lock = redissonClient.getLock(lockKey);

try {
if (lock.tryLock(10, TimeUnit.SECONDS)) {
List<Long> usedCouponIds = new ArrayList<>();

// 1. 遍历优惠券ID,标记为已使用
for (Long couponId : request.getCouponIds()) {
// 查询用户优惠券
UserCoupon userCoupon = userCouponMapper.selectByUserIdAndCouponId(
request.getUserId(), couponId);

if (userCoupon == null) {
return CouponUseResult.failed("优惠券不存在: " + couponId);
}

if (!CouponStatus.UNUSED.getCode().equals(userCoupon.getStatus())) {
return CouponUseResult.failed("优惠券已使用或已过期: " + couponId);
}

// 标记为已使用
userCoupon.setStatus(CouponStatus.USED.getCode());
userCoupon.setUseTime(new Date());
userCoupon.setOrderAmount(request.getOrderAmount());
userCoupon.setUpdateTime(new Date());
userCouponMapper.updateById(userCoupon);

usedCouponIds.add(couponId);
}

log.info("优惠券使用标记成功: userId={}, couponIds={}",
request.getUserId(), usedCouponIds);

// 2. 构建返回结果
CouponUseResult result = new CouponUseResult();
result.setSuccess(true);
result.setUsedCouponIds(usedCouponIds);
result.setMessage("优惠券使用成功");

return result;

} else {
return CouponUseResult.failed("优惠券操作超时,请稍后再试");
}
} catch (Exception e) {
log.error("优惠券使用标记失败: userId={}, couponIds={}, error={}",
request.getUserId(), request.getCouponIds(), e.getMessage(), e);
return CouponUseResult.failed("优惠券使用失败: " + e.getMessage());
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}

/**
* 优惠券使用处理
*/
public CouponUseProcessResult processCouponUse(CouponUseProcessRequest request) {
try {
CouponUseResult useResult = useCoupons(request.getCouponUseRequest());

CouponUseProcessResult result = new CouponUseProcessResult();
result.setSuccess(useResult.isSuccess());
result.setUsedCouponIds(useResult.getUsedCouponIds());
result.setMessage(useResult.getMessage());

return result;

} catch (Exception e) {
log.error("优惠券使用处理失败: error={}", e.getMessage(), e);
return CouponUseProcessResult.failed("处理失败: " + e.getMessage());
}
}
}

6. 数据模型定义

6.1 订单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/**
* 订单
*/
@Data
@TableName("order")
public class Order {
/**
* 主键ID
*/
@TableId(type = IdType.AUTO)
private Long id;

/**
* 订单号
*/
private String orderNo;

/**
* 用户ID
*/
private Long userId;

/**
* 商品ID
*/
private Long productId;

/**
* 商品名称
*/
private String productName;

/**
* 商品数量
*/
private Integer quantity;

/**
* 原价金额
*/
private BigDecimal originalAmount;

/**
* 优惠金额
*/
private BigDecimal discountAmount;

/**
* 最终金额
*/
private BigDecimal finalAmount;

/**
* 押金金额
*/
private BigDecimal depositAmount;

/**
* 优惠券IDs(逗号分隔)
*/
private String couponIds;

/**
* 订单状态:UNPAID-未支付, PAID-已支付, CANCELLED-已取消等
*/
private String status;

/**
* 创建时间
*/
private Date createTime;

/**
* 更新时间
*/
private Date updateTime;
}

6.2 订单创建请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* 订单创建请求
*/
@Data
public class OrderCreateRequest {
/**
* 用户ID
*/
private Long userId;

/**
* 商品ID
*/
private Long productId;

/**
* 商品数量
*/
private Integer quantity;

/**
* 优惠券IDs
*/
private List<Long> couponIds;

/**
* 优惠项
*/
private List<DiscountItem> discountItems;
}

6.3 订单创建结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* 订单创建结果
*/
@Data
public class OrderCreateResult {
/**
* 是否成功
*/
private Boolean success;

/**
* 订单ID
*/
private Long orderId;

/**
* 订单号
*/
private String orderNo;

/**
* 最终金额
*/
private BigDecimal amount;

/**
* 原价金额
*/
private BigDecimal originalAmount;

/**
* 优惠金额
*/
private BigDecimal discountAmount;

/**
* 消息
*/
private String message;

public static OrderCreateResult failed(String message) {
OrderCreateResult result = new OrderCreateResult();
result.setSuccess(false);
result.setMessage(message);
return result;
}
}

7. 数据库Mapper实现

7.1 OrderMapper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 订单Mapper
*/
@Mapper
public interface OrderMapper extends BaseMapper<Order> {

/**
* 查询有效订单(未完成、未取消的订单)
*/
@Select("SELECT * FROM `order` " +
"WHERE user_id = #{userId} " +
"AND product_id = #{productId} " +
"AND status NOT IN ('COMPLETED', 'CANCELLED', 'REFUNDED') " +
"AND deleted = 0 " +
"ORDER BY create_time DESC")
List<Order> selectValidOrdersByUserIdAndProductId(
@Param("userId") Long userId,
@Param("productId") Long productId);
}

8. 总结

本文详细介绍了用户下单的Java微服务架构实现,包括:

  1. 用户网关服务:负责用户请求接入、身份认证、请求路由
  2. 订单服务:负责订单管理、订单校验、订单生成、流程编排
  3. 目录服务:负责商品信息管理、库存管理、优惠计算
  4. 用户服务:负责用户押金信息查询、优惠券使用标记
  5. 下单流程
    • 用户下单请求(商品Id/商品数量/用户Id/优惠券Ids/优惠项)
    • 身份认证
    • 校验用户是否存在有效订单,如果有不允许下单
    • 商品(换电/保险套餐)信息查询
    • 请求用户押金信息,押金金额是否大于商品押金金额
    • 判断押金金额是否足额,不足不允许下单。足额进行订单金额计算
    • 商品扣库存
    • 优惠计算(优惠券Ids/商品Ids/商品数量/优惠项)
    • 优惠券使用标记请求
    • 订单生成
    • 返回下单信息
  6. 分布式事务:使用Seata保证下单流程的原子性和一致性
  7. 库存管理:支持库存扣减和回滚
  8. 优惠计算:支持商品优惠和优惠券优惠

该架构具有以下优势:

  • 数据一致性:分布式事务保证下单流程的原子性
  • 高性能:分布式锁保证并发安全,支持高并发下单
  • 高可用:数据库持久化,支持数据恢复
  • 可扩展:微服务架构,支持水平扩展
  • 完整性:完整的订单校验、库存管理、优惠计算流程

通过本文的实战代码,可以快速搭建一个高性能、高可用、数据一致性的用户下单系统。