苍穹外卖day10——订单状态定时处理(Spring Task)、来单提醒和客户催单(WebSocket)

news2024/11/15 13:24:47

 预期效果

 

 对于超时没处理的需要定时程序处理。基于SpringTask实现。

来单提醒和客户催单。基于WebSocket实现。

 

 Spring Task

介绍

 

Cron表达式

周几通常不能和日一起指定。 

 cron表达式在线生成器

在线Cron表达式生成器

入门案例

 创建定时任务类

/**
 * 定义定时任务类
 */
@Slf4j
@Component
public class MyTask {


    /**
     * 定时任务,每隔5秒触发一次
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void executeTask(){
        log.info("定时任务开始执行:{}",new Date());
    }
}

订单状态定时处理——需求分析与设计

 

 

订单状态定时处理——代码开发

新建一个task包中一个类如下

/**
 * 定时任务类,定时处理订单状态
 */
@Component
@Slf4j
public class OrderTask {
    @Autowired
    private OrderMapper orderMapper;

    /**
     * 处理超时订单
     */
    @Scheduled(cron = "0 * * * * ? ")//每分钟触发一次
    public void processTimeoutOrder(){
        log.info("定时处理超时订单:{}",LocalDateTime.now());

        LocalDateTime time = LocalDateTime.now().plusMinutes(-15);
        // select * from orders where status = ? and order_time < (当前时间-15分钟)
        List<Orders> list = orderMapper.getByStatusAndOrderTimeLT(Orders.PENDING_PAYMENT, time);

        if(list!=null&&list.size()>0){
            for (Orders orders : list) {
                orders.setStatus(Orders.CANCELLED);
                orders.setCancelReason("订单超时,自动取消");
                orders.setCancelTime(LocalDateTime.now()); //取消时间
                orderMapper.update(orders);
            }
        }
    }

    /**
     * 处理一直派送中的订单
     */
    @Scheduled(cron = "0 0 1 * * ?")//每天凌晨一点
    public void processDeliveryOrder(){
        log.info("定时处理派送中的订单:{}",LocalDateTime.now());
        LocalDateTime time = LocalDateTime.now().plusMinutes(-60);
        List<Orders> list = orderMapper.getByStatusAndOrderTimeLT(Orders.DELIVERY_IN_PROGRESS, time);

        if(list!=null&&list.size()>0){
            for (Orders orders : list) {
                orders.setStatus(Orders.COMPLETED);
                orderMapper.update(orders);
            }
        }
    }
}

在OrderMapper中

    /**
     * 根据订单状态和下单时间查询订单
     * @param status
     * @param orderTime
     * @return
     */
    @Select("select * from orders where status = #{status} and order_time < #{orderTime}")
    List<Orders> getByStatusAndOrderTimeLT(Integer status, LocalDateTime orderTime);

订单状态定时处理——功能测试

运行测试无误。

WebSocket——介绍

  

WebSocket——入门案例

导入提供的代码资料。

 

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8">
    <title>WebSocket Demo</title>
</head>
<body>
    <input id="text" type="text" />
    <button onclick="send()">发送消息</button>
    <button onclick="closeWebSocket()">关闭连接</button>
    <div id="message">
    </div>
</body>
<script type="text/javascript">
    var websocket = null;
    var clientId = Math.random().toString(36).substr(2);

    //判断当前浏览器是否支持WebSocket
    if('WebSocket' in window){
        //连接WebSocket节点
        websocket = new WebSocket("ws://localhost:8080/ws/"+clientId);
    }
    else{
        alert('Not support websocket')
    }

    //连接发生错误的回调方法
    websocket.onerror = function(){
        setMessageInnerHTML("error");
    };

    //连接成功建立的回调方法
    websocket.onopen = function(){
        setMessageInnerHTML("连接成功");
    }

    //接收到消息的回调方法
    websocket.onmessage = function(event){
        setMessageInnerHTML(event.data);
    }

