当前位置: 首页 > news >正文

二刷 苍穹外卖day10(含bug修改)

Spring Task

Spring框架提供的任务调度工具,可以按照约定的时间自动执行某个代码逻辑

cron表达式

一个字符串,通过cron表达式可以定义任务触发的时间
**构成规则:**分为6或7个域,由空格分隔开,每个域代表一个含义

每个域的含义分别为:秒、分钟、小时、日、月、周、年(可选)
cron表达式在线生成器:https://cron.qqe2.com/
可以直接在这个网站上面,只要根据自己的要求去生成corn表达式即可。所以一般就不用自己去编写这个表达式。
通配符:

* 表示所有值;? 表示未说明的值,即不关心它为何值;- 表示一个指定的范围;, 表示附加一个可能值;/ 符号前表示开始时间,符号后表示每次递增的值;
**cron表达式案例:***/5 * * * * ? 每隔5秒执行一次0 */1 * * * ? 每隔1分钟执行一次0 0 5-15 * * ? 每天5-15点整点触发0 0/3 * * * ? 每三分钟触发一次0 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发0 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发0 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
	/*** 处理支付超时订单*/@Scheduled(cron = "0 * * * * ?")public void processTimeoutOrder(){log.info("处理支付超时订单:{}", new Date());LocalDateTime time = LocalDateTime.now().plusMinutes(-15);// select * from orders where status = 1 and order_time < 当前时间-15分钟List<Orders> ordersList = orderMapper.getByStatusAndOrdertimeLT(Orders.PENDING_PAYMENT, time);if(ordersList != null && ordersList.size() > 0){ordersList.forEach(order -> {order.setStatus(Orders.CANCELLED);order.setCancelReason("支付超时,自动取消");order.setCancelTime(LocalDateTime.now());orderMapper.update(order);});}}

每分钟触发,每次触发会查询状态为1,即非付款且未付款时间大于15分钟的订单,拿到这些订单后将状态修改,更新到数据库中

	/*** 处理“派送中”状态的订单*/@Scheduled(cron = "0 0 1 * * ?")public void processDeliveryOrder(){log.info("处理派送中订单:{}", new Date());// select * from orders where status = 4 and order_time < 当前时间-1小时LocalDateTime time = LocalDateTime.now().plusMinutes(-60);List<Orders> ordersList = orderMapper.getByStatusAndOrdertimeLT(Orders.DELIVERY_IN_PROGRESS, time);if(ordersList != null && ordersList.size() > 0){ordersList.forEach(order -> {order.setStatus(Orders.COMPLETED);orderMapper.update(order);});}}

每天早上一点触发,将时间超过一个小时的订单进行修改

WebSocker

基于TCP的网络协议,实现了浏览器与服务器全双工通信,浏览器和服务器只需要一次握手,就可以创建持久性的连接,并进行双向数据传输。
与HTTP协议的对比:
HTTP是短连接,WebSocket是长连接
HTTP通信是单向,基于请求响应模式
WebSocket支持双向通信
HTTP和WebSocket底层都是TCP连接
![[Pasted image 20250701094005.png]]

WebSokcet缺点:
长期维护长连接有成本
各个浏览器支持程度不一
WebSocket是长连接,受网络限制比较大,需要处理好重连

WebSocket应用场景
1.视频弹幕
2.网页聊天
3.体育实况更新
4.股票基金报价实时更新

@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();}}}}

连接建立成功后存放会话对象:
sessionMap.put(sid,session);

连接关闭后调用:
sessionMap.remove(sid);

服务端给客户端发送信息:
session.getBasicRemote().sendText(messge);

“@ServerEndpoint” 表明该注解所标注的类是一个 WebSocket 服务器端点,它定义了 WebSocket 服务端与客户端进行通信的端点。“/ws/{sid}” 是这个 WebSocket 端点的路径,其中 “{sid}” 是一个占位符,代表会话标识符之类的动态参数,在实际使用中,这个参数值会被具体的内容替换,比如在客户端连接时传递一个具体的会话 ID,服务端就能根据这个路径和参数来处理不同的 WebSocket 连接请求。 例如,客户端可能通过 “ws://[localhost:8080/ws/12345](https://localhost:8080/ws/12345)” 这样的地址连接到这个 WebSocket 端点,其中 “12345” 就是替换 “{sid}” 的具体值。

