完整版订单超时自动取消功能

news2024/9/22 14:18:18

        前几天对实习还是继续学习技术产生了抉择,问了一个前辈,他抛给我一个问题,怎么做15分钟订单自动取消,我说然后到时间之后,自动执行这个订单关闭业务,比如把锁了的库存给解开等等操作,然后在数据库里肯定要有体现,比如抖音,查我的订单内一块,在前段应该显示已过期,把支付的按钮变灰或者取消,支付的时候不能直接对库存进行操作,应该是支付模块调用订单模块调用库存模块。

        然后把理论予以实现,发现需要考虑的点还是有一些的。

功能架构

        该功能使用了三大模块解除耦合,保证高可用性,从高层到底层分别是支付模块->订单模块->商品模块,各司其职,支付模块主要负责支付,退款等相应功能;订单模块主要负责订单查询,订单创建,删除订单相关功能;商品模块主要负责商品上下架,补货,查货相关功能;是环环相扣的,支付模块通过操控订单实现支付,订单模块通过操控商品来实现订单创建等操作。

功能实现流程

        由于是全栈开发,本功能实现流程会涵盖前后端都有。由于管理模块,就是添加商品等等操作,在前端并没有实现,就先在数据库里加一些商品。sql如下:

 然后写一个接口获取商品列表,然后前端进行渲染,效果如下:

测试阶段,未接入微信支付等,但有字段标识,后期方便扩展,渲染的时候只需要有一点,判断支付类型,如果是钱支付就渲染成¥的形式,如果是积分就渲染成积分的形式。然后点击兑换会弹出一个弹出框如下:

 扩展一些信息也会变得非常简单,由于数据库里设置了两个字段一个是销售价(也就是优惠后的价格),一个是原价,直接在前端算出优惠金额即可。然后点击提交订单,就会向后端去发送一个创建的请求,java代码如下所示:

        // 这里先把订单持续事件设置成15秒
        // 1.1 先校验参数,看看该商品是否有库存
        CommonGoodPo good = goodMapper.queryGoodById(dto.getGoodId());
        if (good == null) return Result.error("已查询不到该商品");
        Boolean isPut = good.getIsPut();
        if (!isPut) return Result.error("无法对已下架的商品下订单");
        // 1.2 看看库存还够不够
        Boolean haveStore = good.getHaveStore();
        Integer store = good.getStore();
        if (haveStore && store <= 0) return Result.error("库存不足,无法下单");

        // 库存足就锁定一个库存
        if (haveStore) goodMapper.lockStore(good.getId());

        // 1.3 todo 如果有一个人只能买一单等等限制,可继续扩展

        // 2.1 然后就要生成订单的信息了,比如订单的id,这里起始应该使用杂乱的数字字母等作为id,图方便就直接使用自增id

        // 2.2 然后生成开始时间和结束时间
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime end = LocalDateTime.now().plusMinutes(15); // 15分钟写死
        PopOrderVo popOrderVo = new PopOrderVo(null, good.getId(), now, end, 15 * 60, dto.getAccount());
        orderMapper.creatOrder(popOrderVo);

        // 3 准备对象,发送消息
        String mes = JSON.toJSONString(popOrderVo);
        sendDelayMessage(mes, 60 * 15, RabbitConstants.DELAY_ORDER_DEL_DIRECT_EXCHANGE, RabbitConstants.DELAY_ORDER_KEY);


        // 然后封装一下给前端,然后前端得到信息后,弹出弹出层,在我的订单里也可以找到该信息
        return Result.ok(popOrderVo);

 代码逻辑主要分为三部分,校验参数;然后去执行sql,就是向数据库的order表里去添加一条订单消息,并且要锁库存;最后向rabbitMQ里发一条延迟消息,这个是封装好的方法。到期执行的方法如下所示:

        log.error("我要开始喽!");
        // 把msg转成对象
        PopOrderVo popOrderVo = null;
        try {
            popOrderVo = JSON.parseObject(msg, PopOrderVo.class);
        } catch (Exception e) {
            throw new RuntimeException("请调用符合规定的api,类型转换错误,无法转换为PopOrderVo");
        }

        // 自动取消订单逻辑
        LocalDateTime now = LocalDateTime.now();
        Integer orderId = popOrderVo.getOrderId();
        Integer goodId = popOrderVo.getGoodId();
        // 修改订单状态
        orderMapper.finishOrder(orderId, now, ORDER_STATUS_OVERTIME);
        // 把锁了的库存释放
        goodMapper.unLockStore(goodId);
        log.error("我结束喽!");

就是去校验一下参数,然后去解锁库存,然后修改订单状态。

订单表如下所示:

