csmall

front模块

分类 service

@DubboService
@Service
@Slf4j
public class FrontCategoryServiceImpl implements IFrontCategoryService {

    // 项目中涉及Redis的信息读取,定义这个常量,降低拼写错误风险
    public static final String CATEGORY_TREE_KEY="category_tree";
    // 利用Dubbo获得可以连接数据库获得所有分类信息的业务逻辑层方法
    @DubboReference
    private IForFrontCategoryService dubboCategoryService;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public FrontCategoryTreeVO categoryTree() {
        // 凡是有Redis读取检查的都是这个模式
        if(redisTemplate.hasKey(CATEGORY_TREE_KEY)){
            // 如果Redis中包含分类树信息,直接从Redis中获取返回即可
            FrontCategoryTreeVO<FrontCategoryEntity> treeVO=
                    (FrontCategoryTreeVO<FrontCategoryEntity>)
                            redisTemplate.boundValueOps(CATEGORY_TREE_KEY).get();
            return treeVO;
        }
        // 如果Redis中没有数据,证明本次运行需要从数据库查询所有分类,拼接从三级分类树并返回
        // 首先一定是先要从数据库中查询所有分类对象
        List<CategoryStandardVO> categoryStandardVOs=
                                    dubboCategoryService.getCategoryList();
        // 将所有分类对象关联成三级分类树返回
        FrontCategoryTreeVO<FrontCategoryEntity> treeVO=initTree(categoryStandardVOs);
        // 将确定好的三级分类树保存到Redis
        redisTemplate.boundValueOps(CATEGORY_TREE_KEY)
                        .set(treeVO, 24 , TimeUnit.HOURS);
        // 千万别忘了返回!!!
        return treeVO;
    }

    private FrontCategoryTreeVO<FrontCategoryEntity> initTree(List<CategoryStandardVO> categoryStandardVOs) {
        // 第一部分,确定所有分类对象的父分类
        // 声明一个Map,这个map的Key是父分类的Id,这个Map的Value是当前父分类的所有子分类对象
        Map<Long,List<FrontCategoryEntity>> map=new HashMap<>();
        // 日志输出分类对象个数
        log.info("当前分类对象总数:{}",categoryStandardVOs.size());
        // 下面编写for循环,遍历categoryStandardVOs集合,将其中的所有元素保存到父分类id值对应的Map中
        // 根分类parentId是0
        for(CategoryStandardVO categoryStandardVO : categoryStandardVOs){
            // 因为CategoryStandardVO类型中没有children属性保存子分类对象
            // 所以我们要使用FrontCategoryEntity来保存同名属性
            FrontCategoryEntity frontCategoryEntity=new FrontCategoryEntity();
            // 利用BeanUtils将categoryStandardVO同名属性赋值给frontCategoryEntity
            BeanUtils.copyProperties(categoryStandardVO,frontCategoryEntity);
            // 提取当前分类对象的父级id(parentId)
            Long parentId=frontCategoryEntity.getParentId();
            // 判断当前的父级Id是否在Map中已经存在
            if(!map.containsKey(parentId)){
                // 如果parentId是第一次出现,就要向map中添加一个元素
                List<FrontCategoryEntity> value=new ArrayList<>();
                value.add(frontCategoryEntity);
                map.put(parentId,value);
            }else{
                // 如果当前以parentId值作为key的map元素已经存在,
                // 我们就向当前map元素的List集合中添加当前分类对象即可
                map.get(parentId).add(frontCategoryEntity);
            }
        }
        log.info("当前map中包含父级id的个数为:{}",map.size());
        // 第二部分,将每个分类对象关联到正确父分类对象中
        // 我们已经获得了每个父分类包含了内些子分类的数据
        // 下面就可以从根分类开始,通过循环遍历将每个分类对象包含的子分类添加到children属性中
        // 因为根分类id为0,所以先key为0的获取
        List<FrontCategoryEntity> firstLevels=map.get(0L);
        //判断根分类是否为null
        if(firstLevels==null){
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"当前项目没有根分类");
        }
        // 首先遍历我们从Map中获取的所有根分类
        for(FrontCategoryEntity oneLevel: firstLevels){
            // 获得当前根分类对象的id
            Long secondLevelParentId=oneLevel.getId();
            // map中获取当前分类对象的所有子分类的集合
            List<FrontCategoryEntity> secondLevels=map.get(secondLevelParentId);
            // 判断二级分类是否为null
            if(secondLevels==null){
                log.warn("当前分类缺少二级分类内容:{}",secondLevelParentId);
                // 为了防止空集合遍历发生异常,我们直接跳过本次循环,运行下次循环
                continue;
            }
            // 遍历当前根分类的所有二级分类
            for(FrontCategoryEntity twoLevel : secondLevels){
                // 获得当前二级分类对象id,作为三级分类的父id保存
                Long thirdLevelParentId = twoLevel.getId();
                // 获得当前二级分类的所有子元素
                List<FrontCategoryEntity> thirdLevels=map.get(thirdLevelParentId);
                if(thirdLevels==null){
                    log.warn("当前分类缺少三级分类内容:{}",thirdLevelParentId);
                    continue;
                }
                // 将三级分类对象集合赋值给二级分类对象的children属性
                twoLevel.setChildrens(thirdLevels);
            }
            // 将二级分类对象集合赋值给一级分类对象的children属性
            oneLevel.setChildrens(secondLevels);
        }
        // 将转换完成的所有一级分类对象,按方法要求返回
        FrontCategoryTreeVO<FrontCategoryEntity> treeVO=new FrontCategoryTreeVO<>();
        // 向对象中属性赋值
        treeVO.setCategories(firstLevels);
        // 别忘了修改返回treeVO
        return treeVO;

    }

}

 

