订单 ​
1. 数据库 ​

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);

2.2 提交订单 ​
接口说明:这个接口是在上一步获取了结算页的信息之后,用户点击提交订单,然后去生成订单,需要做的事情:
- 下单之前校验
- 校验库存是否足够
wareApiClient.hasStock(skuId,num);- 校验商品价格是否产生变动
- 保存订单以及订单详情
- 删除购物车
- 发送订单超时自动取消的消息

关于仓储系统(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);
}几个细节:
保存订单以及订单详情:事务
删除购物车:
- 不要把用户的购物车都删除,只删除这次订单中的商品
- 需要调用购物车服务
发送订单超时取消的消息
需要引入
common-mq模块使用BaseProducer发送消息
消息的Topic是什么?消息延迟多久?
在哪个服务消费消息?消费消息的逻辑是什么?
修改订单状态为 “已取消”
支付成功后前端自动跳转到支付成功页面,此时因为在支付成功的页面,要显示订单信息,所以此时前端会发送请求到支付服务,获取当前的订单信息,所以支付服务需要实现如下接口
java
@GetMapping("pay/auth")
public Result<OrderInfoDTO> payIndex(Long orderId){
// 调用订单服务获取订单信息
OrderInfoDTO orderInfoDTO = orderApiClient.getOrderInfoDTO(orderId);
return Result.ok(orderInfoDTO);
}所以,很显然我们需要在订单服务中,实现Controller方法来接收处理这个来自支付服务的服务调用请求

2.4 查看我的订单 ​

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);
}笔记 ​
- 库存一般会有一个单独的服务,内部逻辑复杂,涉及到货物的调度算法,要考虑货源发货成本,举例等因素
- 同一个消费组的consumer一个服务只有一个,想要多个就多起服务