然后在点击提交订单后,弹出支付页面,并有前端实现的倒计时。 

 然后会显示一些订单信息,倒计时到了之后,按钮会变成灰色,并无法点击,点击支付按钮后,进入到后端逻辑。代码如下:

    @Override
    @Transactional
    public Result payOrder(PayOrderDto dto) {
        Integer orderId = dto.getOrderId();
        OrderPo orderInfo = orderMapper.getOrderInfo(orderId);

        Integer goodId = orderInfo.getGoodId();

        LocalDateTime now = LocalDateTime.now();
        CommonGoodPo good = goodMapper.queryGoodById(goodId);
        // 1 先需要校验参数
        // 1.1 看过没过期,如果现在的时间在截止时间之后,则证明过期了
        if (now.isAfter(orderInfo.getEndTime())) {
           

            return Result.error("该订单已经过期,请重新下单!");
        }
        
        // 1.2 看一下状态是不是待支付状态
        if (orderInfo.getStatus() != 0) return Result.error("该订单已被处理,请刷新重试");
        // 1.3 看余额够不够
        Boolean isEnough = payMapper.checkBalance(orderInfo.getAccount(), good.getSalePrice());
        // 2.1 如果不够,直接报错余额不足
        if (!isEnough) return Result.error("你的余额不足,无法完成支付");
        // 2.2 如果够,扣减余额
        payMapper.decreaseBalance(orderInfo.getAccount(), good.getSalePrice());
        // 2 需要进行三个方面的处理
        // 2.1 商品给增加销量等等
        goodMapper.increaseSales(goodId);
        // 2.2 设置订单状态,截至时间等
        orderMapper.finishOrder(orderId, now, ORDER_STATUS_SUCCESS);
        // 2.3 记录支付日志
        payMapper.logPay(good.getSalePrice(), good.getPayType(), orderInfo.getAccount(), now, goodId);
//        return null;
        return Result.ok("支付成功");

    }

支付逻辑比较简单,就是校验参数,但需要注意需要检验一下订单状态,因为可能因为网络问题等等,导致请求到后端的时候,出现时间延迟问题,出现状态已经不是待支付状态已经被修改的问题(处理幂等问题),余额不足问题,这时就不能再进行支付,要对订单进行一下处理。如果满足条件就进行sql操作。

然后在前端为了订单的丢失,又写了一个我的订单页面,如下所示:

可以根据不同的状态去筛选不同的订单列表,然后并可以在此页面完成支付。

至此本功能结束,使用的是rabbitMQ的延迟队列实现定时操作,也可以使用xxl-job,直接使用策略模式扩展一下即可,在复习专栏里有关于设计模式的文章和例子,后续有时间会讲一下定时操作策略的扩展。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2139177.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

后续学习规划 ----含我个人的学习路线,经历及感受

目前的基础 开发相关&#xff08;最重要&#xff09; 1.Java SE 从入门到起飞 2.Java Web开发 3.苍穹外卖 以上三个是和开发相关的基础。 我是按照书写的顺序学习的&#xff0c;有需要的朋友可以参考。 计算机相关 其他的话&#xff0c;都是比较久远的了。隔得时间一年半…

【大数据方案】智慧大数据平台总体建设方案书(word原件)

第1章 总体说明 1.1 建设背景 1.2 建设目标 1.3 项目建设主要内容 1.4 设计原则 第2章 对项目的理解 2.1 现状分析 2.2 业务需求分析 2.3 功能需求分析 第3章 大数据平台建设方案 3.1 大数据平台总体设计 3.2 大数据平台功能设计 3.3 平台应用 第4章 政策标准保障体系 4.1 政策…

nginx: [emerg] unknown “connection_upgrade“ variable 解决与思考

问题,如下图&#xff1a; 一天更新完主分支后启动nginx,结果报错&#xff1a;nginx: [emerg] unknown "connection_upgrade" variable 解决方法 网上查&#xff0c;发现是nginx配置文件出了问题&#xff0c;将下面map代码块补上即可。 http { map $http_upgrade …

深入理解算法效率:时间复杂度与空间复杂度

