苍穹外卖07——来单提醒和客户催单(涉及SpringTask、WebSocket协议、苍穹外卖跳过微信支付同时保证可以收到订单功能)

devtools/2025/1/13 1:58:02/

Spring Task介绍

应用场景:

  • 信用卡每月还款提醒
  • 银行贷款每月还款提醒
  • 火车票销售系统处理未付款订单
  • 入职纪念日为用户发送通知

cron表达式

cron表达式其实就是一个字符串,通过cron表达式可以定义任务触发的时间。

构成规则:分为6或7个域,由空格分隔,每个域代表一个含义。

每个域的含义分别为:秒、分钟、小时、日、月、周、年(可选)。

秒 分钟 小时 日 月 周 年 

2022年10月12日上午9点整对应的cron表达式为:0 0 9 12 10 ? 2022

cron表达式在线生成器:Cron在线生成器 | 程序员导航网

Spring Task 使用步骤:

  1. 导入 Maven 坐标 spring-context(已存在)
  2. 在启动类添加注解 @EnableScheduling 开启任务调度
  3. 自定义定时任务类,新建一个Task包
    @Component
    @Slf4j
    public class MyTask {@Scheduled(cron = "0/5 * * * * ?") // 每五秒触发public void executeTask(){log.info("定时任务开始执行:{}", new Date());}
    }

订单状态定时处理 

@Component  // 将该类标记为Spring组件,以便自动扫描和管理  
@Slf4j  // 使用Lombok的@Slf4j注解,自动生成日志记录器  
public class OrderTask {  @Autowired  // 自动注入OrderMapper依赖  private OrderMapper orderMapper;  @Scheduled(cron = "0 * * * * ?")  // 每分钟执行一次  public void processTimeoutOrder() {  log.info("定时处理超时订单 {}", LocalDateTime.now());  // 记录当前时间的日志  // 当前时间减去15分钟  LocalDateTime time = LocalDateTime.now().plusMinutes(-15);  // 查询状态为待付款且订单时间早于当前时间减去15分钟的订单  List<Orders> ordersList = orderMapper.getByStatusAndOrderTimeLT(Orders.PENDING_PAYMENT, time);  // 如果查询到的订单列表不为空  if (ordersList != null && ordersList.size() > 0) {  for (Orders orders : ordersList) {  // 将订单状态设置为已取消  orders.setStatus(Orders.CANCELLED);  // 设置取消原因  orders.setCancelReason("订单超时,自动取消");  // 设置取消时间为当前时间  orders.setCancelTime(LocalDateTime.now());  // 更新订单信息  orderMapper.update(orders);  }  }  }  @Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1点执行  public void processDeliveryOrder() {  log.info("定时处理配送中的订单 {}", LocalDateTime.now());  // 记录当前时间的日志  // 当前时间减去60分钟  LocalDateTime time = LocalDateTime.now().plusMinutes(-60);  // 查询状态为配送中且订单时间早于当前时间减去60分钟的订单  List<Orders> ordersList = orderMapper.getByStatusAndOrderTimeLT(Orders.DELIVERY_IN_PROGRESS, time);  // 如果查询到的订单列表不为空  if (ordersList != null && ordersList.size() > 0) {  for (Orders orders : ordersList) {  // 将订单状态设置为已完成  orders.setStatus(Orders.COMPLETED);  // 更新订单信息  orderMapper.update(orders);  }  }  }  
}

WebSocket

WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信——一次握手,两者之间就可以建立持久性的连接,并进行双向数据传输。

HTTP协议和WebSocket协议对比:

  • HTTP是短连接
  • WebSocket是长连接
  • HTTP通信是单向的,基于请求响应模式
  • WebSocket支持双向通信
  • HTTP和WebSocket底层都是TCP连接

 选择使用 HTTP 协议还是 WebSocket 协议?

使用 HTTP 协议的情况

  1. 请求-响应结构

    • 如果你的应用主要以传统的请求-响应方式工作(例如,加载网页、提交表单等),那么 HTTP 是更合适的。
  2. 无持续连接

    • HTTP 适合于短暂的连接需求,每个请求和响应都是独立的。
  3. 安全和缓存

    • HTTP 支持缓存机制,可以提高静态资源的加载速度,同时可以通过 HTTPS 实现安全传输。
  4. 简单性

    • 对于相对简单的应用,使用 HTTP 通信更为直观和易于实现。

