代码模块化

该代码实现了一个秒杀系统的同步下单过程,包括用户排队、消息队列、Redis存储和库存扣减。同时,展示了普通订单的创建,涉及远程调用、库存扣除和延迟消息。另外,提到了商品详情页的异步加载和自定义注解AOP缓存处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、秒杀代码

/***
 * 秒杀订单的接口类的实现类
 */
@Service
public class SeckillOrderServiceImpl implements SeckillOrderService {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Resource
    private SeckillOrderMapper seckillOrderMapper;

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 秒杀假下单,真排队:同步下单
     *
     * @param time
     * @param goodsId
     * @param num
     * @return
     */
    @Override
    public UserRecode addSeckillOrder(String time, String goodsId, Integer num) {
        // 排队:记录这些信息,进行排队
        UserRecode userRecode = new UserRecode();
        String username = ThreadLocalUtil.get();
        // 限制用户的排队次数,每个用户每次只能排一次
        Long increment = redisTemplate.opsForValue().increment("User_Recode_Count_" + username, 1);
        if (increment > 1) {
            userRecode.setStatus(3);
            userRecode.setMsg("重复排队,秒杀失败");
            return userRecode;
        }
        userRecode.setTime(time);
        userRecode.setGoodsId(goodsId);
        userRecode.setNum(num);
        userRecode.setUsername(ThreadLocalUtil.get());
        userRecode.setCreateTime(new Date());
        CompletableFuture.runAsync(() -> {
            // 将用户的排队信息存储到redis:提供一会查询
            /**
             * 问题:
             * a.value:1.key会非常多 2.数据多恢复速度慢
             * b.hash:redis大key问题--》1.redis卡死,2.效率会随着hkey的数量增加而导致效率越来越慢3.数据丢失风险4.回复速度慢
             */
            redisTemplate.opsForValue().set("User_Recode_Info_" + username, userRecode);
            // 生产者:消息队列-->相对公平
            rabbitTemplate.convertAndSend("seckill_order_exchange", "seckill.order", JSONObject.toJSONString(userRecode));
            // 设置排队计数器(防止用户不能排队):设置这个计数器的过期时间为15分钟
            redisTemplate.expire("User_Recode_Count" + username, 300, TimeUnit.SECONDS);
        }, threadPoolExecutor).whenCompleteAsync((a, b) -> {
            // 保持排队消息或发送排队的消息失败,删除用户的排队计数器
            if (b != null) {
                // 告诉用户排队失败
                userRecode.setStatus(3);
                userRecode.setMsg("排队失败,请重新排队");
                redisTemplate.opsForValue().set("User_Recode_Info_" + username, userRecode);
                // 删除排队计数器:不影响用户失败的情况下买其他东西
                redisTemplate.delete("User_Recode_Count_" + username);
            }
        });

        // 返回:排队结果
        return userRecode;
    }

