一、购物车需求分析:

1.1 购物车存储数据结构如下:

image.png

购物车实现的核心思想:

根据京东购物车的改版,我们也做成了要求登录版的购物车,即所有购物商品的用户必须登录。这使用的是cas单点登录。

1.2 数据模型Cart声明如下:

  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. public class Cart implements Serializable {
  5. private String sellerId; //商家id
  6. private String sellerName; //商家名称
  7. private List<OrderItemEntity> orderItemList; //订单项列表
  8. }

二、新建模块

zyg-cart-interface / zyg-cart-service / zyg-cart-web
image.png
image.png
image.png

说明: 1、在zyg-cart-service中引入redis的依赖就可以,其它与普通服务一样。 2、在zyg-cart-web中引入cas与security的依赖,可以参考zyg-user-web模块,将相关的单点登录的登录引入。

三、添加购物车功能的实现

3.1 在zyg-cart-service模块中定义添加到购物车的方法:

  1. /**
  2. * ------------------------------
  3. * 功能:
  4. * 作者:WF
  5. * 微信:hbxfwf13590332912
  6. * 创建时间:2021/8/13-14:47
  7. * ------------------------------
  8. */
  9. @Service
  10. public class CartServiceImpl implements CartService {
  11. @Autowired
  12. private StringRedisTemplate redisTemplate;
  13. @Autowired
  14. private ItemDao itemDao;
  15. /**
  16. * 功能: 添加商品到购物车
  17. * 参数:
  18. * 返回值: java.util.List<com.zelin.entity.group.Cart>
  19. * 时间: 2021/8/13 14:47
  20. */
  21. @Override
  22. public List<Cart> addCart(String name, Long itemId, int num) {
  23. //第一步:得到购物车列表
  24. //1.1 根据skuid得到sku商品对象
  25. ItemEntity itemEntity = itemDao.selectById(itemId);
  26. //1.2 得到商家id
  27. String sellerId = itemEntity.getSellerId();
  28. //1.3 从redis中读取购物车列表(字符串形式)
  29. String cartListString = redisTemplate.opsForValue().get(name);
  30. //1.4 将购物车列表转换为List<Cart>这种数据
  31. List<Cart> cartList = null;
  32. if(StringUtils.isBlank(cartListString)) {
  33. cartListString = "[]";
  34. }
  35. cartList = JSON.parseArray(cartListString, Cart.class);
  36. //第二步:根据itemId查询在某个购物车中是否存在此商品,有就返回此购物车
  37. //2.1 遍历购物车列表,根据sellerId查找购物车
  38. Cart cart = findCartBySellerId(cartList,sellerId);
  39. //2.2 如要没有购物车,就构造一个,有就修改购物车中的购物项集合
  40. if(cart == null){ //如果没有就创建
  41. cart = createCart(itemEntity,num);
  42. //放到购物车集合列表中
  43. cartList.add(cart);
  44. }else{ //如果有就修改此购物车
  45. //2.3 判断在此购物车的购物项集合中是否有此itemId对应的购物项
  46. OrderItemEntity orderItem = findOrderItemByItemId(cart,itemId);
  47. //2.4 如果有此购物项,就修改它的数量及金额
  48. if(orderItem != null){
  49. orderItem.setNum(orderItem.getNum() + num); //修改数量
  50. orderItem.setTotalFee(new BigDecimal(orderItem.getNum() * orderItem.getPrice().doubleValue())); //修改小计
  51. }else{ //2.5 没有此商品就创建此商品并放到购物车的购物项集合中
  52. //2.5.1 构造item对象
  53. OrderItemEntity item = createOrderItem(itemEntity, num);
  54. //2.5.2 将此item放到购物车的购物项集合中
  55. cart.getOrderItemList().add(item);
  56. }
  57. //其它一些兼容性处理
  58. //① 如果购物车中没有购物项,要从购物车列表中移除此购物项
  59. if(cart.getOrderItemList().size() == 0){
  60. cartList.remove(cart);
  61. }
  62. //② 如果某个购物车的购物项的数量为0,要从购物车的购物项中移除此购物项
  63. if(orderItem != null && orderItem.getNum() == 0){
  64. cart.getOrderItemList().remove(orderItem);
  65. }
  66. }
  67. //将购物车列表放到redis中
  68. redisTemplate.opsForValue().set(name,JSON.toJSONString(cartList),10, TimeUnit.DAYS);
  69. return cartList;
  70. }
  71. /**
  72. * 功能: 在购物车的购物项列表中查询是否指定itemid对应的购物项
  73. * 参数:
  74. * 返回值: com.zelin.entity.OrderItemEntity
  75. * 时间: 2021/8/13 15:16
  76. */
  77. private OrderItemEntity findOrderItemByItemId(Cart cart, Long itemId) {
  78. for (OrderItemEntity itemEntity : cart.getOrderItemList()) {
  79. if (itemEntity.getItemId().longValue() == itemId.longValue()) {
  80. return itemEntity;
  81. }
  82. }
  83. return null;
  84. }
  85. /**
  86. * 功能: 创建一个新的购物车
  87. * 参数:
  88. * 返回值: com.zelin.entity.group.Cart
  89. * 时间: 2021/8/13 15:04
  90. */
  91. private Cart createCart(ItemEntity itemEntity, int num) {
  92. //1. 创建购物车对象
  93. Cart cart = new Cart();
  94. cart.setSellerId(itemEntity.getSellerId());
  95. cart.setSellerName(itemEntity.getSeller());
  96. List<OrderItemEntity> orderItemList = new ArrayList<>();
  97. OrderItemEntity item = createOrderItem(itemEntity, num);
  98. //3. 将item放到orderItemList中
  99. orderItemList.add(item);
  100. //2. 将orderItemList设置到购物车的购物项集合
  101. cart.setOrderItemList(orderItemList);
  102. //3. 返回
  103. return cart;
  104. }
  105. /**
  106. * 功能: 创建订单项方法
  107. * 参数:
  108. * 返回值: void
  109. * 时间: 2021/8/13 15:11
  110. */
  111. private OrderItemEntity createOrderItem(ItemEntity itemEntity, int num) {
  112. //1. 定义OrderItemEntity对象
  113. OrderItemEntity item = new OrderItemEntity();
  114. item.setGoodsId(itemEntity.getGoodsId());
  115. item.setItemId(itemEntity.getId());
  116. item.setNum(num);
  117. item.setPrice(itemEntity.getPrice());
  118. item.setTitle(itemEntity.getTitle());
  119. item.setPicPath(itemEntity.getImage());
  120. item.setTotalFee(item.getPrice().multiply(new BigDecimal(num))); //小计
  121. //2. 返回
  122. return item;
  123. }
  124. /**
  125. * 功能: 从购物车列表中根据商家id查询出购物车对象
  126. * 参数:
  127. * 返回值: com.zelin.entity.group.Cart
  128. * 时间: 2021/8/13 15:02
  129. */
  130. private Cart findCartBySellerId( List<Cart> cartList ,String sellerId) {
  131. for (Cart cart : cartList) {
  132. if (cart.getSellerId().equals(sellerId)) {
  133. return cart;
  134. }
  135. }
  136. return null;
  137. }
  138. }