    //连接关闭的回调方法
    websocket.onclose = function(){
        setMessageInnerHTML("close");
    }

    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function(){
        websocket.close();
    }

    //将消息显示在网页上
    function setMessageInnerHTML(innerHTML){
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }

    //发送消息
    function send(){
        var message = document.getElementById('text').value;
        websocket.send(message);
    }
	
	//关闭连接
    function closeWebSocket() {
        websocket.close();
    }
</script>
</html>

 导入坐标

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

准备一个新的包创建如下的类

与Controller相似,通过路径进行匹配。

/**
 * WebSocket服务
 */
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {

    //存放会话对象
    private static Map<String, Session> sessionMap = new HashMap();

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        System.out.println("客户端:" + sid + "建立连接");
        sessionMap.put(sid, session);
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, @PathParam("sid") String sid) {
        System.out.println("收到来自客户端:" + sid + "的信息:" + message);
    }

    /**
     * 连接关闭调用的方法
     *
     * @param sid
     */
    @OnClose
    public void onClose(@PathParam("sid") String sid) {
        System.out.println("连接断开:" + sid);
        sessionMap.remove(sid);
    }

    /**
     * 群发
     *
     * @param message
     */
    public void sendToAllClient(String message) {
        Collection<Session> sessions = sessionMap.values();
        for (Session session : sessions) {
            try {
                //服务器向客户端发送消息
                session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

准备一个配置类

/**
 * WebSocket配置类,用于注册WebSocket的Bean
 */
@Configuration
public class WebSocketConfiguration {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

准备一个定时任务类

@Component
public class WebSocketTask {
    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 通过WebSocket每隔5秒向客户端发送消息
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void sendMessageToClient() {
        webSocketServer.sendToAllClient("这是来自服务端的消息:" + DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now()));
    }
}

 

 来单提醒——需求分析与设计

设计

 

 来单提醒——代码开发

这里不该资料的源码的话连接不上,加上:8080之后直接请求到后端了,没有走nginx去。

 使用上面的代码

在OrderServiceImpl中

    @Autowired
    private WebSocketServer webSocketServer;
    /**
     * 支付成功,修改订单状态
     *
     * @param outTradeNo
     */
    public void paySuccess(String outTradeNo) {

        XX
        XX
        XX
        XX
        XX

        //通过webSocket向客户端浏览器推送消息 type orderId content
        Map map=new HashMap();
        map.put("type",1);//1表示来单提醒
        map.put("orderId",ordersDB.getId());
        map.put("content","订单号:"+outTradeNo);
        String json = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(json);
    }

 来单提醒——功能测试

懒得模拟支付,就这样吧

客户催单——需求分析与设计

 设计

 接口设计

客户催单——代码开发

Controller中

    /**
     * 客户催单
     * @param id
     * @return
     */
    @GetMapping("/reminder/{id}")
    @ApiOperation("客户催单")
    public Result reminder(@PathVariable("id") Long id){
        orderService.reminder(id);
        return Result.success();
    }

Service中

    /**
     * 客户催单
     * @param id
     */
    @Override
    public void reminder(Long id) {
        // 根据id查询订单
        Orders ordersDB = orderMapper.getById(id);

        // 校验订单是否存在
        if (ordersDB == null ) {
            throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
        }

        Map map=new HashMap();
        map.put("type",2);//1.表示来单提醒,2表示客户催单
        map.put("orderId",id);
        map.put("content","订单号:"+ordersDB.getNumber());
        String json = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(json);
    }

客户催单——功能测试

成功催单

 

 

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

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

相关文章

OBS推流工具介绍及桌面录屏推流功能实现

OBS推流工具介绍及桌面录屏推流功能实现 文章目录 OBS推流工具介绍及桌面录屏推流功能实现1 OBS工具介绍2 OBS工具安装及简单使用2.1 安装步骤2.2 简单使用介绍 3 OBS实现桌面录屏推流工具实现4 总结 流媒体开发工程中&#xff0c;我们除了使用ffmpeg等工具辅助调试外&#xff…

《工具箱-数据库相关》Dbeaver数据导入“CSV格式“、“Txt格式“导入配置

《工具箱-数据库相关》DBeaver线下数据导入数据库表 Dbeaver数据导入"CSV格式"、"Txt格式"导入配置 使用CSV、Txt导入的时候&#xff0c;数据格式不同&#xff0c;在导入数据的时候&#xff0c;要根据数据编码样式设置不同的配置。 一、Txt格式导入 1.1 …

汇编语言基础知识

目录 前言&#xff1a; 汇编语言的产生 汇编语言的组成 内存 指令和数据 cpu对内存的读写操作 地址总线 数据总线 控制总线 内存地址空间 前言&#xff1a; 汇编语言是直接在硬件之上工作的 编程语言&#xff0c;我们首先了解硬件系统的机构&#xff0c;才能有效地应用…

CHI中的resp type

Rsp分为4大类&#xff1b; Completion response □ 除了PCrdReturn&#xff0c;PrefetchTgt&#xff0c;其他所有的trans都需要comp resp; □ 通常是一个trans的最后一个发送的message, 来自completer; 这个响应保证trans到达了POS/POC; □ 通常RN还会发送一个compack;Read an…

pytorch深度学习快速入门

放弃个人素质 享受缺德人生 拒绝精神内耗 有事直接发疯 一、安装Anaconda 官网下载地址 选择适合的系统版本进行安装即可 安装完之后&#xff0c;可以看到下面的内容 二、使用Anaconda创建开发环境 这也是为什么要使用Anaconda的原因&#xff0c;可以创建不同的开发环境&am…

剑指offer46.把数字翻译成字符串

一开始我的想法是从后面向前面不断对100取余&#xff0c;如果这个余数大于等于10并且小于等于25&#xff0c;说明这两位既可以做一个大的字母&#xff0c;也可以做两个小的字母。所以对于前面的n-2个数字来说&#xff0c;后面的连个数字使得前面的n-2个数字的结果数翻了一倍&am…

Statefulset 实战 1

上一部分与大家分享到 Statefulset 与 RplicaSet 的区别&#xff0c;以及 Statefulset 的特点&#xff0c;能做的一些事情及一些注意事项 现在我们来尝试使用 Statefulset 来部署我们的应用&#xff0c;我们可以需要有应用程序&#xff0c;然后有持久化卷 开始使用 Statefuls…

28.利用fminsearch、fminunc 求解最大利润问题(matlab程序)

1.简述 1.无约束&#xff08;无条件&#xff09;的最优化 fminunc函数 : - 可用于任意函数求最小值 - 统一求最小值问题 - 如求最大值问题&#xff1a; >对函数取相反数而变成求最小值问题&#xff0c;最后把函数值取反即为函数的最大值。 使用格式如下 1.必须预先把函数存…

【机器学习】Gradient Descent for Logistic Regression

Gradient Descent for Logistic Regression 1. 数据集&#xff08;多变量&#xff09;2. 逻辑梯度下降3. 梯度下降的实现及代码描述3.1 计算梯度3.2 梯度下降 4. 数据集&#xff08;单变量&#xff09;附录 导入所需的库 import copy, math import numpy as np %matplotlib wi…

Django的生命周期流程图(补充)、路由层urls.py文件、无名分组和有名分组、反向解析(无名反向解析、有名反向解析)、路由分发、伪静态

一、orm的增删改查方法&#xff08;补充&#xff09; 1. 查询resmodels.表名(类名).objects.all()[0]resmodels.表名(类名).objects.filter(usernameusername, passwordpassword).all()res models.表名(类名).objects.first() # 判断&#xff0c;判断数据是否有# res如果查询…

如何通过github学生包认证(远程不在学校或在校但位置报错均可用)

如何通过github学生包认证 在经历11次被拒绝&#xff0c;查阅多方博客后&#xff0c;终于成功通过了github的学生认证&#xff0c;材料每次重复的话github又会让你提交不同的材料&#xff0c;博主最后都已经要没有材料可以证明自己是学生了&#xff0c;不得不说这个认证是真的…

git使用(由浅到深)

目录流程图 1. 分布式版本控制与集中式版本控制 1.1 集中式版本控制 集中式版本控制系统有:CVS和SVN它们的主要特点是单一的集中管理的服务器&#xff0c;保存所有文件的修订版本&#xff1b;协同开发人员通过客户端连接到这台服务器&#xff0c;取出最新的文件或者提交更新…

【C++】通讯录管理系统

1.系统功能介绍与展示 2.创建项目 3.菜单功能 代码&#xff1a; //-封装函数显示该界面 如 void showMenu() //-在main函数中调用封装好的函数 #include <iostream> using namespace std;//-菜单界面 void showMenu() {cout << "***************************…

Azure pipeline自动化打包发布

pipeline自动化&#xff0c;提交代码后&#xff0c;就自动打包&#xff0c;打包成功后自动发布 第一步 pipeline提交代码后&#xff0c;自动打包。 1 在Repos,分支里选择要触发的分支&#xff0c;这里选择cn_china,对该分支设置分支策略 2 在生产验证中增加新的策略 3 在分支安…

【Linux】yum工具的认识及使用

【Linux】yum工具的认识及使用 1.知识点补充2.yum是什么3.yum常用指令3.1查看软件安装包3.1.1关于rzsz 3.2安装软件3.3卸载软件 4.yum扩展4.1扩展14.2扩展24.3扩展3 什么是工具&#xff1f; 本质上也是指令 1.知识点补充 1.我们一般安装软件&#xff0c;是不是需要把软件安装…

LabVIEW FPGA开发实时滑动摩擦系统

LabVIEW FPGA开发实时滑动摩擦系统 由于非线性摩擦效应的建模和补偿的固有困难&#xff0c;摩擦系统的运动控制已被广泛研究。最近&#xff0c;人们更加关注滑动动力学和滑动定位&#xff0c;作为传统机器人定位的低成本和更灵活的驱动替代方案。摩擦控制器设计和适当选择基础…

JVM类加载器的作用和层次结构

类加载器的作用 1)通过一个类的全限定名来获取定义此类的二进制字节流。 2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。 3)在内存中生成一个代表这个类的java.lang.Class对象,这个对象存放在方法区中。这个对象将作为程序访问方法区中的这些数据的外部接…

【嵌入式学习笔记】嵌入式入门2——中断(外部中断)

1.什么是中断 打断CPU执行正常的程序&#xff0c;转而处理紧急程序&#xff0c;然后返回原暂停的程序继续运行&#xff0c;就叫中断 1.1.中断的作用与意义 作用1&#xff1a;实时控制在确定时间内对相应事件作出响应——定时器中断作用2&#xff1a;故障处理检测到故障&…

Linux内核的I2C驱动框架详解------这应该是我目前600多篇博客中耗时最长的一篇博客

目录 1 I2C驱动整体框架图 2 I2C控制器 2.1 I2C控制器设备--I2C控制器在内核中也被看做一个设备 2.2 i2c控制器驱动程序 2.3 platform_driver结构体中的probe函数做了什么 2.3.1 疑问&#xff1a; i2cdev_notifier_call函数哪里来的 2.3.2 疑问&#xff1a;为什么有两…

重生之我要学C++第六天

这篇文章的主要内容是const以及权限问题、static关键字、友元函数和友元类&#xff0c;希望对大家有所帮助&#xff0c;点赞收藏评论支持一下吧&#xff01; 更多优质内容跳转&#xff1a; 专栏&#xff1a;重生之C启程(文章平均质量分93) 目录 const以及权限问题 1.const修饰…