使用 WebSocket 协议的情况

  1. 实时双向通信

    • 当应用需要实时数据交换,如在线聊天、游戏、股票行情更新等,WebSocket 是更好的选择。
  2. 低延迟和高频率数据传输

    • WebSocket 允许在客户端和服务器之间建立持久连接,适用于需要频繁更新或低延迟的数据传输场景。
  3. 高效数据传输

    • WebSocket 在数据传输上比 HTTP 更为高效,因为它减少了开销,适合大规模应用。
  4. 无需频繁连接和断开

    • 如果应用需要保持长连接,WebSocket 可以避免频繁的连接和断开,节省资源和时间。

总结

  • HTTP:适用于传统请求-响应式的应用,简单和一次性的通信。
  • WebSocket:适用于需要实时、双向且高效沟通的应用。

WebSocket入门案例

导入坐标

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

 导完坐标之后新建配置类,使WebSocket的第三方bean由ioc容器管理

@Configuration
public class WebSocketConfiguration {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}

添加websocket的实体类

/*** WebSocket服务*/
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {//存放会话对象private static Map<String, Session> sessionMap = new HashMap();/*** 连接建立成功调用的方法*/@OnOpenpublic void onOpen(Session session, @PathParam("sid") String sid) {System.out.println("客户端:" + sid + "建立连接");sessionMap.put(sid, session);}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, @PathParam("sid") String sid) {System.out.println("收到来自客户端:" + sid + "的信息:" + message);}/*** 连接关闭调用的方法** @param sid*/@OnClosepublic 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();  // 捕获并打印异常  }  }  }}

苍穹外卖跳过微信支付同时保证可以收到订单功能

苍穹外卖遇到问题(包括跳过微信支付、nodejs不兼容等)-CSDN博客

来单提醒功能代码开发

需求分析和设计

  • 通过WebSocket实现管理端页面和服务端保持长连接状态
  • 当客户支付后,调用WebSocket的相关API实现服务端向客户端推送消息
  • 客户端浏览器解析服务端推送的消息,判断是来单提醒还是客户催单,进行相应的消息提示和语音播报
  • 约定服务端发送给客户端浏览器的数据格式为JSON,字段包括:type, orderId, content
    • type 为消息类型,1为来单提醒 2为客户催单
    • orderId 为订单id
    • content 为消息内容
/*** 订单支付* @param ordersPaymentDTO* @return*/public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {// 当前登录用户idLong userId = BaseContext.getCurrentId();User user = userMapper.getById(userId);JSONObject jsonObject = new JSONObject();jsonObject.put("code","ORDERPAID");OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);vo.setPackageStr(jsonObject.getString("package"));Integer OrderPaidStatus = Orders.PAID;//支付状态,已支付Integer OrderStatus = Orders.TO_BE_CONFIRMED;  //订单状态,待接单LocalDateTime check_out_time = LocalDateTime.now();//更新支付时间orderMapper.updateStatus(OrderStatus, OrderPaidStatus, check_out_time, this.os.getId());//通过websocket向客户端浏览器推送消息 type orderId contentMap map = new HashMap();map.put("type",1);map.put("orderId",this.os.getId());map.put("content","订单号:"+this.os.getNumber());String json = JSON.toJSONString(map);webSocketServer.sendToAllClient(json);return vo;}

如上面的代码,用户支付成功之后修改数据库中记录的订单的状态为已支付,然后发送websocket响应给管理端admin,然后在controller层发送vo实体类的响应给小程序用户端。

//通过websocket向客户端浏览器推送消息 type orderId content
Map map = new HashMap();
map.put("type",1);
map.put("orderId",this.os.getId());
map.put("content","订单号:"+this.os.getNumber());
String json = JSON.toJSONString(map);
webSocketServer.sendToAllClient(json);
return vo; // 发送给小程序端

管理员的浏览器端接收websocket响应。

深入了解websocket

  • websocket使用前一定要建立通信的信道,这样就可以实现双方的相互通信。
  • WebSocket通信通常是前端负责打开和关闭的,一旦连接建立,前端和后端可以通过这个通道双向发送和接收消息。

客户催单

// controller层
//客户催单@GetMapping("/reminder/{id}")@ApiOperation("客户端提醒")public Result reminder(@PathVariable("id") Long id){orderService.reminder(id);return Result.success();}// service层
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); // 类型map.put("orderId", id);map.put("content", "订单号: " + ordersDB.getNumber());// 发送websocket消息webSocketServer.sendToAllClient(JSON.toJSONString(map));}

http://www.ppmy.cn/devtools/150023.html

相关文章

(概率论)无偏估计

参考文章&#xff1a;(15 封私信 / 51 条消息) 什么是无偏估计&#xff1f; - 知乎 (zhihu.com) 首先&#xff0c;第一个回答中&#xff0c;马同学图解数学讲解得很形象&#xff0c; 我的概括是&#xff1a;“注意&#xff0c;有一个总体的均值u。然后&#xff0c;如果抽样n个&…

Unity + Firebase + GoogleSignIn 导入问题

我目前使用 Unity版本&#xff1a;2021.3.33f1 JDK版本为&#xff1a;1.8 Gradle 版本为&#xff1a;6.1.1 Firebase 版本: 9.6.0 Google Sign In 版本为&#xff1a; 1.0.1 问题1 &#xff1a;手机点击登录报错 apk转化成zip&#xff0c;解压&#xff0c;看到/lib/armeabi-v…

CES 2025|美格智能高算力AI模组助力“通天晓”人形机器人震撼发布

当地时间1月7日&#xff0c;2025年国际消费电子展&#xff08;CES 2025&#xff09;在美国拉斯维加斯正式开幕。美格智能合作伙伴阿加犀联合高通在展会上面向全球重磅发布人形机器人原型机——通天晓&#xff08;Ultra Magnus&#xff09;。该人形机器人内置美格智能基于高通QC…

GPT大模型下,如何实现网络自主防御

近年来&#xff0c;随着GPT大模型的出现&#xff0c;安全领域的攻防对抗变得更加激烈。RSAC2023人工智能安全议题重点探讨了人工智能安全的最新发展&#xff0c;包括人工智能合成器安全、安全机器学习以及如何利用渗透测试和强化学习技术来确保人工智能模型的安全性和可靠性。 …

Jina AI/Reader:将 URL 和 PDF 内容自动化提取并转换为 LLM 可处理文本

Jina AI/Reader:将 URL 和 PDF 内容自动化提取并转换为 LLM 可处理文本 前言一、Reader API :使用 r.jina.ai 读取 URL1.1 在浏览器地址栏中使用1.2 在Jina AI 的 API 仪表板中使用1.3 本地 PDF/HTML 文件内容解析二、Reader API :使用 s.jina.ai 搜索网络并返回结果2.1 在r…

Linux:进程概念(二.查看进程、父进程与子进程、进程状态详解)

目录 1. 查看进程 1.1 准备工作 1.2 指令&#xff1a;ps—显示当前系统中运行的进程信息 1.3 查看进程属性 1.4 通过 /proc 系统文件夹看进程 2. 父进程与子进程 2.1 介绍 2.2 getpid() \getppid() 2.3 fork()函数—通过系统调用创建进程 fork()函数疑问 3. 进程状态…

UniAPP和Vue3生命周期hook

Uni-app 是一个使用 Vue.js 开发跨平台应用的框架&#xff0c;支持编译到多个平台&#xff08;如 iOS、Android、H5、微信小程序等&#xff09;。在 Uni-app 中&#xff0c;生命周期钩子&#xff08;Lifecycle Hooks&#xff09;用于在应用或页面的不同阶段执行特定的逻辑。理解…

GDPU Android移动应用 重点习题集

目录 程序填空 ppt摘选 题目摘选 “就这两页ppt&#xff0c;你还背不了吗” “。。。” 打开ppt后 “Sorry咯&#xff0c;还真背不了&#x1f61c;” 更新日志 考后的更新日志 没想到重点勾了一堆&#xff0c;还愣是没考到其中的内容&#xff0c;翻了一下&#xff0c;原…