建议阅读前，先阅读《商城表设计-购物车》相关文档

我们的购物车只有一个表：`tz_basket` 非常简单，但是关联了非常多的表。比如：

- 购物车有商品，关联商品表
- 每个商品都有sku，关联sku表
- 一个购物车有多个店铺的商品，关联店铺表
- 一个购物车肯定是和用户有关的，关联用户表



我们对商品进行添加，修改，其实都很简单，最为让人难以理解的是如何将这些字段进行组合，关联满减满折等一系列的活动。

我们先来看下是如何获取商品信息的

```java
    @PostMapping("/info")
    @Operation(summary = "获取用户购物车信息" , description = "获取用户购物车信息，参数为用户选中的活动项数组,以购物车id为key")
    public ServerResponseEntity<List<ShopCartDto>> info(@RequestBody Map<Long, ShopCartParam> basketIdShopCartParamMap) {
        String userId = SecurityUtils.getUser().getUserId();

        // 更新购物车信息，
        if (MapUtil.isNotEmpty(basketIdShopCartParamMap)) {
            basketService.updateBasketByShopCartParam(userId, basketIdShopCartParamMap);
        }

        // 拿到购物车的所有item
        List<ShopCartItemDto> shopCartItems = basketService.getShopCartItems(userId);
        return ServerResponseEntity.success(basketService.getShopCarts(shopCartItems));

    }
```

这里面传了一个参数：`Map<Long, ShopCartParam> basketIdShopCartParamMap` 这里是当用户改变了某件商品的满减满折活动时，重新改变满减满折信息以后计算加个的一个方法。当然在开源是没有这个满减模块的，只有思路，具体实现需要靠自己了。

我们继续往下看，这里面`basketService.getShopCartItems(userId)`使用的直接是从数据库中获取的数据，而真正对满减满折、店铺等进行排列组合的，在于`basketService.getShopCarts(shopCartItems)` 这个方法。



我们进到`getShopCarts`方法内部，可以查看到一行代码`applicationContext.publishEvent(new ShopCartEvent(shopCart, shopCartItemDtoList));`，这里使用的事件的模式。这个事件的主要作用是用于对模块之间的解耦，比如我们清楚的知道当购物车需要计算价格的时候，需要满减模块的配合，进行“装饰”。最后将装饰回来的东西，返回给前端。 



我们现在看看购物车返回的数据`ServerResponseEntity<List<ShopCartDto>>`，我们清楚一个购物车是分多个店铺的，每一个店铺就是一个`ShopCartDto`，我们看下这个`bean`。

```java
@Data
public class ShopCartDto implements Serializable {

   @Schema(description = "店铺ID" , required = true)
   private Long shopId;

   @Schema(description = "店铺名称" , required = true)
   private String shopName;

   @Schema(description = "购物车满减活动携带的商品" , required = true)
   private List<ShopCartItemDiscountDto> shopCartItemDiscounts;

}
```

其实一个店铺下面是有多个商品的，但是根据京东的划分，每当有满减之类的活动时，满减活动的商品总是要归到一类的，所以，每个店铺下面是多个满减活动（`List<ShopCartItemDiscountDto>`），满减活动下面是多个商品（购物项`List<ShopCartItemDto>`），到此你就能明白了`ShopCartItemDiscountDto` 里面的`ChooseDiscountItemDto` 是什么东西了，这个是选中的满减项。

```java
public class ShopCartItemDiscountDto implements Serializable {

    @Schema(description = "已选满减项" , required = true)
    private ChooseDiscountItemDto chooseDiscountItemDto;

    @Schema(description = "商品列表" )
    private List<ShopCartItemDto> shopCartItems;
}
```

我们再留意`ShopCartItemDto` 这个`bean` ，发现还有这个东西：

```java
@Schema(description = "参与满减活动列表" )
private List<DiscountDto> discounts = new ArrayList<>();
```

其实购物车的每个购物项，都是有很多个满减的活动的，可以自主选择满减活动，然后进行组合，生成新的优惠。而在这选择新的活动类型时，就需要购物车就行新的价格计算。这也就是为什么获取用户购物车信息，也就是`/info`接口需要一个这个参数的原因了`Map<Long, ShopCartParam> basketIdShopCartParamMap`
