基于 RabbitMQ 实现延迟消息的订单处理流程
文章目录
- 订单创建流程
- 1. 商品查询与订单数据初始化
- 2. 总价计算与订单保存
- 3. 扣减库存与购物车清理
- 4. 延迟消息与支付状态检测
- 订单延迟消息监听器
- 支付成功与订单取消
- 1. 订单支付成功
- 2. 订单取消与库存恢复
- 总结
在现代电商系统中,订单处理是一个复杂且关键的环节。从商品查询到库存扣减、订单生成、支付确认等多个步骤,任何一个环节出现问题都可能导致用户体验下降甚至订单失败。今天,我们将通过一个典型的 Java Spring Boot 订单处理流程,结合 RabbitMQ 延迟消息 和全局事务管理,确保每一步都能顺利执行。
订单创建流程
在这个系统中,我们主要关注的功能是 createOrder 方法,它实现了从订单创建到支付确认的全过程。让我们一起来看看代码背后都发生了什么。
@Override
@GlobalTransactional
public Long createOrder(OrderFormDTO orderFormDTO) {// 1.订单数据Order order = new Order();// 1.1.查询商品List<OrderDetailDTO> detailDTOS = orderFormDTO.getDetails();// 1.2.获取商品id和数量的MapMap<Long, Integer> itemNumMap = detailDTOS.stream().collect(Collectors.toMap(OrderDetailDTO::getItemId, OrderDetailDTO::getNum));Set<Long> itemIds = itemNumMap.keySet();// 1.3.查询商品List<ItemDTO> items = itemClient.queryItemByIds(itemIds);if (items == null || items.size() < itemIds.size()) {throw new BadRequestException("商品不存在");}// 1.4.基于商品价格、购买数量计算商品总价:totalFeeint total = 0;for (ItemDTO item : items) {total += item.getPrice() * itemNumMap.get(item.getId());}order.setTotalFee(total);// 1.5.其它属性order.setPaymentType(orderFormDTO.getPaymentType());order.setUserId(UserContext.getUser());order.setStatus(1);// 1.6.将Order写入数据库order表中save(order);// 2.保存订单详情List<OrderDetail> details = buildDetails(order.getId(), items, itemNumMap);detailService.saveBatch(details);// 3.扣减库存try {itemClient.deductStock(detailDTOS);} catch (Exception e) {throw new RuntimeException("库存不足!");}// 4.清理购物车商品cartClient.deleteCartItemByIds(itemIds);// 5.发送延迟消息,检测订单支付状态rabbitTemplate.convertAndSend(MQConstants.DELAY_EXCHANGE_NAME, MQConstants.DELAY_ORDER_KEY, order.getId(),message -> {message.getMessageProperties().setDelay(15 * 60 * 1000); // 15分钟延迟return message;});return order.getId();
}
1. 商品查询与订单数据初始化
首先,我们从用户提交的订单数据中提取商品 ID 和数量,并通过 itemClient.queryItemByIds 方法批量查询商品信息。如果查询结果中商品数量与请求的商品数量不符,则抛出异常提示“商品不存在”。
2. 总价计算与订单保存
接下来,系统根据商品单价与购买数量计算总价,并将相关信息写入数据库。在这一过程中,我们利用 Java 的流处理特性,对商品列表进行遍历与总价计算。
3. 扣减库存与购物车清理
订单数据保存成功后,系统会尝试扣减相应库存,并清理用户购物车中的相关商品。如果库存不足,系统会抛出异常并回滚整个事务。
4. 延迟消息与支付状态检测
最后,系统通过 RabbitMQ 发送一个延迟消息,以便在未来某个时间点检查订单支付状态。这一步保证了即便用户在支付过程中遇到问题,系统也能够及时响应并处理未支付的订单。这里,我们将延迟消息的时间设置为 15 分钟。
订单延迟消息监听器
接下来,我们来看看如何利用消息队列处理订单支付状态的异步检测。
@Component
@RequiredArgsConstructor
public class OrderDelayMessageListener {private final IOrderService orderService;private final PayClient payClient;@RabbitListener(bindings = @QueueBinding(value = @Queue(MQConstants.DELAY_ORDER_QUEUE_NAME),exchange = @Exchange(name = MQConstants.DELAY_EXCHANGE_NAME,delayed = "true"), key = MQConstants.DELAY_ORDER_KEY))public void listenOrderDelayMessage(Long orderId) {// 1.查询订单Order order = orderService.getById(orderId);// 2.判断订单状态,是否已支付if (order == null || order.getStatus() != 1) {// 不做处理return;}// 3.未支付,需要查询支付流水状态PayOrderDTO payOrder = payClient.queryPayOrderByBizOrderNo(orderId);// 4.判断是否支付if (payOrder != null && payOrder.getStatus() == 3) {// 4.1.已经支付,标记订单状态为已支付orderService.markOrderPaySuccess(orderId);} else {// 4.2.未支付,取消订单,回复库存orderService.cancelOrder(orderId);}}
}
在上述代码中,我们利用了 RabbitMQ 的延迟队列特性。当订单延迟消息被监听器捕获后,系统会根据订单当前状态和支付流水状态决定接下来的处理步骤。如果支付成功,订单状态将被更新为已支付;否则,订单将被取消,并恢复相应库存。
支付成功与订单取消
@Override
public void markOrderPaySuccess(Long orderId) {Order order = new Order();order.setId(orderId);order.setStatus(2);order.setPayTime(LocalDateTime.now());updateById(order);
}@Override
@GlobalTransactional
public void cancelOrder(Long orderId) {// 标记订单为已关闭Order order = getById(orderId);if (order != null && order.getStatus() != 5) {order.setStatus(5);updateById(order);}// 恢复库存List<OrderDetail> details = detailService.lambdaQuery().eq(OrderDetail::getOrderId, orderId).list();List<OrderDetailDTO> orderDetailDTOS = BeanUtils.copyList(details, OrderDetailDTO.class);itemClient.restoreStock(orderDetailDTOS);
}
1. 订单支付成功
在 markOrderPaySuccess 方法中,系统将订单状态更新为已支付,并记录支付时间。这一操作确保用户和系统对订单状态有准确的认知。
2. 订单取消与库存恢复
如果订单在延迟消息检测中被认定为未支付,则调用 cancelOrder 方法取消订单,并通过 itemClient.restoreStock 恢复相应库存。由于这些操作可能涉及多个服务,因此通过 @GlobalTransactional 注解确保其在全局事务中执行。
总结
在本篇博客中,我们深入探讨了一个完整的订单处理流程。从商品查询到库存管理,再到支付状态检测,每一步都经过精心设计与实现。通过 Spring Boot 的全局事务管理和 RabbitMQ 延迟消息,我们确保了整个流程的原子性和可靠性。
相关文章:
基于 RabbitMQ 实现延迟消息的订单处理流程
文章目录 订单创建流程1. 商品查询与订单数据初始化2. 总价计算与订单保存3. 扣减库存与购物车清理4. 延迟消息与支付状态检测 订单延迟消息监听器支付成功与订单取消1. 订单支付成功2. 订单取消与库存恢复 总结 在现代电商系统中,订单处理是一个复杂且关键的环节。…...
使用Python将Word文档转换为PNG图片
在这篇博客中,我将介绍一个使用Python编写的小工具,它能够将指定文件夹中的所有Word文档(.doc和.docx格式)转换为PNG图片。这个工具基于wxPython库构建图形用户界面,并结合了win32com和PyMuPDF库实现文档格式的转换。接…...
Qt创建Json对象时浮点数的精度控制
我们在Qt中使用Json都是使用QJsonDocument、QJsonArray、QJsonObject、QJsonValue等类。 当我们在QJsonObject中插入浮点数字段时,会发现浮点数的小数位数很长,如下所示: #include <QJsonDocument> #include <QJsonArray> #incl…...
【海贼王航海日志:前端技术探索】CSS你了解多少?(二)
目录 1 -> 字体属性 1.1 -> 设置字体 1.2 -> 字体大小 1.3 -> 字体粗细 1.4 -> 文字样式 2 -> 文本属性 2.1 -> 文本颜色 2.1.1 -> 认识RGB 2.1.2 -> 设置文本颜色 2.2 -> 文本对齐 2.3 -> 文本装饰 2.4 -> 文本缩进 2.5 -&g…...
软件测试面试200问(全)
1、你的测试职业发展是什么? 测试经验越多,测试能力越高。所以我的职业发展是需要时间积累的,一步步向着高级测试工程师奔去。而且我也有初步的职业规划,前 3 年积累测试经验,按如何做好测试工程师的要点去要求自己&a…...
【单片机毕业设计选题24106】-基于阿里云的心率呼吸监测系统
系统功能: 上电后OLED显示 “欢迎使用请稍后”,两秒后显示Connecting...表示 正在连接阿里云,正常连接阿里云后进入系统显示界面,如长时间显示Connecting...请 检查WiFi网络是否正确。 系统连接阿里云后可在阿里云界面查看到系统上报的温…...
leetcode28:找出字符串第一个匹配的下标
找出字符串第一个匹配的下标 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。 public int strStr(Str…...
Java二十三种设计模式-桥接模式(10/23)
桥接模式:解耦抽象与实现的灵活设计 引言 桥接模式(Bridge Pattern)是一种结构型设计模式,用于将抽象部分与其实现部分分离,使它们可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模…...
Java 面试指南
Java 面试指南 目录 引言Java 基础知识 数据类型运算符控制结构面向对象编程 Java 高级特性 异常处理集合框架泛型多线程与并发 Java 标准类库 java.lang 包java.util 包java.io 包 Java Web 开发 ServletJSPSpring 框架 数据库连接与JDBC JDBC 基础数据库连接池 设计模式 单…...
计算机毕业设计选题推荐-自习室座位预约系统-Java/Python项目实战
✨作者主页:IT毕设梦工厂✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…...
android13 删除兼容性警告窗口 deprecation warning 去除弃用警告
总纲 android13 rom 开发总纲说明 目录 1.前言 2.情况 3.问题分析 4.代码更改 5.编译测试 6.彩蛋 1.前言 在 Android 13 中,为了提高用户体验和应用的兼容性,系统引入了一些新的隐私和安全特性。这些特性可能会影响旧版应用的行为,因此当用户运行可能不完全兼容 An…...
JESD204B/C协议学习笔记
JESD204B基础概念 204B包含传输层,链路层,物理层。 应用层是对 JESD204B 进行配置的接口,在标准协议中是不含此层,只是为了便于理解,添加的一个层。 协议层指工程中生成的IP核JESD204B,负责处理输入的用户…...
网络安全-渗透测试工具及插件介绍和使用方法
1、Burp Suite Burp Suite 是用于攻击web 应用程序的集成平台。 是一款广泛使用的网络安全工具套件,主要用于测试Web应用程序的安全性。它可以帮助安全研究人员、渗透测试人员和开发人员发现和利用Web应用程序中的安全漏洞。 (1)下载和安装&a…...
JAVA WEB初步实验
Spring应用开发环境准备 安装配置Spring应用开发环境 熟悉IntelliJ IDEA开发工具 打开idea工具,创建普通Java工程 配置普通Java工程运行环境 得到基本的Java运行环境配置正常 修改pom.xml文件,搭建Spring IOC运行环境 更新pom文件 新建User、TestSpr…...
30 个 JavaScript 技巧,让你的代码更具可读性
1 、使用 !! 转换为布尔值 使用双重否定快速将任何值转换为布尔值。 let truthyValue !!1; // true let falsyValue !!0; // false 2 、 默认函数参数 设置函数参数的默认值以避免定义错误。 function greet(name "Guest") {return Hello, ${name}!; }greet(…...
电商行业中选择分账系统的关键因素!
分账是指将一笔交易的款项拆分成多个部分,按照预先设定的比例或规则分配给相关方。在电商行业中,分账通常是指将交易金额分给卖家、平台和其他相关方。 具体来说,分账可以帮助实现以下目标: 卖家结算:将顾客支付的货…...
通过继承实现状态模式(C++)
注意:先做类的声明和抽象基类的声明 抽象基类的函数方法中引入类,具体方法在类的实现后面声明。 在抽象基类的子类的函数中可以调用类的成员函数。 #include <iostream>using namespace std;class Contex;class state { public:virtual void Ha…...
全国多地公布2024下半年软考报名具体时间
下半年开考科目: 高级资格:系统分析师、系统架构设计师、网络规划设计师、系统规划与管理师 中级资格:软件设计师、网络工程师、信息安全工程师、信息系统监理师、多媒体应用设计师、系统集成项目管理工程师 初级资格:网络管理…...
【Python】requests的response.text 和 urllib.request 的 response.read()的区别
刚写代码的时候,我经常会把requests 和 urllib下的request 包搞混,这两个请求响应的方法看起来很相似,但是写获取的方法是不一样的。 前者requests 是用response.text 来获取源码,而 urllib.request是用 response.read() 来获取h…...
Obsidian插件安装与开发
大概背景 事情的起因还是因为做笔记,我喜欢利用插件Obsidian Git自动同步笔记到Gitee,写md文档有个问题就是关于图片如何存储。 我个人习惯是将所有图片都保存到指定的文件夹下,如图👇 由于Obsidian对粘贴图片默认格式为这样的&…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
【7色560页】职场可视化逻辑图高级数据分析PPT模版
7种色调职场工作汇报PPT,橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版:职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