product模块

添加购物车

@Override
    public void addCart(CartAddDTO cartDTO) {
        // 获取当前登录用户的userId
        Long userId=getUserId();
        // 查询这个userId的用户是否已经将指定的sku添加到购物车
        OmsCart omsCart=omsCartMapper.selectExistsCart(userId,cartDTO.getSkuId());
        // 判断查询结果是否为null
        if(omsCart!=null){
            // 不等于null,表示当前用户这个sku已经添加在购物车列表中
            // 我们需要做的就是修改它的数量,根据cartDTO对象的quantity属性值添加
            omsCart.setQuantity(omsCart.getQuantity()+cartDTO.getQuantity());
            // 调用持久层方法修改数量
            omsCartMapper.updateQuantityById(omsCart);
        }else{
            // 如果omsCart是null 会运行else代码块
            // 去完成购物车对象的新增,先实例化OmsCart对象
            OmsCart newOmsCart=new OmsCart();
            // 将参数cartDTO的同名属性赋值给newOmsCart
            BeanUtils.copyProperties(cartDTO,newOmsCart);
            // cartDTO对象中没有userId属性,需要单独赋值
            newOmsCart.setUserId(userId);
            // 执行新增
            omsCartMapper.saveCart(newOmsCart);
        }
    }

添加订单

