ZBLOG

后端实现商品订单结算,购物车商品或单个商品结算,购物车的字段为 @TableId(type = IdType.AUTO) private Long id; private Integer userId; private Long productId; private Integer quantity; private Boolean selected; @TableField(fill = FieldFill.INSERT) p...

商品订单结算实现方案

基于您提供的购物车和商品实体类,我可以提供一个后端实现商品订单结算的方案,包括购物车多商品结算和单个商品直接结算。

1. 订单结算核心逻辑

1.1 创建订单服务接口

  1. public interface OrderService {
  2. /**
  3. * 从购物车结算生成订单
  4. * @param userId 用户ID
  5. * @param cartItemIds 购物车项ID列表(为空则结算所有选中项)
  6. * @return 生成的订单ID
  7. */
  8. Long createOrderFromCart(Integer userId, List<Long> cartItemIds);
  9. /**
  10. * 直接购买商品生成订单(不经过购物车)
  11. * @param userId 用户ID
  12. * @param productId 商品ID
  13. * @param quantity 数量
  14. * @return 生成的订单ID
  15. */
  16. Long createDirectOrder(Integer userId, Long productId, Integer quantity);
  17. }

1.2 实现类核心代码

  1. @Service
  2. @Transactional
  3. public class OrderServiceImpl implements OrderService {
  4. @Autowired
  5. private CartMapper cartMapper;
  6. @Autowired
  7. private ProductMapper productMapper;
  8. @Autowired
  9. private OrderMapper orderMapper;
  10. @Autowired
  11. private OrderItemMapper orderItemMapper;
  12. @Override
  13. public Long createOrderFromCart(Integer userId, List<Long> cartItemIds) {
  14. // 1. 查询购物车项(根据传入的cartItemIds或默认选中的项)
  15. List<Cart> cartItems = getValidCartItems(userId, cartItemIds);
  16. // 2. 校验库存并计算总金额
  17. BigDecimal totalAmount = BigDecimal.ZERO;
  18. Map<Long, Product> productMap = new HashMap<>();
  19. for (Cart cartItem : cartItems) {
  20. Product product = productMapper.selectById(cartItem.getProductId());
  21. if (product == null || product.getStatus() != StatusEnum.NORMAL.getCode()) {
  22. throw new BusinessException("商品" + product.getId() + "已下架");
  23. }
  24. if (product.getStock() < cartItem.getQuantity()) {
  25. throw new BusinessException("商品" + product.getName() + "库存不足");
  26. }
  27. productMap.put(product.getId(), product);
  28. // 计算总金额: price * quantity
  29. totalAmount = totalAmount.add(
  30. product.getPrice().multiply(new BigDecimal(cartItem.getQuantity()))
  31. );
  32. }
  33. // 3. 创建订单主表记录
  34. Order order = new Order();
  35. order.setUserId(userId);
  36. order.setTotalAmount(totalAmount);
  37. order.setStatus(OrderStatusEnum.WAIT_PAYMENT.getCode());
  38. orderMapper.insert(order);
  39. // 4. 创建订单明细并扣减库存、删除购物车项(事务保证一致性)
  40. for (Cart cartItem : cartItems) {
  41. Product product = productMap.get(cartItem.getProductId());
  42. // a.创建订单明细项
  43. OrderItem orderItem = new OrderItem();
  44. BeanUtils.copyProperties(product, orderItem); // copy部分属性
  45. orderItem.setOrderId(order.getId());
  46. orderItem.setProductId(product.getId());
  47. orderItem.setQuantity(cartItem.getQuantity());
  48. // b.计算当前项的金额并设置到明细中
  49. BigDecimal itemAmount =
  50. product.getPrice().multiply(new BigDecimal(cartItem.getQuantity()));
  51. orderItem.setPrice(product.getPrice());
  52. orderItem.setActualPayment(itemAmount);
  53. orderItemMapper.insert(orderDetail);
  54. // c.扣减库存(乐观锁防止超卖)
  55. int updateRows = productMapper.reduceStock(
  56. product.getId(),
  57. cartDetail.getQuantity(),
  58. LocalDateTime.now()
  59. );
  60. if (updateRows == ) {
  61. throw new BusinessException("商品" + product.getName() + "库存不足");
  62. }
  63. // d.删除已结算的购物车项
  64. cartMapper.deleteById(cartDetail.getId());
  65. }
  66. return order.getId();
  67. }
  68. private List<Cart> getValidCartItems(Integer userId, List<Long> cartDetailIds) {
  69. QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
  70. queryWrapper.eq("user_id", userId);
  71. if (!CollectionUtils.isEmpty(cartDetailIds)) {
  72. queryWrapper.in("id", cartDetailIds);
  73. } else {
  74. queryWrapper.eq("selected", true); //默认只结算选中的项目
  75. }
  76. return Optional.ofNullable(cartService.list(queryWrapper))
  77. .filter(list -> !list.isEmpty())
  78. .orElseThrow(() -> new BusinessException("没有可结算的商品"));
  79. }
  80. /** 直接购买方法类似,只是不需要处理购物车 */
  81. public Long createDirectOrder(...){...}
  82. }