目录 引言 一、算法效率的基础 二、时间复杂度 1.概念 2.常见类型 1.O(1) — 常数阶 2.O(n) — 线性阶 3.O(n^2) — 平方阶 4.O(2^&#x1d45b;) — 指数阶 5.O(log &#x1d45b;) — 对数阶 3.总结 三、空间复杂度 1.概念 2.常见类型 1.O(1) — 常数阶 2.…

Linux进程(3)(进程优先级 - 优先级 - 命令行参数 - 环境变量)

目录 1.进程优先级 1&#xff09;什么是优先级 2&#xff09;为什么要有优先级 3&#xff09;Linux的优先级特点 && 查看方式 2.命令行参数和环境变量 3.环境变量 1&#xff09;直接现象 2&#xff09;见见更多的环境变量 3&#xff09;整体理解环境变量和系统…

【UEFI基础】BIOS模块执行的优先级

综述 BIOS下主要通过两种方式来确定一般模块的优先级&#xff0c;一种是fdf文件中指定的优先级&#xff0c;另一种是inf文件中指定的优先级。需要注意这里使用了“一般模块”的说法&#xff0c;因为有些模块&#xff08;尤其是PEI_CORE&#xff0c;DXE_CORE类型的模块&#xf…

Codeforces Round 972(Div.2)A+B

Codeforces Round 972&#xff08;Div.2&#xff09;ABC 昨天晚上做了Codeforces Round 972&#xff08;Div.2&#xff09;的A、B两道题&#xff0c;今天补一下思路。 题目来源&#xff1a;https://codeforces.com/contest/2005 A. Simple Palindrome 题目描述 输入输出样例…

linux---压缩打包

linux打包和压缩文件和目录&#xff1a; 归档(打包)命令&#xff1a;tar 归档就是将多个文件或者目录打包成为一个文件&#xff0c;存放再磁盘中&#xff0c;方便文件或者目录丢失时&#xff0c;可以恢复。 归档文件名使用相对路径 &#xff08;注意区分归档文件和被归档文…

Go 注册Nacos

根据需要GO 项目也接入Nacos 系统版本&#xff1a;Linux 5.4.18-87.76-generic KYLINOS SMP Thu Aug 31 09:05:44 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux Go:1.19.4 1.查看Nacos-sdk-go 官方适配自己的工程 github.com/nacos-group/nacos-sdk-go NacosManager.go p…

【自动化测试】UI自动化的分类、如何选择合适的自动化测试工具以及其中appium的设计理念、引擎和引擎如何工作

引言 UI自动化测试主要针对软件的用户界面进行测试&#xff0c;以确保用户界面元素的交互和功能符合预期 文章目录 引言一、UI自动化的分类1.1 基于代码的自动化测试1.2 基于录制/回放的自动化测试1.3 基于框架的自动化测试1.4 按测试对象分类1.5 按测试层次分类1.6 按测试执行…

[产品管理-21]:NPDP新产品开发 - 19 - 产品设计与开发工具 - 详细设计与规格定义

目录 前言&#xff1a; 一、详细设计与规格定义概述 1、产品详细设计 2、规格定义 3、详细设计与规格定义的关系 4、实际应用中的注意事项 二、详细设计与规格定义主要工具 2.1 质量功能展开QFD - 需求跟踪矩阵 1、QFD的基本原理 2、QFD的实施步骤 3、QFD的优势与应…

智能赋能,Vatee万腾平台助力企业升级新高度

在当今这个日新月异的数字时代&#xff0c;智能技术的飞速发展正以前所未有的力量重塑着各行各业的面貌。作为这一变革浪潮中的佼佼者&#xff0c;Vatee万腾平台凭借其卓越的智能赋能能力&#xff0c;正引领众多企业迈向转型升级的新高度&#xff0c;开启了智能化发展的新篇章。…

【性能优化】分块

性能优化-tiling过程 这张图展示了在硬件和软件两个层面上执行矩阵乘法 C + = A B C += AB C+

560 和为k的子数组

解题思路&#xff1a; \qquad 一开始看到连续非空序列&#xff0c;会想到是不是可以用双指针表示一个区间&#xff0c;然后通过一次遍历找出所有可能的区间&#xff0c;但看到元素的取值区间就知道行不通&#xff0c;这个方法仅适用于数组元素大于等于0的情况。若数字是负数&a…

【Java面试】第十天

&#x1f31f;个人主页&#xff1a;时间会证明一切. 目录 Spring 中的 Bean 是线程安全的吗&#xff1f;有状态的Bean如何解决线程安全问题 SpringBoot和Spring的区别是什么&#xff1f;SpringBoot的启动流程是怎么样的&#xff1f;new SpringApplication()SpringApplication.r…

【Android 13源码分析】WindowContainer窗口层级-2-构建流程

在安卓源码的设计中&#xff0c;将将屏幕分为了37层&#xff0c;不同的窗口将在不同的层级中显示。 对这一块的概念以及相关源码做了详细分析&#xff0c;整理出以下几篇。 【Android 13源码分析】WindowContainer窗口层级-1-初识窗口层级树 【Android 13源码分析】WindowCon…

ArrayList 源码解析

ArrayList是Java集合框架中的一个动态数组实现&#xff0c;提供了可变大小的数组功能。它继承自AbstractList并实现了List接口&#xff0c;是顺序容器&#xff0c;即元素存放的数据与放进去的顺序相同&#xff0c;允许放入null元素&#xff0c;底层通过数组实现。除该类未实现同…

模板替换引擎(支持富文本动态表格)

模板替换引擎&#xff08;支持富文本动态表格&#xff09; 前言功能介绍example&#xff1a; 使用方法函数扩展系统函数自定义函数 前言 分享一下自己开源的工具——模板替换引擎 https://github.com/RwTo/template-engine 可以拿来学习设计模式或使用 感兴趣的话&#xff…

网络编程基础概述

文章目录 协议网络协议栈(osi)局域网IPIP和Mac地址端口号TCP和UDP网络字节序 协议 (网络协议的)意义:为了让计算机传输之间将信息正确传输给目标机器 不同系统之间能接入网络是因为定制了一套通用的协议以便支持不同系统间的网络通信 1.网络通信的问题: 将数据可靠的从A传给B a…

AtCoder ABC369 A-D题解

比赛链接:ABC369 省流&#xff1a;A<B<D<C&#xff08;题解是按照该顺序写的&#xff09; Problem A: #include <bist/stdc.h> using namespace std; int main(){int A,B;cin>>A>>B;if(AB)cout<<1<<endl;else if(abs(A-B)%20)cout&l…