@GlobalTransactional
    @Override
    public OrderAddVO addOrder(OrderAddDTO orderAddDTO) {
        // 在连接数据库操作前,一定要先把所有数据准备好
        // 1.将订单实体的所有属性赋值OmsOrder
        OmsOrder omsOrder=new OmsOrder();
        // 将参数orderAddDTO所有同名属性赋值给omsOrder
        BeanUtils.copyProperties(orderAddDTO,omsOrder);
        // orderAddDTO中数据并不全面,我们需要更详细的信息才能新增订单
        // 因为收集信息代码较多,单独编写一个方法实现
        loadOrder(omsOrder);
        // 2.遍历订单中包含的所有商品的集合,也保证所有属性被赋值OmsOrderItem
        // 获得orderAddDTO对象中的所有商品sku集合,判断是否为空
        List<OrderItemAddDTO> orderItemAddDTOs=orderAddDTO.getOrderItems();
        if(orderItemAddDTOs==null || orderItemAddDTOs.isEmpty()){
            // 如果为null或集合中没有元素,抛出异常,终止新增订单
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"订单中必须有商品");
        }
        // 我们的目标是将订单中的商品增到oms_order_item表中
        // 我们持有的持久层方法参数是List<OmsOrderItem>
        // 我们先在获得的是List<OrderItemAddDTO>,类型不一致,
        // 我们需要讲OrderItemAddDTO转换成OmsOrderItem,保存到一个新的集合里
        List<OmsOrderItem> omsOrderItems=new ArrayList<>();
        // 遍历参数中包含的所有商品列表
        for(OrderItemAddDTO addDTO: orderItemAddDTOs){
            // 先是转换我们的OrderItemAddDTO为OmsOrderItem
            OmsOrderItem orderItem=new OmsOrderItem();
            // 同名属性赋值
            BeanUtils.copyProperties(addDTO,orderItem);
            // 和Order一样OrderItem也有属性要单独复制
            loadOrderItem(orderItem);
            // 根据上面方法获得的omsOrder的订单id,给当前订单项的订单id属性赋值
            orderItem.setOrderId(omsOrder.getId());
            // 到此为止,我们的订单和循环遍历的订单中的订单项都已经赋好值,下面就要开始进行数据库操作了!
            // 将收集好信息的orderItem对象添加到omsOrderItems集合中
            omsOrderItems.add(orderItem);
            // 3.遍历中所有值被赋值后,修改集合中所有商品的库存,并从购物车中删除这些商品
            // 减少库存数
            // 获得skuId
            Long skuId=orderItem.getSkuId();
            // 获取减少的商品的数量
            Integer quantity=orderItem.getQuantity();
            // dubbo调用减少库存的方法
            int rows=dubboSkuService.reduceStockNum(skuId,quantity);
            // 如果rows值为0,表示这次修改没有修改任何行,一般因为库存不足导致的
            if(rows==0){
                log.warn("商品skuId:{},库存不足",skuId);
                // 抛出异常,Seata组件可以另之前循环过程中已经新增到数据库的信息回滚
                throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"库存不足");
            }
            // 删除购物车中商品
            // 删除购物车商品的方法需要OmsCart实体类
            OmsCart omsCart=new OmsCart();
            omsCart.setSkuId(skuId);
            omsCart.setUserId(omsOrder.getUserId());
            cartService.removeUserCarts(omsCart);
        }
        // 4.将订单信息新增到数据(包括OrderItem和Order)
        // 新增OrderItem对象,利用mapper中批量新增的方法
        orderItemMapper.insertOrderItems(omsOrderItems);
        // 新增订单表
        orderMapper.insertOrder(omsOrder);

        // 最后要保证用户能够看到订单详情
        // 我们不需要返回订单的所有信息,因为前端包含大部分订单信息
        // 我们只需要返回后端生成的一些数据即可
        // OrderAddVO完成这个功能
        OrderAddVO addVO=new OrderAddVO();
        addVO.setId(omsOrder.getId());
        addVO.setSn(omsOrder.getSn());
        addVO.setCreateTime(omsOrder.getGmtCreate());
        addVO.setPayAmount(omsOrder.getAmountOfActualPay());
        // 别忘了返回正确的对象
        return addVO;
    }

    private void loadOrderItem(OmsOrderItem orderItem) {
        if(orderItem.getId()==null){
            Long id=IdGeneratorUtils.getDistributeId("order_item");
            orderItem.setId(id);
        }
        // 必须包含skuid信息,才能确定商品信息
        if(orderItem.getSkuId()==null){
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,
                                            "订单中商品必须包含skuId");
        }
    }

