需求:
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版权协议,转载请附上原文出处链接和本声明。