企业级开发项目实战——下单业务逻辑分析及实现流程

需求:

1. 实现订单信息的生成提交:整合订单表信息、订单详情表信息、订单物流表信息;

2. 实现扣减库存接口;

3. 清理超时未支付订单;

 需求分析:

实现流程:

创建订单业务比较复杂,流程如下:

  • 1)根据雪花算法生成订单id
  • 2)商品微服务提供FeignClient,实现根据id查询商品的接口
  • 3)根据itemId查询商品信息
  • 4)基于商品价格、购买数量计算商品总价:totalFee
  • 5)封装Order对象,初识status为未支付
  • 6)将Order写入数据库tb_order表中
  • 7)将商品信息、orderId信息封装为OrderDetail对象,写入tb_order_detail表
  • 8)将user-service的根据id查询地址接口封装为FeignClient
  • 9)根据addressId查询user-service服务,获取地址信息
  • 10)将地址封装为OrderLogistics对象,写入tb_order_logistics表
  • 11)在item-service提供减库存接口,并编写FeignClient
  • 12)调用item-service的减库存接口

需要注意的是,注意确保跨服务业务的事务安全性。

何时扣库存?

  • 下单扣库存
  • 支付扣库存

 

1、实现方法

/**
     * 创建订单:实现方法
     *
     * @param requestParams
     * @return
     */

    @Transactional  //开启事务
    @Override
    public Long createOrder(RequestParams requestParams) {

        //**商品信息
        Order order = new Order();
        //- 1)根据雪花算法生成订单id —— MyBatis-Plus 自带雪花算法生成——  在Order实体类的  订单编号中 把 @TableId(type = IdType.ASSIGN.ID)
        // 雪花算法————mybatis-plus有提供方法

        //- 2)商品微服务提供FeignClient,实现根据id查询商品的接口
        //- 3)根据itemId查询商品信息
        Item item = itemClient.queryItemById(requestParams.getItemId());
        //- 4)基于商品价格、购买数量计算商品总价:totalFee
        long totalFee = item.getPrice()*requestParams.getNum();
        //- 5)封装Order对象,初始status为未支付
        order.setTotalFee(totalFee);
        order.setPaymentType(requestParams.getPaymentType());
        order.setStatus(1); //未付款
        //- 6)将Order写入数据库tb_order表中
        this.save(order);

        //**订单详情
        //- 7)将商品信息、orderId信息封装为OrderDetail对象,写入tb_order_detail表
        //- 8)将user-service的根据id查询地址接口封装为FeignClient
        OrderDetail detail = new OrderDetail();
        detail.setName(item.getName());
        detail.setSpec(item.getSpec());
        detail.setPrice(item.getPrice());
        detail.setNum(requestParams.getNum());
        detail.setItemId(item.getId());
        detail.setImage(item.getImage());
        detail.setOrderId(order.getId());
        detailService.save(detail);


        //**地址
        Long addressId = requestParams.getAddressId();
        //- 9)根据addressId查询user-service服务,获取地址信息
        Address address = userClient.findAddressById(addressId);
        //- 10)将地址封装为OrderLogistics对象,写入tb_order_logistics表
        OrderLogistics orderLogistics = new OrderLogistics();
        //**要把address的属性拷贝到 orderLogistics中,看一下它们属性一不一样呢,有一些关键字段一样,可以拷贝——BeanUtils.copyProperties(从哪,到哪)
        BeanUtils.copyProperties(address,orderLogistics);
        orderLogistics.setOrderId(order.getId());
        orderLogisticsService.save(orderLogistics);

        //**扣减库存
        //- 11)在item-service提供减库存接口,并编写FeignClient
        //- 12)调用item-service的减库存接口
        try {
            itemClient.updateStock(requestParams.getItemId(),requestParams.getNum());
        } catch (Exception e) {
            throw new RuntimeException("库存不足!");
        }

        return order.getId() ;
    }

2、清理超时未支付的订单

一旦下单成功,就会进入支付页面。超时30分钟后,订单就会取消。

实现思路:

这里可以使用延迟队列来实现,基本思路如下:

  • 1. 创建订单后,立即发送一条延迟消息(携带订单id),延迟时间(TTL)为30分钟

  • 2. 编写监听者,监听延迟队列

  • 3. 当监听者收到消息后,一定是下单30分钟后。根据订单id查询订单信息,判断status是否已经支付:

  • 如果未支付:肯定是超时未支付订单,将其status修改为5,取消订单,恢复扣减的库存
  • 如果是已支付,则丢弃消息不管

注意,这里监听到超时信息后,业务的流程包括:

  • 1. 根据orderId查询订单

  • 2. 判断订单status是否为1

    • 不为1则丢弃

    • 为1则继续

  • 3. 根据orderId查询订单详情,得到商品购买数量

  • 4. 根据orderId修改订单status为5(取消),注意幂等判断,避免重复消息

  • 5. 调用item-service,根据商品id、商品数量恢复库存

 


版权声明:本文为chuanbo1995原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。