    /**
     * 异步下单
     *
     * @param userRecodeString
     */
    @Override
    public void realSeckillOrderAdd(String userRecodeString) {
        // 反序列化
        UserRecode userRecode = JSONObject.parseObject(userRecodeString, UserRecode.class);
        // 获取用户名
        String username = userRecode.getUsername();
        // 获取时间段
        String time = userRecode.getTime();
        // 是否是当前活动时间段
        String nowTime = DateUtil.data2str(DateUtil.getDateMenus().get(0), DateUtil.PATTERN_YYYYMMDDHH);
        if (!time.equals(nowTime)) {
            // 不在活动时间以内:秒杀失败!
            seckillOrderFail(userRecode, "秒杀的商品不在活动的时间以内");
            return;
        }
        // 获取商品id
        String goodsId = userRecode.getGoodsId();
        // 判断商品是否存在
        SeckillGoods seckillGoods = (SeckillGoods) redisTemplate.opsForHash().get(time, goodsId);
        if (seckillGoods == null) {
            // 商品不存在
            seckillOrderFail(userRecode, "商品不存在");
            return;
        }
        // 获取购买的数量
        Integer num = userRecode.getNum();
        // 判断数量是否正确以及数量是否超出
        if (num <= 0) {
            // 商品购买数量错误
            seckillOrderFail(userRecode, "商品购买数量错误");
            return;
        }
        // 是否超出限购
        if (num > seckillGoods.getSeckillLimit()) {
            // 商品购买超出限购--
            seckillOrderFail(userRecode, "商品购买超出限购");
            return;
        }
        // 库存是否足够:pop一次出列一个----方案一:循环pop
        /**
         * 问题:
         * 1.只有最后几个剩余库存可能触发多次问题
         * 2.后来的人比先来的买到(无所谓--公平问题--相对公平--》目的:卖出去!!!)
         * 3.可能原本有,但是没抢到
         * 4.对这个key的写操作会增加
         * 有点:
         * 1.解决超卖:安全
         * 2。代码效率高,逻辑效率也高
         */
        for (int i = 0; i < num; i++) {
            Object o =
                    redisTemplate.opsForList().rightPop("Seckill_Goods_Stock_Queue_" + goodsId);
            if (o == null) {
                if (i > 0) {
                    // 回滚
                    redisTemplate.opsForList().leftPushAll("Seckill_Goods_Stock_Queue_" + goodsId, StockUtil.getIds(i));
                }
                // 库存不足
                seckillOrderFail(userRecode, "库存不足");
                return;
            }
        }
        // ----方案二:
        /**
         * 问题:
         * 1.redis的key的操作减少2次
         * 2.安全
         * 3.代码效率高,逻辑也高
         * 有点:
         * 1. 只有最后几个剩余库存可能触发多次回滚
         * 2. 后来的人比先来的买到
         * 3. 最后几个可能永远卖不出去
         */
        // 修改商品的最新库存:1个
        Long increment = redisTemplate.opsForHash().increment("Seckill_Goods_Stock_Count_" + time, goodsId, -num);
//        if (increment < 0) {
//            // 回滚
//            redisTemplate.opsForHash().increment("Seckill_Goods_Stock_Count_" + time, goodsId, num);
//            // 库存不足
//            seckillOrderFail(userRecode, "库存不足");
//            return;
//        }

        // 生成秒杀订单
        SeckillOrder seckillOrder = new SeckillOrder();
        seckillOrder.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        seckillOrder.setGoodsId(goodsId);
        seckillOrder.setMoney(seckillGoods.getCostPrice().multiply(new BigDecimal(num)));
        seckillOrder.setUserId(username);
        seckillOrder.setCreateTime(new Date());
        seckillOrder.setStatus(OrderStatus.UNPAID.getComment());
        seckillOrder.setNum(num);
        // 将秒杀的订单存储:redis--》订单入库的时间:1.支付 2.主动取消 3.超时取消
        redisTemplate.opsForHash().put("Seckill_Order_" + time, seckillOrder.getId(), seckillOrder);
        // 修改用户的排队状态
        userRecode.setStatus(2);
        userRecode.setMsg("秒杀成功,等待支付!");
        userRecode.setOrderId(seckillOrder.getId());
        userRecode.setMoney(seckillOrder.getMoney().doubleValue() + "");
        redisTemplate.opsForValue().set("User_Recode_Info_" + userRecode.getUsername(), userRecode);
        seckillGoods.setStockCount(increment.intValue());
        redisTemplate.opsForHash().put(time, goodsId, seckillGoods);
        // 延迟消息
        rabbitTemplate.convertAndSend(
                "seckill_order_delay_exchange",
                "seckill.order.dead",
                username + "",
                (message -> {
                    // 获取消息的属性
                    MessageProperties messageProperties = message.getMessageProperties();
                    // 设置过期的时间
                    messageProperties.setExpiration(50000 + "");
                    // 返回
                    return message;
                })
        );
    }

2、普通新增订单