和@RequestMapping的区别:

应用场景有别

  • WebSocket 服务端端点注解(@ServerEndpoint:主要用于创建基于 WebSocket 协议的通信通道。这种通信是全双工的,意味着客户端和服务端能够同时进行数据传输,比较适合需要实时通信的场景,像在线聊天、实时数据推送等。
  • Spring MVC 中处理 HTTP 请求的注解(@RequestMapping:用于构建 RESTful API,遵循的是 HTTP 请求 - 响应模式。客户端发送请求后,服务端进行处理并返回响应,之后连接就会关闭,主要适用于传统的 Web 应用场景。

通信模式不同

  • WebSocket 服务端端点注解(@ServerEndpoint:建立的是持久连接,在连接建立之后,客户端和服务端可以随时发送消息,无需重新建立连接。
  • Spring MVC 中处理 HTTP 请求的注解(@RequestMapping:采用的是无状态的请求 - 响应模式,每次请求都需要重新建立连接。

注解参数不一样

  • WebSocket 服务端端点注解(@ServerEndpoint:可以设置路径参数(如 /{sid})、子协议以及编码器 / 解码器等。
  • Spring MVC 中处理 HTTP 请求的注解(@RequestMapping:能够指定 HTTP 方法(GET、POST 等)、请求头、请求参数以及 consumes/produces 等内容。

方法签名有差异

  • WebSocket 服务端端点注解(@ServerEndpoint:端点方法要处理生命周期事件,例如 onOpenonMessageonClose 等。
  • Spring MVC 中处理 HTTP 请求的注解(@RequestMapping:方法的返回值会直接转换为 HTTP 响应,像 JSON、XML 等格式。

来单提醒

用户下单并支付成功后,需要第一时间同时外卖商家
通过WebSocket实现管理端页面和服务端保持长连接
客户支付后,调用WebSocket实现服务端向客户端推送消息
客户端浏览器解析服务器推送的消息,判断是来单提醒还是催单,进行对应的消息提示和语音播报
由于我并没有实现支付功能,所以原代码中的来单提醒在paySuccess中是无法调用的,我将其移动到了payment函数之中,并在Mapper中定义了一个新的查询函数

@Select("select * from orders where number=#{id} ")  
Orders getByOrderId(Long id);

service

  
@Override  
public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {  Long userId = BaseContext.getCurrentId();  userMapper.getById(userId);  JSONObject jsonObject = new JSONObject();  jsonObject.put("code", "ORDERPAID");  OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);  vo.setPackageStr(jsonObject.getString("package"));  Map map = new HashMap();  Long orderNumber= Long.valueOf(ordersPaymentDTO.getOrderNumber());  Orders byOrderId = orderMapper.getByOrderId(orderNumber);  //#########map.put("type", 1);//消息类型,1表示来单提醒  map.put("orderId", byOrderId.getId());  map.put("content", "订单号:" + orderNumber.toString());  //通过WebSocket实现来单提醒,向客户端浏览器推送消息  webSocketServer.sendToAllClient(JSON.toJSONString(map));  //#########return vo;  }

收到推送
![[Pasted image 20250701143111.png]]

bug修改

起因是在写代码的时候发现一直报服务器错误
![[Pasted image 20250701141324.png]]

我以为是我代码的问题,死活改不对。。。。
后面一看浏览器提示404,我就知道应该是前端发送的请求地址有问题,
找到这个文件,在里面搜索ws://localhost
![[Pasted image 20250701142638.png]]![[Pasted image 20250701142721.png]]

这里我的后端端口是8080,我就填的8080,具体看个人的后端端口
修改好之后重启nginx和java后端,刷新之后显示连接上了
![[Pasted image 20250701142823.png]]

总结

1. Spring Task

Spring框架提供的任务调度工具,可以按约定的时间自动执行某个代码逻辑
cron表达式 分为6或7个域,由空格分隔开
每个域含义分别为秒、分、时、日、月、周
通配符

2.WebSocker

基于TCP的网络协议,实现了全双工通信,更消耗资源,对网络要求高,适合频繁的资源传输
使用场景:
弹幕、实时聊天、实况更新、股票更新

3.@ServerEndPoint与@RequestMapping的区别

应用场景不同:@ServerEndPoint主要创建基于WebSocke协议,@RequestMapping遵循HTTP请求,客户端发送,服务器响应后关闭连接
通信模式不同:webSocket服务端端点注解建立的是持久连接,而HTTP请求采用的是无状态的请求-响应模式,每次请求都需要重新建立
注解参数不同:Websocket设置参数路径(/{sid})- `{sid}`是路径参数占位符,用于标识不同的客户端会话(如用户 ID)。在服务端方法中,通过`@PathParam("sid")`注解获取该参数
方法签名不同:WebSocket端点方法要处理生命周期事件,例如 `onOpen`、`onMessage`、`onClose` 等。@RequestMapping的返回值会转换为HTTP响应

4.WebSocket 服务端如何实现向所有客户端群发消息?

回答:
通过维护一个会话集合(如Map<String, Session>),遍历所有会话并调用sendText()方法:

public void sendToAllClient(String message) {for (Session session : sessionMap.values()) {session.getBasicRemote().sendText(message);}
}

其中sessionMap存储客户端 ID 与会话的映射,确保群发时能访问所有活跃连接。

5.WebSocket 连接时出现 404 错误,可能的原因有哪些?

  1. 服务端路径配置错误:如@ServerEndpoint的路径与客户端请求的 URL 不匹配(例:服务端为/ws/{sid},客户端请求/websocket/123)。
  2. 端口不匹配:客户端连接的端口(如ws://localhost:8080)与服务端实际端口不一致。
  3. 未正确部署 WebSocket 服务:如未添加@Component注解或未配置 WebSocket 容器。

WebSocket 的onOpenonMessageonClose方法的触发时机是什么?

  • onOpen:当客户端与服务端成功建立 WebSocket 连接时触发。
  • onMessage:当服务端接收到客户端发送的消息时触发。
  • onClose:当连接关闭(客户端断开、服务端主动关闭或异常断开)时触发。
http://www.dtcms.com/a/263904.html

相关文章:

  • 如何使用StartUML绘制类图,用例图,时序图入门
  • 转录组分析流程(二):差异分析
  • MySQL MVCC 详解
  • ChatGPT使用限额记录与插件统计
  • 杭州来未来科技 Java 实习面经
  • [C#] WPF - 自定义样式(Slider篇)
  • 【Hive SQL优化完全指南:从0.x到4.x的性能进化之路】
  • c# IO密集型与CPU密集型任务详解,以及在异步编程中的使用示例
  • [2025CVPR]DE-GANs:一种高效的生成对抗网络
  • 微分几何、旋量理论、李群李代数、黎曼度量、微分流形、SE(3)、SO(3)
  • java微服务-linux单机CPU接近100%优化
  • Jenkins × 容器技术:构建未来DevOps生态的超级引擎
  • 插入排序解析
  • C++ dll lib 以及编译链接加载的底层机制
  • 【从历史数据分析英特尔该如何摆脱困境】
  • 跨境证券交易系统合规升级白皮书:全链路微秒风控+开源替代,护航7月程序化交易新规落地
  • 手工部署与自动化部署场景模拟及参考项目
  • 数据结构与算法 第二章 线性表
  • Disruptor架构哲学
  • 【算法 day13】LeetCode 110.平衡二叉树 | 257. 二叉树的所有路径| 404.左叶子之和 |222.完全二叉树的节点个数
  • 【Python】字典get方法介绍
  • C++中的虚函数与纯虚函数
  • 【PaddleOCR】快速集成 PP-OCRv5 的 Python 实战秘籍--- PaddleOCR实例化 OCR 对象的参数介绍
  • css函数写个loading动画 | css预编译scss使用
  • YOLOv11性能评估全解析:从理论到实战的指标指南
  • GitHub已破4.5w star,从“零样本”到“少样本”TTS,5秒克隆声音,冲击传统录音棚!
  • 智能客服的进化论:当服务遇见 AI 的化学反应
  • 数据结构:递归:斐波那契数列(Fibonacci Sequence)
  • Android布局管理器实战指南:从LinearLayout到ConstraintLayout的优化之旅
  • 计算机网络第十章——网络层