3.2 在控制器cartController中定添加到购物车方法

  1. @Controller
  2. @RequestMapping("cart")
  3. public class CartController {
  4. @Reference(timeout = 5000)
  5. public CartService cartService;
  6. //1. 添加商品到购物车中
  7. @RequestMapping("/addCart")
  8. public String addCart(Long itemId, int num, Model model){
  9. //1.0 得到登录名
  10. String name = SecurityContextHolder.getContext().getAuthentication().getName();
  11. System.out.println("name = " + name);
  12. //1.1 将指定的sku商品添加到购物车列表中
  13. List<Cart> cartList = cartService.addCart(name,itemId,num);
  14. System.out.println("cartList = " + cartList);
  15. //1.2 将购物车集合放到model中,送到模板中显示
  16. model.addAttribute("cartList",cartList);
  17. //1.3 返回页面
  18. return "cart";
  19. }
  20. }

四、展示购物车:

4.1 前端计算购物车的总数量与总金额

  1. <script th:inline="javascript">
  2. $(function() {
  3. //1. 得到购物车数据
  4. let cartList = [[${cartList}]];
  5. //2. 遍历购物车集合计算总金额及总数量
  6. let totalNum = 0; //商品总数量
  7. let totalMoney = 0; //商品总金额
  8. cartList.forEach(cart=>{
  9. let items = cart.orderItemList;
  10. items.forEach(item=>{
  11. totalNum += item.num;
  12. totalMoney += item.totalFee;
  13. })
  14. })
  15. //3. 为控件赋值
  16. $("#goodsNum").html(totalNum)
  17. $("#goodsPrice").html("¥" + totalMoney);
  18. })
  19. </script>

4.2 前端展示数据

  1. <div class="toolbar">
  2. <div class="chosed">已选择<span id="goodsNum">xxx</span>件商品</div>
  3. <div class="sumprice">
  4. <span><em>总价(不含运费) :</em><i class="summoney" id="goodsPrice">¥16283.00</i></span>
  5. <span><em>已节省:</em><i>-¥20.00</i></span>
  6. </div>
  7. <div class="sumbtn">
  8. <a class="sum-btn" href="/static/cart/getOrderInfo.html" target="_blank">结算</a>
  9. </div>
  10. </div>

4.3 页面展示效果:

image.png