## 订单接口-1 用户下单时调用的订单接口有两个: 1、确认订单[生成订单信息] 2、提交订单[此时默认支付成功] ### 1.确认订单 确认订单有以下几个步骤: 1、判断是购物车还是直接购买 2、组装购物项信息 3、根据店铺计算金额 4、计算总额 --- 用户通过点击"**立即购买**"或进入购物车选择"**结算**"进入到"**确认订单**"页面,具体接口:"`/a/order/confirm`" 由于有两种方式进入到确认订单界面,但本商城设计为一个接口处理,统一下单: ```java public class OrderDTO { @Schema(description = "立即购买时提交的商品项,如果该值为空,则说明是从购物车进入,如果该值不为空则说明为立即购买" ) private ShopCartItemDTO shopCartItem; @NotNull(message = "配送类型不能为空") @Schema(description = "配送类型3:无需快递" ) private Integer dvyType; } ``` 通过购物车适配器来**获取购物项组装信息** ```java public ServerResponseEntity> getShopCartItems(ShopCartItemDTO shopCartItemParam) { ServerResponseEntity> shopCartItemResponse; // 当立即购买时,没有提交的订单是没有购物车信息的 if (shopCartItemParam != null) { shopCartItemResponse = conversionShopCartItem(shopCartItemParam); } // 从购物车提交订单 else { shopCartItemResponse = shopCartFeignClient.getCheckedShopCartItems(); } if (!shopCartItemResponse.isSuccess()) { return ServerResponseEntity.transform(shopCartItemResponse); } // 请选择您需要的商品加入购物车 if (CollectionUtil.isEmpty(shopCartItemResponse.getData())) { return ServerResponseEntity.fail(ResponseEnum.SHOP_CART_NOT_EXIST); } // 返回购物车选择的商品信息 return shopCartItemResponse; } ``` 当购物项`shopCartItem`为空时,则说明是从购物车进入,此时调用获取**用户的购物车信息**的方法`shopCartFeignClient.getCheckedShopCartItems()`: ```java public ServerResponseEntity> getCheckedShopCartItems() { //该方法从数据库查询购物车的商品 List checkedShopCartItems = shopCartService.getCheckedShopCartItems(); if (CollectionUtil.isNotEmpty(checkedShopCartItems)) { for (ShopCartItemVO shopCartItem : checkedShopCartItems) { shopCartItem.setTotalAmount(shopCartItem.getCount() * shopCartItem.getSkuPriceFee()); } } return ServerResponseEntity.success(checkedShopCartItems); } ``` 而若`shopCartItem`不为空,则是直接购买进入该页面,调用`shopCartAdapter.conversionShopCartItem()`方法,组装购物信息: ```java public ServerResponseEntity> conversionShopCartItem(ShopCartItemDTO shopCartItemParam){ ServerResponseEntity spuAndSkuResponse = spuFeignClient.getSpuAndSkuById(shopCartItemParam.getSpuId(),shopCartItemParam.getSkuId()); if (!spuAndSkuResponse.isSuccess()) { return ServerResponseEntity.transform(spuAndSkuResponse); } SkuVO sku = spuAndSkuResponse.getData().getSku(); SpuVO spu = spuAndSkuResponse.getData().getSpu(); // 拿到购物车的所有item ShopCartItemVO shopCartItem = new ShopCartItemVO(); shopCartItem.setCartItemId(0L); shopCartItem.setSkuId(shopCartItemParam.getSkuId()); shopCartItem.setCount(shopCartItemParam.getCount()); shopCartItem.setSpuId(shopCartItemParam.getSpuId()); shopCartItem.setSkuName(sku.getSkuName()); shopCartItem.setSpuName(spu.getName()); shopCartItem.setImgUrl(BooleanUtil.isTrue(spu.getHasSkuImg()) ? sku.getImgUrl() : spu.getMainImgUrl()); shopCartItem.setSkuPriceFee(sku.getPriceFee()); shopCartItem.setTotalAmount(shopCartItem.getCount() * shopCartItem.getSkuPriceFee()); shopCartItem.setCreateTime(new Date()); shopCartItem.setShopId(shopCartItemParam.getShopId()); return ServerResponseEntity.success(Collections.singletonList(shopCartItem)); } ``` 两个路径的购物信息统一组装完毕后,不能在这一步删除购物车信息,万一用户点击返回后,发现购物车的商品虽然还没提交,但是已经消失,会造成信息差。 下一步,根据不同店铺来划分购物项,调用`shopCartAdapter.conversionShopCart()`: ```java public List conversionShopCart(List shopCartItems){ // 根据店铺ID划分item Map> shopCartMap = shopCartItems.stream().collect(Collectors.groupingBy(ShopCartItemVO::getShopId)); // 返回一个店铺的所有信息 List shopCarts = Lists.newArrayList(); for (Long shopId : shopCartMap.keySet()) { // 构建每个店铺的购物车信息 ShopCartVO shopCart = buildShopCart(shopId,shopCartMap.get(shopId)); shopCart.setShopId(shopId); shopCart.setShopCartItemVOS(shopCartMap.get(shopId)); // 店铺信息 ServerResponseEntity shopNameResponse = shopDetailFeignClient.getShopNameByShopId(shopId); if (!shopNameResponse.isSuccess()) { throw new mall4cloudException(shopNameResponse.getMsg()); } shopCart.setShopName(shopNameResponse.getData()); shopCarts.add(shopCart); } return shopCarts; } ``` 在`buildShopCart(shopId,shopCartMap.get(shopId))`的时候,根据每个店铺来划分商品,再计算每个店铺商品的全部金额: ```java private ShopCartVO buildShopCart(Long shopId, List shopCartItems) { ShopCartVO shopCart = new ShopCartVO(); shopCart.setShopId(shopId); long total = 0L; int totalCount = 0; for (ShopCartItemVO shopCartItem : shopCartItems) { total += shopCartItem.getTotalAmount(); totalCount += shopCartItem.getCount(); } shopCart.setTotal(total); shopCart.setTotalCount(totalCount); return shopCart; } ``` 此时根据店铺计算完金额后,在确认订单的时候,会重新计算一次总金额,返回给前端 ```java private void recalculateAmountWhenFinishingCalculateShop(ShopCartOrderMergerVO shopCartOrderMerger, List shopCarts) { // 所有店铺的订单信息 List shopCartOrders = new ArrayList<>(); long total = 0; int totalCount = 0; // 所有店铺所有的商品item for (ShopCartVO shopCart : shopCarts) { // 每个店铺的订单信息 ShopCartOrderVO shopCartOrder = new ShopCartOrderVO(); shopCartOrder.setShopId(shopCart.getShopId()); shopCartOrder.setShopName(shopCart.getShopName()); total += shopCart.getTotal(); totalCount += shopCart.getTotalCount(); shopCartOrder.setTotal(shopCart.getTotal()); shopCartOrder.setTotalCount(shopCart.getTotalCount()); shopCartOrder.setShopCartItemVO(shopCart.getShopCartItemVOS()); shopCartOrders.add(shopCartOrder); } shopCartOrderMerger.setTotal(total); shopCartOrderMerger.setTotalCount(totalCount); shopCartOrderMerger.setShopCartOrders(shopCartOrders); } ``` 最后,使用工具类对重复提交的订单做判断,并且将结果存入缓存中,提交订单时可取出使用: ```java // 防止重复提交 RedisUtil.STRING_REDIS_TEMPLATE.opsForValue().set(OrderCacheNames.ORDER_CONFIRM_UUID_KEY + CacheNames.UNION + userId, String.valueOf(userId)); // 保存订单计算结果缓存,省得重新计算并且用户确认的订单金额与提交的一致 cacheManagerUtil.putCache(OrderCacheNames.ORDER_CONFIRM_KEY,String.valueOf(userId),shopCartOrderMerger); ``` 提交订单的接口设计请看下节:**订单接口-2**