業務分析
點擊提交訂單的時候,會立即創建訂單數據,創建訂單數據會將數據存入到2張表中,分別是訂單表和訂單明細表,此處還需要修改商品對應的庫存數量。
訂單表結構如下:
CREATE TABLE `tb_order` ( `id` varchar(50) COLLATE utf8_bin NOT NULL COMMENT '訂單id', `total_num` int(11) DEFAULT NULL COMMENT '數量合計', `total_money` int(11) DEFAULT NULL COMMENT '金額合計', `pre_money` int(11) DEFAULT NULL COMMENT '優惠金額', `post_fee` int(11) DEFAULT NULL COMMENT '郵費', `pay_money` int(11) DEFAULT NULL COMMENT '實付金額', `pay_type` varchar(1) COLLATE utf8_bin DEFAULT NULL COMMENT '支付類型,1、在線支付、0 貨到付款', `create_time` datetime DEFAULT NULL COMMENT '訂單創建時間', `update_time` datetime DEFAULT NULL COMMENT '訂單更新時間', `pay_time` datetime DEFAULT NULL COMMENT '付款時間', `consign_time` datetime DEFAULT NULL COMMENT '發貨時間', `end_time` datetime DEFAULT NULL COMMENT '交易完成時間', `close_time` datetime DEFAULT NULL COMMENT '交易關閉時間', `shipping_name` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '物流名稱', `shipping_code` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '物流單號', `username` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '用戶名稱', `buyer_message` varchar(1000) COLLATE utf8_bin DEFAULT NULL COMMENT '買家留言', `buyer_rate` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '是否評價', `receiver_contact` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '收貨人', `receiver_mobile` varchar(12) COLLATE utf8_bin DEFAULT NULL COMMENT '收貨人手機', `receiver_address` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '收貨人地址', `source_type` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '訂單來源:1:web,2:app,3:微信公眾號,4:微信小程序 5 H5手機頁面', `transaction_id` varchar(30) COLLATE utf8_bin DEFAULT NULL COMMENT '交易流水號', `order_status` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '訂單狀態,0:未完成,1:已完成,2:已退貨', `pay_status` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '支付狀態,0:未支付,1:已支付,2:支付失敗', `consign_status` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '發貨狀態,0:未發貨,1:已發貨,2:已收貨', `is_delete` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '是否刪除', PRIMARY KEY (`id`), KEY `create_time` (`create_time`), KEY `status` (`order_status`), KEY `payment_type` (`pay_type`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
訂單明細表結構如下:
CREATE TABLE `tb_order_item` ( `id` varchar(50) COLLATE utf8_bin NOT NULL COMMENT 'ID', `category_id1` int(11) DEFAULT NULL COMMENT '1級分類', `category_id2` int(11) DEFAULT NULL COMMENT '2級分類', `category_id3` int(11) DEFAULT NULL COMMENT '3級分類', `spu_id` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT 'SPU_ID', `sku_id` bigint(20) NOT NULL COMMENT 'SKU_ID', `order_id` bigint(20) NOT NULL COMMENT '訂單ID', `name` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '商品名稱', `price` int(20) DEFAULT NULL COMMENT '單價', `num` int(10) DEFAULT NULL COMMENT '數量', `money` int(20) DEFAULT NULL COMMENT '總金額', `pay_money` int(11) DEFAULT NULL COMMENT '實付金額', `image` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '圖片地址', `weight` int(11) DEFAULT NULL COMMENT '重量', `post_fee` int(11) DEFAULT NULL COMMENT '運費', `is_return` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '是否退貨,0:未退貨,1:已退貨', PRIMARY KEY (`id`), KEY `item_id` (`sku_id`), KEY `order_id` (`order_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
下單實現
下單的時候,先往tb_order表中增加數據,再往tb_order_item表中增加數據。
代碼實現
這里先修改changgou-service-order微服務,實現下單操作,這里會生成訂單號,我們首先需要在啟動類中創建一個IdWorker對象。
在com.changgou.OrderApplication
中創建IdWorker,代碼如下:
@Bean public IdWorker idWorker(){ return new IdWorker(1,1); }
(1)控制層
修改changgou-service-order微服務,修改com.changgou.order.controller.OrderController類,代碼如下:
@Autowired private TokenDecode tokenDecode; /*** * 新增Order數據 * @param order * @return */ @PostMapping public Result add(@RequestBody Order order){ //獲取用戶名 Map<String, String> userMap = tokenDecode.getUserInfo(); String username = userMap.get("username"); //設置購買用戶 order.setUsername(username); orderService.add(order); return new Result(true,StatusCode.OK,"添加成功"); }
(2)業務層
實現邏輯:
1)獲取所有購物項
2)統計計算:總金額,總數量
3)填充訂單數據並保存
4)獲取每一個購物項保存到orderItem
5)刪除購物車中數據
修改訂單微服務添加com.changgou.order.service.impl.OrderServiceImpl,代碼如下:
/** * 增加 * @param order */ @Override public void add(Order order){ //1)獲取所有購物項 Map cartMap = cartService.list(order.getUsername()); List<OrderItem> orderItemList = (List<OrderItem>) cartMap.get("orderItemList"); //3)填充訂單數據並保存 order.setTotalNum((Integer) cartMap.get("totalNum")); order.setTotalMoney((Integer) cartMap.get("totalMoney")); order.setPayMoney((Integer) cartMap.get("totalMoney")); order.setCreateTime(new Date()); order.setUpdateTime(order.getCreateTime()); order.setBuyerRate("0"); //0:未評價,1:已評價 order.setSourceType("1"); //來源,1:WEB order.setOrderStatus("0"); //0:未完成,1:已完成,2:已退貨 order.setPayStatus("0"); //0:未支付,1:已支付,2:支付失敗 order.setConsignStatus("0"); //0:未發貨,1:已發貨,2:已收貨 order.setId(idWorker.nextId()+""); int count = orderMapper.insertSelective(order); //添加訂單明細 for (OrderItem orderItem : orderItemList) { orderItem.setId(idWorker.nextId()+""); orderItem.setIsReturn("0"); orderItem.setOrderId(order.getId()); orderItemMapper.insertSelective(orderItem); } //清除Redis緩存購物車數據 redisTemplate.delete("Cart_"+order.getUsername()); }
渲染服務對接
我們需要在模板渲染端調用訂單微服務實現下單操作,下單操作需要調用訂單微服務,所以需要創建對應的Feign。
(1)Feign創建
修改changgou-service-order-api,添加OrderFeign,代碼如下:
@FeignClient(name="order") public interface OrderFeign { /*** * 提交訂單數據 * @param order * @return */ @PostMapping("/order") Result add(@RequestBody Order order); }
(2)下單調用
修改changgou-web-order的com.changgou.order.controller.OrderController
添加下單方法,代碼如下:
@Autowired private OrderFeign orderFeign; /*** * 添加訂單數據到購物車中 * @param order * @return */ @PostMapping(value = "/add") @ResponseBody public Result add(@RequestBody Order order){ Result result = orderFeign.add(order); return result; }
(3)頁面調用
修改order.html,增加下單js方法,並且在頁面點擊下單調用,代碼如下:
點擊提交訂單調用
保存訂單測試,表數據變化如下:
tb_order表數據:
tb_order_item表數據:
庫存變更
業務分析
上面操作只實現了下單操作,但對應的庫存還沒跟着一起減少,我們在下單之后,應該調用商品微服務,將下單的商品庫存減少,銷量增加。每次訂單微服務只需要將用戶名傳到商品微服務,商品微服務通過用戶名到Redis中查詢對應的購物車數據,然后執行庫存減少,庫存減少需要控制當前商品庫存>=銷售數量。
如何控制庫存數量>=購買數量呢?其實可以通過SQL語句實現,每次減少數量之前,加個條件判斷。
where num>=#{num}
即可。
商品服務需要查詢購物車數據,所以需要引入訂單的api,在pom.xml中添加如下依賴:
<!--order api 依賴--> <dependency> <groupId>com.changgou</groupId> <artifactId>changgou_service_order_api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
代碼實現
要調用其他微服務,需要將頭文件中的令牌數據攜帶到其他微服務中取,所以我們不能使用hystrix的多線程模式,修改changgou-service-order的applicatin.yml配置,代碼如下:
#hystrix 配置 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 10000 strategy: SEMAPHORE
每次還需要使用攔截器添加頭文件信息,修改配置類com.changgou.OrderApplication添加攔截器,代碼如下:
@Bean public FeignInterceptor feignInterceptor(){ return new FeignInterceptor(); }
(1)Dao層
修改changgou-service-goods微服務的com.changgou.goods.dao.SkuMapper
接口,增加庫存遞減方法,代碼如下:
/** * 遞減庫存 * @param orderItem * @return */ @Update("UPDATE tb_sku SET num=num-#{num},sale_num=sale_num+#{num} WHERE id=#{skuId} AND num>=#{num}") int decrCount(OrderItem orderItem);
(2)業務層
修改changgou-service-order微服務的com.changgou.goods.service.SkuService
接口,添加如下方法:
/*** * 庫存遞減 * @param username */ void decrCount(String username);
修改changgou-service-order微服務的com.changgou.goods.service.impl.SkuServiceImpl
實現類,添加一個實現方法,代碼如下:
@Autowired private RedisTemplate redisTemplate; /*** * 庫存遞減 * @param username */ @Override public void decrCount(String username) { //獲取購物車數據 List<OrderItem> orderItems = redisTemplate.boundHashOps("Cart_" + username).values(); //循環遞減 for (OrderItem orderItem : orderItems) { //遞減庫存 int count = skuMapper.decrCount(orderItem); if(count<=0){ throw new RuntimeException("庫存不足,遞減失敗!"); } } }
(3)控制層
修改changgou-service-goods的com.changgou.goods.controller.SkuController
類,添加庫存遞減方法,代碼如下:
/*** * 庫存遞減 * @param username * @return */ @PostMapping(value = "/decr/count") public Result decrCount(@RequestParam("username") String username){ //庫存遞減 skuService.decrCount(username); return new Result(true,StatusCode.OK,"庫存遞減成功!"); }
(4)創建feign
同時在changgou-service-goods-api工程添加com.changgou.goods.feign.SkuFeign
的實現,代碼如下:
/*** * 庫存遞減 * @param username * @return */ @PostMapping(value = "/decr/count") Result decrCount(@RequestParam(value = "username") String username);
調用庫存遞減
修改changgou-service-order微服務的com.changgou.order.service.impl.OrderServiceImpl類的add方法,增加庫存遞減的調用。
先注入SkuFeign
@Autowired private SkuFeign skuFeign;
再調用庫存遞減方法
//庫存減庫存 skuFeign.decrCount(order.getUsername());
完整代碼如下:
測試
庫存減少前,查詢數據庫Sku數據如下:個數98,銷量0
使用Postman執行 http://localhost:18081/api/order/add
執行測試后,剩余庫存97,銷量1
增加積分(學員練習)
比如每次下單完成之后,給用戶增加10個積分,支付完成后贈送優惠券,優惠券可用於支付時再次抵扣。我們先完成增加積分功能。如下表:points表示用戶積分
CREATE TABLE `tb_user` ( `username` varchar(50) NOT NULL COMMENT '用戶名', `password` varchar(100) NOT NULL COMMENT '密碼,加密存儲', `phone` varchar(20) DEFAULT NULL COMMENT '注冊手機號', `email` varchar(50) DEFAULT NULL COMMENT '注冊郵箱', `created` datetime NOT NULL COMMENT '創建時間', `updated` datetime NOT NULL COMMENT '修改時間', `source_type` varchar(1) DEFAULT NULL COMMENT '會員來源:1:PC,2:H5,3:Android,4:IOS', `nick_name` varchar(50) DEFAULT NULL COMMENT '昵稱', `name` varchar(50) DEFAULT NULL COMMENT '真實姓名', `status` varchar(1) DEFAULT NULL COMMENT '使用狀態(1正常 0非正常)', `head_pic` varchar(150) DEFAULT NULL COMMENT '頭像地址', `qq` varchar(20) DEFAULT NULL COMMENT 'QQ號碼', `is_mobile_check` varchar(1) DEFAULT '0' COMMENT '手機是否驗證 (0否 1是)', `is_email_check` varchar(1) DEFAULT '0' COMMENT '郵箱是否檢測(0否 1是)', `sex` varchar(1) DEFAULT '1' COMMENT '性別,1男,0女', `user_level` int(11) DEFAULT NULL COMMENT '會員等級', `points` int(11) DEFAULT NULL COMMENT '積分', `experience_value` int(11) DEFAULT NULL COMMENT '經驗值', `birthday` datetime DEFAULT NULL COMMENT '出生年月日', `last_login_time` datetime DEFAULT NULL COMMENT '最后登錄時間', PRIMARY KEY (`username`), UNIQUE KEY `username` (`username`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶表';
代碼實現
(1)dao層
修改changgou-service-user微服務的com.changgou.user.dao.UserMapper
接口,增加用戶積分方法,代碼如下:
/*** * 增加用戶積分 * @param username * @param pint * @return */ @Update("UPDATE tb_user SET points=points+#{point} WHERE username=#{username}") int addUserPoints(@Param("username") String username, @Param("point") Integer pint);
(2)業務層
修改changgou-service-user微服務的com.changgou.user.service.UserService
接口,代碼如下:
/*** * 添加用戶積分 * @param username * @param pint * @return */ int addUserPoints(String username,Integer pint);
修改changgou-service-user微服務的com.changgou.user.service.impl.UserServiceImpl
,增加添加積分方法實現,代碼如下:
/*** * 修改用戶積分 * @param username * @param pint * @return */ @Override public int addUserPoints(String username, Integer pint) { return userMapper.addUserPoints(username,pint); }
(3)控制層
修改changgou-service-user微服務的com.changgou.user.controller.UserController
,添加增加用戶積分方法,代碼如下:
@Autowired private TokenDecode tokenDecode; /*** * 增加用戶積分 * @param points:要添加的積分 */ @GetMapping(value = "/points/add") public Result addPoints(Integer points){ //獲取用戶名 Map<String, String> userMap = tokenDecode.getUserInfo(); String username = userMap.get("username"); //添加積分 userService.addUserPoints(username,points); return new Result(true,StatusCode.OK,"添加積分成功!"); }
(4)Feign添加
修改changgou-service-user-api工程,修改com.changgou.user.feign.UserFeign
,添加增加用戶積分方法,代碼如下:
/*** * 添加用戶積分 * @param points * @return */ @GetMapping(value = "/points/add") Result addPoints(@RequestParam(value = "points")Integer points);
增加積分調用
修改changgou-service-order,添加changgou-service-user-api的依賴,修改pom.xml,添加如下依賴:
<!--user api 依賴--> <dependency> <groupId>com.changgou</groupId> <artifactId>changgou-service-user-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
在增加訂單的時候,同時添加用戶積分,修改changgou-service-order微服務的com.changgou.order.service.impl.OrderServiceImpl
下單方法,增加調用添加積分方法,代碼如下:
修改changgou-service-order的啟動類com.changgou.OrderApplication
,添加feign的包路徑: