Skip to content

订单 ​

1. 数据库 ​

image-20230315110922296

sql
# 订单表
CREATE TABLE `order_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `parent_order_id` bigint(20) DEFAULT NULL COMMENT '父订单编号',
  `order_status` varchar(20) DEFAULT NULL COMMENT '订单状态',
  `user_id` bigint(20) DEFAULT NULL COMMENT '用户id',
  `payment_way` varchar(20) DEFAULT NULL COMMENT '付款方式',
  `consignee` varchar(100) DEFAULT NULL COMMENT '收货人',
  `consignee_tel` varchar(20) DEFAULT NULL COMMENT '收件人电话',
  `delivery_address` varchar(1000) DEFAULT NULL COMMENT '送货地址',
  `total_amount` decimal(10,2) DEFAULT NULL COMMENT '总金额',
  `original_total_amount` decimal(16,2) DEFAULT NULL COMMENT '原价金额',
  `order_comment` varchar(200) DEFAULT NULL COMMENT '订单备注',
  `out_trade_no` varchar(50) DEFAULT NULL COMMENT '订单交易编号(第三方支付用)',
  `trade_body` varchar(200) DEFAULT NULL COMMENT '订单描述(第三方支付用)',
  `order_type` varchar(50) DEFAULT NULL COMMENT '订单类型: 秒杀订单|普通订单',
  `expire_time` datetime DEFAULT NULL COMMENT '失效时间',
	
  `tracking_no` varchar(1000) DEFAULT NULL COMMENT '物流单编号',
  `refundable_time` datetime DEFAULT NULL COMMENT '可退款日期(签收后30天)',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `is_deleted` tinyint(3) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8 COMMENT='订单表';


# 订单明细表
CREATE TABLE `order_detail` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `order_id` bigint(20) DEFAULT NULL COMMENT '订单编号',
  `sku_id` bigint(20) DEFAULT NULL COMMENT 'sku_id',
  `sku_name` varchar(200) DEFAULT NULL COMMENT 'sku名称(冗余)',
  `img_url` varchar(200) DEFAULT NULL COMMENT '图片名称(冗余)',
  `order_price` decimal(10,2) DEFAULT NULL COMMENT '购买价格(下单时sku价格)',
  `sku_num` varchar(200) DEFAULT NULL COMMENT '购买个数',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `is_deleted` tinyint(3) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='订单明细表';

2. 接口功能 ​

2.1 去结算 ​

java
/**
 * 获取订单结算页面
 * @return
*/
@GetMapping("/order/auth/trade")
public Result<OrderTradeDTO> trade(HttpServletRequest request){}

接口说明:这个接口主要是从购物车点击“结算” 然后跳转去结算页面。结算页面需要显示以下两个信息

  • 用户的收货地址信息

    java
    @GetMapping("/api/user/inner/findUserAddressListByUserId/{userId}")
    public List<UserAddressDTO> findUserAddressListByUserId(@PathVariable("userId") String userId);
  • 用户购物车中所有的选中商品信息

    java
    // 下单的时候 查询购物车中所有被选中的商品
    @GetMapping("/api/cart/inner/getCartCheckedList/{userId}")
    public List<CartInfoDTO> getCartCheckedList(@PathVariable(value = "userId") String userId);

![](订单 - 改.assets/订单结算链路.png)

2.2 提交订单 &#8203;

接口说明:这个接口是在上一步获取了结算页的信息之后,用户点击提交订单,然后去生成订单,需要做的事情:

  • 下单之前校验
    • 校验库存是否足够 wareApiClient.hasStock(skuId,num);
    • 校验商品价格是否产生变动
  • 保存订单以及订单详情
  • 删除购物车
  • 发送订单超时自动取消的消息

![](订单 - 改.assets/提交订单链路.png)

关于仓储系统(Warehouse Management System), 在一般企业的电商开发中,都是独立的系统。对于我们做电商业务的同学而言,只需要调用它提供的接口即可。

详情见仓储管理系统开发文档。

java
@PostMapping("/order/auth/submitOrder")
    public Result submitOrder(@RequestBody OrderInfoParam orderInfo,HttpServletRequest request) {
        // 获取到用户Id
        String userId = AuthContext.getUserId(request);
        
        // 1. 校验库存是否足够
		// wareApiClient.hasStock(skuId,num);
        
        // 2. 校验商品价格是否产生变动
        
        // 3. 保存订单以及订单详情
        
        // 4. 删除购物车中已经下单的商品
        
        // 5. 发送订单超时自动取消的消息
		
        // 6. 返回
        return Result.ok(orderId);
}

几个细节:

  1. 保存订单以及订单详情:事务

  2. 删除购物车:

    • 不要把用户的购物车都删除,只删除这次订单中的商品
    • 需要调用购物车服务
  3. 发送订单超时取消的消息

    • 需要引入common-mq模块

    • 使用BaseProducer发送消息

    • 消息的Topic是什么?消息延迟多久?

    • 在哪个服务消费消息?消费消息的逻辑是什么?

      修改订单状态为 “已取消”

支付成功后前端自动跳转到支付成功页面,此时因为在支付成功的页面,要显示订单信息,所以此时前端会发送请求到支付服务,获取当前的订单信息,所以支付服务需要实现如下接口

java
    @GetMapping("pay/auth")
    public Result<OrderInfoDTO> payIndex(Long orderId){
        // 调用订单服务获取订单信息
        OrderInfoDTO orderInfoDTO = orderApiClient.getOrderInfoDTO(orderId);
        return Result.ok(orderInfoDTO);
    }

所以,很显然我们需要在订单服务中,实现Controller方法来接收处理这个来自支付服务的服务调用请求

image-20230316175430364

2.4 查看我的订单 &#8203;

![](订单 - 改.assets/我的订单链路.png)

java
@GetMapping("/order/auth/{page}/{limit}")
public Result<IPage<OrderInfoDTO>> index(@PathVariable Long page, @PathVariable Long limit, HttpServletRequest request) {
    // 获取到用户Id
    String userId = AuthContext.getUserId(request);

    Page<OrderInfoDTO> pageParam = new Page<>(page, limit);
    
    // 获取用户订单的分页列表
    // 注意:
    // 1. 建议使用MybatisPlus的分页查询功能
    // 2. 思考一下哪些订单状态不用在用户页面展示出来?
    // 3. 查询结果需要设置OrderInfoDTO中的orderStatusName(如'未支付'| '已支付' | '已发货')
    IPage<OrderInfoDTO> pageModel = orderService.getPage(pageParam, userId);

    return Result.ok(pageModel);
}

笔记 &#8203;

  • 库存一般会有一个单独的服务,内部逻辑复杂,涉及到货物的调度算法,要考虑货源发货成本,举例等因素
  • 同一个消费组的consumer一个服务只有一个,想要多个就多起服务