  /**
     * 新增订单
     *
     * @param orderInfo
     */
    @Override
    public void addOrder(OrderInfo orderInfo) {
        // 获取锁
        RLock lock = redissonClient.getLock("Add_Order_Lock_" + ThreadLocalUtil.get());
        try {
            // 尝试加锁:只有一次机会
            if (lock.tryLock()) {
                // 加锁成功
                try {
                    // 防止死锁的兜底
                    redisTemplate.expire("Add_Order_Lock_" + ThreadLocalUtil.get(), 60, TimeUnit.SECONDS);
                    // 参数校验
                    if (orderInfo == null) {
                        throw new GmallException("参数错误,新增订单失败", 201);
                    }
                    // 远程调用购物车微服务,获取购物车列表和总金额
                    Map<String, Object> result = cartFeign.getOrderAddInfo();
                    if (result == null)
                        throw new GmallException("本次未勾选任何购物车数据,新增订单失败", 201);
                    // 补全订单对象的属性
                    orderInfo.setTotalAmount(new BigDecimal(result.get("totalMoney").toString()));
                    orderInfo.setOrderStatus(OrderStatus.UNPAID.getComment());
                    orderInfo.setUserId(ThreadLocalUtil.get());
                    orderInfo.setCreateTime(new Date());
                    orderInfo.setExpireTime(new Date(System.currentTimeMillis() + 1800000));
                    orderInfo.setProcessStatus(ProcessStatus.UNPAID.getComment());
                    // 保存订单数据
                    int insert = orderInfoMapper.insert(orderInfo);
                    if (insert <= 0) {
                        throw new GmallException("新增订单发送异常,失败,请重试!", 201);
                    }
                    // 获取订单号
                    Long orderId = orderInfo.getId();
                    // 通过购物车数据包装订单的详情数据,并且保存
                    List cartInfoList = (List) result.get("cartInfoList");
                    Map decountMap = saveOrderDetail(orderId, cartInfoList);
                    // 清空本次购物车数据
//                    if (!cartFeign.clearCart()) {
//                        throw new GmallException("清空购物车失败", 201);
//                    }
                    // -扣减库存
                    if (!productFeign.decountStock(decountMap)) {
                        throw new GmallException("库存不足", 201);
                    }
                    // 发送延迟消息
                    rabbitTemplate.convertAndSend(
                            "order_nomal_exchange",// 交换机
                            "order.nomal",// routingkey
                            orderId + "",// 消息的内容
                            (message) -> {
                                // 获取消息的属性
                                MessageProperties messageProperties = message.getMessageProperties();
                                // 设置过期时间
                                messageProperties.setExpiration(1800000 + "");
                                // 返回
                                return message;
                            }
                    );
                } catch (Exception e) {
                    log.error("商品不足,下单失败" + e.getMessage());
                    throw e;
                } finally {
                    // 释放锁
                    lock.unlock();
                }
            } else {
                throw new GmallException("重复下单!", 201);
            }
        } catch (Exception e) {
            throw e;
        }
        //  结束
    }
     /**
     * 保存订单的详情数据
     *
     * @param orderId
     * @param cartInfoList
     * @return
     */
    private Map saveOrderDetail(Long orderId, List cartInfoList) {
        Map decountMap = new ConcurrentHashMap<>();
        // 遍历保存订单的详情的数据,同时统计需要加减的库存数据
        cartInfoList.stream().forEach(o -> {
            // 序列化
            String s = JSONObject.toJSONString(o);
            // 反序列化
            CartInfo cartInfo = JSONObject.parseObject(s, CartInfo.class);
            // 初始化订单详情
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(orderId);
            orderDetail.setSkuId(cartInfo.getSkuId());
            orderDetail.setSkuName(cartInfo.getSkuName());
            orderDetail.setImgUrl(cartInfo.getImgUrl());
            orderDetail.setOrderPrice(cartInfo.getSkuPrice());
            orderDetail.setSkuNum(cartInfo.getSkuNum());
            // 保存
            int insert = orderDetailMapper.insert(orderDetail);
            if (insert <= 0) {
                throw new GmallException("新增详情发送异常,失败,请重试", 201);
            }
            // 保存这个扣减的数据
            decountMap.put(cartInfo.getSkuId() + "", cartInfo.getSkuNum());
        });
        return decountMap;
    }

3、商品详情页

/***
 * 商品详情页使用的接口的实现类
 */
@Service
public class ItemServiceImpl implements ItemService {
    @Autowired
    private ProductFeign productFeign;

    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;


    /**
     * 查询商品详情页面需要的全部数据
     *
     * @param skuId
     * @return
     */
    @Override
    public Map<String, Object> getItemPageInfo(Long skuId) {
        // 返回结果类型
        Map<String, Object> result = new ConcurrentHashMap<>();
        // 参数效验
        if (skuId == null)
            return null;
        // 查询skuInfo,判断商品是否存在
        CompletableFuture<SkuInfo> future1 = CompletableFuture.supplyAsync(() -> {
            SkuInfo skuInfo = productFeign.getSkuInfo(skuId);
            // 商品不存在,返回空
            if (skuInfo == null || skuInfo.getId() == null)
                return null;
            // 保存sku 信息
            result.put("skuInfo", skuInfo);
            return skuInfo;
        },threadPoolExecutor);

        // 查询分类信息
        CompletableFuture<Void> future2 = future1.thenAcceptAsync((skuInfo) -> {
            // 商品不存在,返回空
            if (skuInfo == null || skuInfo.getId() == null)
                return;
            // 查询分类
            Long category3Id = skuInfo.getCategory3Id();
            BaseCategoryView category = productFeign.getCategory(category3Id);
            result.put("category", category);
        },threadPoolExecutor);

        // 查询商品图片
        CompletableFuture<Void> future3 = future1.thenAcceptAsync((skuInfo) -> {
            // 商品不存在,返回空
            if (skuInfo == null || skuInfo.getId() == null)
                return;
            List<SkuImage> skuImages = productFeign.getSkuImages(skuId);
            result.put("skuImages", skuImages);
        },threadPoolExecutor);
        // 查询商品价格
        CompletableFuture<Void> future4 = future1.thenAcceptAsync((skuInfo) -> {
            //商品不存在,结束返回空
            if (skuInfo == null || skuInfo.getId() == null) {
                return;
            }
            BigDecimal skuPrice = productFeign.getPrice(skuId);
            result.put("skuPrice", skuPrice);
        },threadPoolExecutor);

        // 查询当前商品所属的spu的全部销售属性,并标识出当前商品拥有哪几个属性值
        CompletableFuture<Void> future5 = future1.thenAcceptAsync((skuInfo) -> {
            //商品不存在,结束返回空
            if (skuInfo == null || skuInfo.getId() == null) {
                return;
            }
            Long spuId = skuInfo.getSpuId();
            List<SpuSaleAttr> spuSaleAttrsList = productFeign.getSpuSaleAttr(skuId, spuId);
            result.put("spuSaleAttrsList", spuSaleAttrsList);
        },threadPoolExecutor);
        CompletableFuture<Void> future6 = future1.thenAcceptAsync((skuInfo) -> {
            // 商品不存在,结束返回空
            if (skuInfo == null || skuInfo.getId() == null) {
                return;
            }
            // 点击获取到固定商品
            Map skuKeyAndValue = productFeign.getSkuKeyAndValue(skuInfo.getSpuId());
            result.put("skuKeyAndValue", skuKeyAndValue);
        },threadPoolExecutor);
        // 全部任务结束
        CompletableFuture.allOf(future2, future3, future4, future5, future6).join();
        // 将以上的所有的结果整合,返回
        return result;
    }
}

3.1自定义注解

/***
 * 自定义注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Java1126GmallCache {
    String prefix() default "cache";
}

3.2 aop切面类

/***
 * 自定义切面类
 */
@Component
@Aspect
public class GmallCacheAspect {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 增强方法,环绕监听
     *
     * @param point:切点
     * @return
     */
    @Around("@annotation(com.atguigu.gmall.common.cache.Java1126GmallCache)")
    public Object cacheAroundAdvice(ProceedingJoinPoint point) {
        // 返回接口初始化
        Object result = null;
        try {
            // 获取方法的参数
            Object[] args = point.getArgs();
            // 获取方法签名
            MethodSignature signature = (MethodSignature) point.getSignature();
            // 通过签名获取方法的注解
            Java1126GmallCache gmallCache = signature.getMethod().getAnnotation(Java1126GmallCache.class);
            // 获取注解的前缀属性
            String prefix = gmallCache.prefix();
            // 拼key
            String key = prefix + Arrays.asList(args).toString();
            // 从redis中数据

            result = cacheHit(signature, key);
            // 判断redis是否有数据
            if (result != null) {
                // 缓存有数据
                return result;
            }
            // 初始化分布式锁
            RLock lock = redissonClient.getLock(key + ":lock");
            // 加锁
            boolean flag = lock.tryLock(100, 100, TimeUnit.SECONDS);
            if (flag) {
                try {
                    try {
                        // 执行方法:查询数据库
                        result = point.proceed(point.getArgs());
                        // 防止缓存穿透
                        if (null == result) {
                            // 并把结果放入缓存
                            // 1.获取字节码
                            Class<?> returnType = signature.getReturnType();
                            // 2.通过无参构造函数创建对象
                            result = returnType.getDeclaredConstructor().newInstance();
                            this.redisTemplate.opsForValue().set(key, JSONObject.toJSONString(result), 300, TimeUnit.SECONDS);
                        } else {
                            this.redisTemplate.opsForValue().set(key, JSONObject.toJSONString(result), 24 * 60 * 60, TimeUnit.SECONDS);
                        }
                    } catch (Throwable throwable) {
                        throwable.printStackTrace();
                    }
                    // 并把结果放入缓存
                    return result;
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    // 释放锁
                    lock.unlock();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //boolean flag = lock.tryLock(10L, 10L, TimeUnit.SECONDS);
        return result;
    }

    /**
     * 从redis中获取数据
     *
     * @param signature:签名
     * @param key:redis中的key
     * @return
     */
    private Object cacheHit(MethodSignature signature, String key) {
        // 1. 查询缓存
        String cache = (String) redisTemplate.opsForValue().get(key);
        if (StringUtils.isNotBlank(cache)) {
            // 有,则反序列化,直接返回
            Class returnType = signature.getReturnType(); // 获取方法返回类型
            // 不能使用parseArray<cache, T>,因为不知道List<T>中的泛型
            return JSONObject.parseObject(cache, returnType);
        }
        return null;
    }

}

4、product

/**
     * 查询首页分类的信息
     *
     * @return
     */
    @Override
    public List<JSONObject> getIndexCategory() {
        // 查询所有的分类信息:一级二级三级
        List<BaseCategoryView> baseCategory1ViewList = baseCategoryViewMapper.selectList(null);
        // 根据一级分类进行分桶
        Map<Long, List<BaseCategoryView>> category1Map = baseCategory1ViewList.stream().collect(Collectors.groupingBy(BaseCategoryView::getCategory1Id));
        // 对一级分类分出来的桶进行遍历
        return category1Map.entrySet().stream().map(category1 -> {
            JSONObject category1Json = new JSONObject();
            // 获取key,一级分类的id
            Long category1Id = category1.getKey();
            category1Json.put("categoryId", category1Id);
            // 获取这个一级分类对应的全部的二级和三级分类
            List<BaseCategoryView> baseCategory2ViewList = category1.getValue();
            String category1Name = baseCategory2ViewList.get(0).getCategory1Name();
            category1Json.put("categoryName", category1Name);
            // 继续对二级分类进行分桶
            Map<Long, List<BaseCategoryView>> category2Map = baseCategory2ViewList.stream().collect(Collectors.groupingBy(BaseCategoryView::getCategory2Id));
            // 遍历分桶出来的每个二级分类的map
            List<JSONObject> category2JsonList = category2Map.entrySet().stream().map(category2 -> {
                JSONObject category2Json = new JSONObject();
                // 获取二级分类id
                Long category2Id = category2.getKey();
                category2Json.put("categoryId", category2Id);
                // 获取这个二级分来对应的全部三级分类
                List<BaseCategoryView> baseCategory3ViewList = category2.getValue();
                // 获取二级分类的名字
                String category2Name = baseCategory3ViewList.get(0).getCategory2Name();
                category2Json.put("categoryName", category2Name);
                // 遍历获取每个三级分类的名字和id
                List<JSONObject> category3JsonList = baseCategory3ViewList.stream().map(category3 -> {
                    JSONObject category3Json = new JSONObject();
                    // 获取三级分类的id
                    Long category3Id = category3.getCategory3Id();
                    category3Json.put("categoryId", category3Id);
                    // 获取三级分类的名字
                    String category3Name = category3.getCategory3Name();
                    category3Json.put("categoryName", category3Name);
                    // 返回
                    return category3Json;
                }).collect(Collectors.toList());
                // 保存这个二级分类对应的全部三级分类
                category2Json.put("childCategory", category3JsonList);
                // 返回
                return category2Json;
            }).collect(Collectors.toList());
            // 保存这个一级分类对应的全部二级分类
            category1Json.put("childCategory", category2JsonList);
            // 返回这个一级分类
            return category1Json;
        }).collect(Collectors.toList());
    }

5、购物车


/***
 * 购物车相关的接口实现类
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class CartInfoServiceImpl implements CartInfoService {
    @Autowired
    private ProductFeign productFeign;
    @Resource
    private CartInfoMapper cartInfoMapper;

    /**
     * 新增购物车
     *
     * @param skuId
     * @param num
     */
    @Override
    public void addCart(Long skuId, Integer num) {
        // 参数校验
        if (skuId == null || num == null) {
            throw new GmallException("新增购物车失败,参数错误", 201);
        }
        // 查询商品的数据
        SkuInfo skuInfo = productFeign.getSkuInfo(skuId);
        // 判断商品是否存在
        if (skuInfo == null || skuInfo.getId() == null) {
            throw new GmallException("新增购物车失败,商品不存在", 201);
        }
        // 获取用户名
        String username = ThreadLocalUtil.get();
        // 查询用户的购物车中有没有这个商品
        CartInfo cartInfo = cartInfoMapper.selectOne(
                new LambdaQueryWrapper<CartInfo>()
                        .eq(CartInfo::getUserId, username)
                        .eq(CartInfo::getSkuId, skuId));
        if (cartInfo == null || cartInfo.getSkuId() == null) {
            // 保证数量大于0
            if (num <= 0) {
                throw new GmallException("新增购物车失败,数量错误", 201);
            }
            num = num > 199 ? 199 : num;
            // 新增购物车
            // 包装购物车对象
            cartInfo = new CartInfo();
            cartInfo.setUserId(username);
            cartInfo.setSkuId(skuId);
            // 查询价格
            BigDecimal price = productFeign.getPrice(skuId);
            cartInfo.setCartPrice(price);
            cartInfo.setSkuNum(num);
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            // 将购物车对象保存到数据库中
            int insert = cartInfoMapper.insert(cartInfo);
            if (insert <= 0) {
                throw new GmallException("新增购物车失败,请重试", 201);
            }
        } else {
            num = cartInfo.getSkuNum() + num;
            if (num <= 0) {
                // 删除购物车
                int delete = cartInfoMapper.deleteById(cartInfo.getId());
                if (delete < 0) {
                    throw new GmallException("新增购物车失败,请重试", 201);
                }
            } else {
                // 合并数量
                num = num > 199 ? 199 : num;
                cartInfo.setSkuNum(num);
                int i = cartInfoMapper.updateById(cartInfo);
                if (i < 0) {
                    throw new GmallException("新增购物车失败,请重试", 201);
                }
            }
        }
    }

    /**
     * 合并购物车
     *
     * @param cartInfoList
     */
    @Override
    public void mergeCart(List<CartInfo> cartInfoList) {
        // 防止空指针
        if (cartInfoList == null || cartInfoList.isEmpty())
            return;
        // 合并
        cartInfoList.stream().forEach(cartInfo -> {
            this.addCart(cartInfo.getSkuId(), cartInfo.getSkuNum());
        });
    }

    /**
     * 查询订单确认页面使用的数据
     *
     * @return
     */
    @Override
    public Map<String, Object> getOrderConfirmInfo() {
        // 查询本次登陆用户的选中的购物车数据
        List<CartInfo> cartInfoList =
                cartInfoMapper.selectList(
                        new LambdaQueryWrapper<CartInfo>()
                                .eq(CartInfo::getUserId, ThreadLocalUtil.get())
                                .eq(CartInfo::getIsChecked, CartConst.CART_CHECK)
                );
        if (cartInfoList == null && cartInfoList.isEmpty()) {
            return null;
        }
        // 根据本次查询到的购物车列表获取总数量和总金额
        AtomicInteger totalNum = new AtomicInteger(0);
        AtomicDouble totalMoney = new AtomicDouble(0);
        List<CartInfo> cartInfoListNew = cartInfoList.stream().map(cartInfo -> {
            // 获取这笔购物车的商品id
            Long skuId = cartInfo.getSkuId();
            // 查询实时价格
            BigDecimal price = productFeign.getPrice(skuId);
            // 保存实时价格页面展示
            cartInfo.setSkuPrice(price);
            // 获取本笔购物车购买的数量
            totalNum.getAndAdd(cartInfo.getSkuNum());
            // 计算这笔购物车的金额
            totalMoney.getAndAdd(price.multiply(new BigDecimal(cartInfo.getSkuNum())).doubleValue());
            // 返回
            return cartInfo;
        }).collect(Collectors.toList());
        // 保存全部数据的返回
        Map<String, Object> result = new HashMap<>();
        result.put("totalNum", totalNum);
        result.put("totalMoney", totalMoney);
        result.put("cartInfoList", cartInfoListNew);
        return result;
    }

    /**
     * 下单后清理每次购买的购物车数据
     */
    @Override
    public void clearCart() {
        int delete =
                cartInfoMapper.delete(
                        new LambdaQueryWrapper<CartInfo>()
                                .eq(CartInfo::getUserId, ThreadLocalUtil.get())
                                .eq(CartInfo::getIsChecked, CartConst.CART_CHECK));
        if (delete < 0) {
            throw new GmallException("清理购物车失败", 201);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值