// 新增订单业务中需要的收集Order信息的方法
    private void loadOrder(OmsOrder omsOrder) {
        // 针对OmsOrder对象为空的值进行收集或生成
        // 判断id是否为空
        if(omsOrder.getId()==null){
            // Leaf获得分布式id
            Long id= IdGeneratorUtils.getDistributeId("order");
            omsOrder.setId(id);
        }
        // 判断userId是否为空
        if(omsOrder.getUserId()==null){
            // 从SpringSecurity容器中获得jwt解析而来的用户id
            omsOrder.setUserId(getUserId());
        }
        // 判断sn
        if(omsOrder.getSn()==null){
            omsOrder.setSn(UUID.randomUUID().toString());
        }
        // 判断state
        if (omsOrder.getState()==null){
            // 如果订单状态为null默认是新生成的订单,状态为0:未支付
            omsOrder.setState(0);
        }
        // 下面要保证订单的生成实际,订单数据的创建实际和最后修改时间一致
        // 我们手动获取当前系统时间,统一给他们赋值
        if(omsOrder.getGmtOrder()==null){
            LocalDateTime now=LocalDateTime.now();
            omsOrder.setGmtOrder(now);
            omsOrder.setGmtCreate(now);
            omsOrder.setGmtModified(now);
        }
        // 下面是系统计算金额,前端实际上有基本计算显示,但是前安全性相对差,后端还要计算
        // 计算基本逻辑 原价+运费-优惠=最终价格
        // 判断运费,默认为0
        if(omsOrder.getAmountOfFreight()==null){
            // 默认运费为0
            omsOrder.setAmountOfFreight(new BigDecimal(0.0));
        }
        // 判断优惠,默认为0
        if(omsOrder.getAmountOfDiscount()==null){
            omsOrder.setAmountOfDiscount(new BigDecimal(0.0));
        }
        // 获取传递过来的原价信息,如果原价为空,抛出异常
        if(omsOrder.getAmountOfOriginalPrice()==null){
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"没有提供订单原价");
        }
        // 计算实际支付金额
        // 原价+运费-优惠=最终价格
        BigDecimal originalPrice=omsOrder.getAmountOfOriginalPrice();
        BigDecimal freight=omsOrder.getAmountOfFreight();
        BigDecimal discount=omsOrder.getAmountOfDiscount();
        BigDecimal actualPay=originalPrice.add(freight).subtract(discount);
        // 赋值给实际支付属性
        omsOrder.setAmountOfActualPay(actualPay);


    }

查询当前登录用户在指定时间范围内(默认一个月内)所有订单

// 查询当前登录用户在指定时间范围内(默认一个月内)所有订单
// 订单包含订单信息和订单项信息两个方面(xml的sql语句是关联查询)
@Override
public JsonPage<OrderListVO> listOrdersBetweenTimes(OrderListTimeDTO orderListTimeDTO) {
    // 因为默认为最近一个月内,如果没有起始和结束时间,需要我们自动添加
    // 要检查起始时间和结束时间是否合理,我们单独编写方法校验上面业务
    validaTimeAndLoadTimes(orderListTimeDTO);
    // 时间验证通过,开始进程查询
    // 获得当前用户id
    Long userId=getUserId();
    // 将userId赋值给参数
    orderListTimeDTO.setUserId(userId);
    // 设置分页条件
    PageHelper.startPage(orderListTimeDTO.getPage(),orderListTimeDTO.getPageSize());
    // 执行查询
    List<OrderListVO> list=orderMapper.selectOrdersBetweenTimes(orderListTimeDTO);
    // 别忘了返回
    return JsonPage.restPage(new PageInfo<>(list));

}

private void validaTimeAndLoadTimes(OrderListTimeDTO orderListTimeDTO) {
    // 取出起始和结束时间对象
    LocalDateTime start=orderListTimeDTO.getStartTime();
    LocalDateTime end=orderListTimeDTO.getEndTime();
    // 如果start和end中有任何一个为null,默认查询一个月内
    if(start==null || end==null){
        // 起始时间是当前时间减一个月minusMonths就是减月份的意思,1就是一个月
        start=LocalDateTime.now().minusMonths(1);
        // 默认结束时间是当前时间
        end=LocalDateTime.now();
        // 赋值给orderListTimeDTO参数
        orderListTimeDTO.setStartTime(start);
        orderListTimeDTO.setEndTime(end);
    }else{
        // 如果是国际的时间判断,需要添加时区修正来判断时间
        // 判断结束时间大于起始时间,否则发生异常
        if(end.toInstant(ZoneOffset.of("+8")).toEpochMilli()<
            start.toInstant(ZoneOffset.of("+8")).toEpochMilli()){
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,
                    "结束时间应该大于起始时间");
        }
    }

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值