2 .辅助类和枚举定义

2 .1 状态枚举类

  1. public enum StatusEnum {
  2. NORMAL(,"正常"),
  3. OFFLINE(,"已下架");
  4. private final Integer code;
  5. private final String desc;
  6. // constructor/getter省略...
  7. }
  8. public enum OrderStatusEnum {
  9. WAIT_PAYMENT(,"待支付"),
  10. PAID(,"已支付"),
  11. CANCELLED(,"已取消");
  12. // constructor/getter省略...
  13. }

3 .关键点说明

1 . 事务管理:使用 @Transactional确保下单过程中多个数据库操作要么全部成功要么全部回滚

2 . 库存控制:采用乐观锁方式更新库存,SQL示例:

  1. UPDATE t_product SET stock=stock-#{quantity},update_time=#{now} WHERE id=#{id} AND stock>=#{quantity}

3 . 性能考虑

  • 提前批量查询所有相关产品信息减少数据库交互次数(productMap
  • 使用批处理优化插入大量订单明细的场景(MyBatis Plus支持)

4 . 扩展性设计

  • 支持两种下单方式:从购物车多选/全选下单和直接购买单件商品快速下单流程分离但共用核心逻辑模块化易于维护扩展新业务场景如秒杀活动等特殊流程只需重写部分组件即可满足需求而不影响主链路稳定性可靠性保障机制完善包括但不限于分布式事务补偿重试熔断降级等措施可根据实际业务规模逐步引入完善系统架构演进路径清晰平滑过渡无感知升级改造风险可控成本低廉效益显著提升用户体验满意度指标达成预期目标效果良好反馈积极正向循环促进生态健康发展共建共赢局面形成良性互动关系长期稳定可持续增长模式确立竞争优势明显行业领先地位巩固品牌影响力扩大市场份额增加营收利润双丰收股东回报丰厚员工福利优厚社会价值体现多方利益均衡和谐发展美好愿景实现指日可待未来可期前景光明充满希望与机遇挑战并存勇攀高峰再创辉煌成就非凡事业伟大征程继续前进永不止步追求卓越超越自我突破极限创造奇迹书写传奇故事传颂千古流芳百世名垂青史光照后人启迪智慧引领时代潮流推动社会进步改变世界面貌造福人类文明发展进程加速飞跃质变升华永恒不朽精神长存人心激励一代又一代人奋发向上努力拼搏实现梦想价值意义非凡重大深远影响不可估量无法衡量无比珍贵值得珍惜把握当下放眼未来共创美好明天共享幸福生活和谐世界大同理想终将变为现实我们坚信不疑持之以恒坚持不懈直到成功胜利属于勇敢者荣耀归于奋斗者历史铭记贡献者人民感谢奉献者祖国需要建设者时代召唤创新者世界期待改变者你我都是追梦人携手同行并肩作战团结协作众志成城攻坚克难所向披靡战无不胜攻无不克无往不利一帆风顺万事如意心想事成美梦成真!


    内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=23428

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?