模拟电商网站购物场景中的【下单】和【支付】业务
###1)下单
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-49XNkX9g-1627787820381)(img/下单组件图.png)]
- 用户请求订单系统下单
- 订单系统通过RPC调用订单服务下单
- 订单服务调用优惠券服务,扣减优惠券
- 订单服务调用调用库存服务,校验并扣减库存
- 订单服务调用用户服务,扣减用户余额
- 订单服务完成确认订单
###2)支付
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-79j0Klbi-1627787820384)(img/支付组件图.png)]
- 用户请求支付系统
- 支付系统调用第三方支付平台API进行发起支付流程
- 用户通过第三方支付平台支付成功后,第三方支付平台回调通知支付系统
- 支付系统调用订单服务修改订单状态
- 支付系统调用积分服务添加积分
- 支付系统调用日志服务记录日志
问题1
用户提交订单后,扣减库存成功、扣减优惠券成功、使用余额成功,但是在确认订单操作失败,需要对库存、库存、余额进行回退。
如何保证数据的完整性?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y47HiSGx-1627787820386)(img/下单失败流程图.png)]
使用MQ保证在下单失败后系统数据的完整性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JH8SqNa7-1627787820389)(img/下单时序图(2)].png)
###问题2
用户通过第三方支付平台(支付宝、微信)支付成功后,第三方支付平台要通过回调API异步通知商家支付系统用户支付结果,支付系统根据支付结果修改订单状态、记录支付日志和给用户增加积分。
商家支付系统如何保证在收到第三方支付平台的异步通知时,如何快速给第三方支付凭条做出回应?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9xA5I4cM-1627787820391)(img/支付流程.png)]
通过MQ进行数据分发,提高系统处理性能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-odBTFhaZ-1627787820392)(img/支付成功数据分发流程图.png)]
- SpringBoot
- Dubbo
- Zookeeper
- RocketMQ
- Mysql
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QrqQUCgb-1627787820393)(img/项目结构图.png)]
下载rocketmq-spring项目
将rocketmq-spring安装到本地仓库
2.2.1 消息生产者
1)添加依赖
2)配置文件
3)启动类
4)测试类
2.2.2 消息消费者
1)添加依赖
同消息生产者
2)配置文件
同消息生产者
3)启动类
4)消息监听器
下载dubbo-spring-boot-starter依赖包
将安装到本地仓库
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z0245bPe-1627787820394)(…/%E6%96%87%E6%A1%A3/img/dubbo.png)]
2.3.1 搭建Zookeeper集群
1)准备工作
- 安装JDK
- 将Zookeeper上传到服务器
- 解压Zookeeper,并创建data目录,将conf下的zoo_sample.cfg文件改名为zoo.cfg
- 建立,将解压后的Zookeeper复制到以下三个目录
-
配置每一个 Zookeeper 的 dataDir(zoo.cfg) clientPort 分别为 2181 2182 2183
修改
修改/usr/local/zookeeper-cluster/zookeeper-2/conf/zoo.cfg
修改/usr/local/zookeeper-cluster/zookeeper-3/conf/zoo.cfg
2)配置集群
-
在每个 zookeeper 的 data 目录下创建一个 myid 文件,内容分别是 1、2、3 。这个文件就是记录每个服务器的 ID
-
在每一个 zookeeper 的 zoo.cfg 配置客户端访问端口(clientPort)和集群服务器 IP 列表。
集群服务器 IP 列表如下
解释:server.服务器 ID=服务器 IP 地址:服务器之间通信端口:服务器之间投票选举端口
3)启动集群
启动集群就是分别启动每个实例。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-POeMIEKU-1627787820396)(…/%E6%96%87%E6%A1%A3/img/zk.png)]
2.3.2 RPC服务接口
2.3.3 服务提供者
1)添加依赖
2)配置文件
3)启动类
4)服务实现
2.3.4 服务消费者
1)添加依赖
2)配置文件
3)启动类
4)Controller
1)优惠券表
2)商品表
3)订单表
4)订单商品日志表
5)用户表
6)用户余额日志表
7)订单支付表
8)MQ消息生产表
###9)MQ消息消费表
shop系统基于Maven进行项目管理
3.1.1 工程浏览
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YLUq5D0g-1627787820397)(img/项目初始化.png)]
- 父工程:shop-parent
- 订单系统:shop-order-web
- 支付系统:shop-pay-web
- 优惠券服务:shop-coupon-service
- 订单服务:shop-order-service
- 支付服务:shop-pay-service
- 商品服务:shop-goods-service
- 用户服务:shop-user-service
- 实体类:shop-pojo
- 持久层:shop-dao
- 接口层:shop-api
- 工具工程:shop-common
共12个系统
3.1.2 工程关系
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ndxrPyAS-1627787820399)(img/项目结构图.png)]
1)代码生成
使用Mybatis逆向工程针对数据表生成CURD持久层代码
###2)代码导入
- 将实体类导入到shop-pojo工程
- 在服务层工程中导入对应的Mapper类和对应配置文件
-
ID生成器
IDWorker:Twitter雪花算法
-
异常处理类
CustomerException:自定义异常类
CastException:异常抛出类
-
常量类
ShopCode:系统状态类
-
响应实体类
Result:封装响应状态和响应信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4DIEQSYk-1627787820400)(img/下单时序图(2)].png)
1)接口定义
- IOrderService
###2)业务类实现
###3)校验订单
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cl25CfaY-1627787820401)(img/校验订单(2)].png)
###4)生成预订单
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DAxM7fO4-1627787820402)(img/生成预订单.png)]
###5)扣减库存
- 通过dubbo调用商品服务完成扣减库存
- 商品服务GoodsService扣减库存
###6)扣减优惠券
- 通过dubbo完成扣减优惠券
- 优惠券服务CouponService更改优惠券状态
###7)扣减用户余额
- 通过用户服务完成扣减余额
- 用户服务UserService,更新余额
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T9yxRYsO-1627787820403)(img/更改用户余额.png)]
###8)确认订单
9)小结
4.2.1 消息发送方
- 配置RocketMQ属性值
- 注入模板类和属性值信息
- 发送下单失败消息
4.2.2 消费接收方
- 配置RocketMQ属性值
- 创建监听类,消费消息
1)回退库存
- 流程分析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rGr73DNN-1627787820404)(img/回退库存.png)]
- 消息消费者
2)回退优惠券
3)回退余额
4)取消订单
1)准备测试环境
###1)准备测试数据
- 用户数据
- 商品数据
- 优惠券数据
###2)测试下单成功流程
执行完毕后,查看数据库中用户的余额、优惠券数据,及订单的状态数据
###3)测试下单失败流程
代码同上。
执行完毕后,查看用户的余额、优惠券数据是否发生更改,订单的状态是否为取消。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ggKDb8YK-1627787820405)(img/创建支付订单.png)]
5.2.1 流程分析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ExVwJhWh-1627787820407)(img/12.支付后回调.png)]
5.2.2 代码实现
线程池优化消息发送逻辑
- 创建线程池对象
- 使用线程池
5.2.3
处理消息
支付成功后,支付服务payService发送MQ消息,订单服务、用户服务、日志服务需要订阅消息进行处理
- 订单服务修改订单状态为已支付
- 日志服务记录支付日志
- 用户服务负责给用户增加积分
以下用订单服务为例说明消息的处理情况
1)配置RocketMQ属性值
2)消费消息
- 在订单服务中,配置公共的消息处理类
- 接受订单支付成功消息
通过Rest客户端请求shop-order-web和shop-pay-web完成下单和支付操作
1)配置RestTemplate类
2)配置请求地址
- 订单系统
- 支付系统
odsNumber(1);
order.setAddress(“北京”);
order.setGoodsPrice(new BigDecimal(“5000”));
order.setOrderAmount(new BigDecimal(“5000”));
order.setMoneyPaid(new BigDecimal(“100”));
order.setCouponId(couponId);
order.setShippingFee(new BigDecimal(0));
}