苍穹外卖day10

📅 2026/7/9 0:14:00 👁️ 阅读次数 📝 编程学习
苍穹外卖day10

SpringTask

SpringTask是 Spring 框架(Spring Framework)中用于实现定时任务(Task Scheduling)的一个轻量级模块。

在开发 Web 应用或后台管理系统时,我们经常需要程序在特定的时间点(如每天凌晨 2 点)或者按固定的频率(如每隔 5 分钟)自动执行某些操作,SpringTask 就是为了解决这类需求而生的。

SpringTask是 Spring 框架(Spring Framework)中用于实现定时任务(Task Scheduling)的一个轻量级模块。

在开发 Web 应用或后台管理系统时,我们经常需要程序在特定的时间点(如每天凌晨 2 点)或者按固定的频率(如每隔 5 分钟)自动执行某些操作,SpringTask 就是为了解决这类需求而生的。


核心功能与特点

  1. 轻量级:相比于重量级的定时任务框架 Quartz,SpringTask 配置更简单,无需额外的数据库表或复杂的依赖。
  2. 易用性:只需简单的注解即可开启和定义任务。
  3. 支持 Cron 表达式:可以灵活定义复杂的执行时间规则。

常见执行方式 (Cron 表达式)

Cron 表达式是 SpringTask 的精髓,它的格式通常为:秒 分 时 日 月 周

表达式含义
0/5 * * * * ?每隔 5 秒执行一次
0 0/1 * * * ?每隔 1 分钟执行一次
0 0 8 * * ?每天早上 8:00 执行一次
0 0 0 1 * ?每月 1 号凌晨执行一次

适用场景

  • 数据同步:定期将缓存(如 Redis)中的数据同步回数据库。
  • 自动清理:定时删除服务器上的临时文件或过期日志。
  • 状态检查:每隔一段时间检查订单是否超时并自动关闭。
  • 定时推送:每天固定时间给用户发送日报或提醒。

配置

SpringTask包含在SpringContext中,而在springboot默认配置中包含了SpringTask

在启动类上加入@EnableScheduling

创建定时任务类

定时处理超时未支付订单

每分钟获取到一次超时十五分钟且未支付的订单,自动取消订单,设置取消原因为订单超时

@Scheduled(cron="0 * * * * ?")publicvoidprocessTimeOutOrder(){log.info("定时处理超时订单:{}",LocalDateTime.now());LocalDateTimetime=LocalDateTime.now().plusMinutes(-15);List<Orders>ordersList=orderMapper.getByStatusAndOrderTimeLT(Orders.PENDING_PAYMENT,time);if(ordersList!=null&&!ordersList.isEmpty()){for(Ordersorders:ordersList){orders.setStatus(Orders.CANCELLED);orders.setCancelReason("订单超时");orders.setCancelTime(LocalDateTime.now());orderMapper.update(orders);}}
@Select("select * from orders where status=#{status} and order_time<#{orderTime}")List<Orders>getByStatusAndOrderTimeLT(Integerstatus,LocalDateTimeorderTime);

定时处理未完成配送的订单/

设置执行时间为凌晨1点,下单时间为当前时间-1h,查询未完成配送以及下单时间小于当前时间的订单

@Scheduled(cron="0 0 1 * * ?")publicvoidprocessDelivery(){log.info("定时处理未完成的配送:{}",LocalDateTime.now());LocalDateTimetime=LocalDateTime.now().plusMinutes(-60);List<Orders>ordersList=orderMapper.getByStatusAndOrderTimeLT(Orders.DELIVERY_IN_PROGRESS,time);for(Ordersorders:ordersList){orders.setStatus(Orders.COMPLETED);orders.setCancelReason("凌晨自动完成");orders.setCancelTime(LocalDateTime.now());orderMapper.update(orders);}}

用户下单与催单提醒

WebSocket

WebSocket 是一种基于 TCP 的全双工通信协议,客户端与服务器建立连接后,双方都可以主动发送消息。


WebSocket 特点

  • 长连接(连接建立后不会频繁断开)
  • 双向通信(客户端、服务端都能主动发消息)
  • 实时性高
  • 减少 HTTP 请求开销

HTTP 与 WebSocket 区别

HTTPWebSocket
短连接长连接
请求-响应双向通信
服务端不能主动推送服务端可主动推送
实时性一般实时性高

工作流程

1. 客户端发送 HTTP Upgrade 请求 2. 服务器返回 101 Switching Protocols 3. 建立 WebSocket 长连接 4. 双方实时通信

常见应用

  • 聊天室
  • 在线游戏
  • AI 流式输出
  • 实时通知
  • 直播弹幕

用户下单

WebSocket

/** * WebSocket服务 */@Component@ServerEndpoint("/ws/{sid}")publicclassWebSocketServer{//存放会话对象privatestaticMap<String,Session>sessionMap=newHashMap();/** * 连接建立成功调用的方法 */@OnOpenpublicvoidonOpen(Sessionsession,@PathParam("sid")Stringsid){System.out.println("客户端:"+sid+"建立连接");sessionMap.put(sid,session);}/** * 收到客户端消息后调用的方法 * * @param message 客户端发送过来的消息 */@OnMessagepublicvoidonMessage(Stringmessage,@PathParam("sid")Stringsid){System.out.println("收到来自客户端:"+sid+"的信息:"+message);}/** * 连接关闭调用的方法 * * @param sid */@OnClosepublicvoidonClose(@PathParam("sid")Stringsid){System.out.println("连接断开:"+sid);sessionMap.remove(sid);}/** * 群发 * * @param message */publicvoidsendToAllClient(Stringmessage){Collection<Session>sessions=sessionMap.values();for(Sessionsession:sessions){try{//服务器向客户端发送消息session.getBasicRemote().sendText(message);}catch(Exceptione){e.printStackTrace();}}}}
  • @compoment交给 Spring 管理。
  • @ServerEndpoint(“/ws/{sid}”)声明 WebSocket 访问路径。
  • 客户端连接:ws://localhost:8080/ws/1001 其中:1001会被:@PathParam(“sid”)接收
  • Session为当前客户端连接对象
  • @OnMessage为客户发消息时触发
  • @onclose连接关闭后触发
  • 群发,sessions获取全部连接对象

整体执行流程:

客户端连接

OnOpen

保存Session

客户端发送消息

OnMessage

服务器处理

sendText推送

客户端断开

OnClose

来单提醒

publicvoidpaySuccess(StringoutTradeNo){// 根据订单号查询订单OrdersordersDB=orderMapper.getByNumber(outTradeNo);// 根据订单id更新订单的状态、支付方式、支付状态、结账时间Ordersorders=Orders.builder().id(ordersDB.getId()).status(Orders.TO_BE_CONFIRMED).payStatus(Orders.PAID).checkoutTime(LocalDateTime.now()).build();orderMapper.update(orders);Mapmap=newHashMap();map.put("type",1);//1表示来单提醒,2是催单map.put("orderId",ordersDB.getId());map.put("content","订单号"+outTradeNo);Stringjson=JSONObject.toJSONString(map);webSocketServer.sendToAllClient(json);}

按照约定格式将type,orderId,content的键值对封装到map中转为json格式发送前端

用户催单

Controller

/** * 用户催单 * @param id * @return */@GetMapping("/reminder/{id}")@ApiOperation("用户催单")publicResultreminder(@PathVariableLongid){log.info("用户催单");orderService.reminder(id);returnResult.success();}

Service实现类

publicvoidreminder(Longid){Ordersorders=orderMapper.getById(id);if(orders==null){thrownewOrderBusinessException(MessageConstant.ORDER_NOT_FOUND);}Mapmap=newHashMap();map.put("type",2);map.put("orderId",id);map.put("content","订单号"+orders.getNumber());webSocketServer.sendToAllClient(JSONObject.toJSONString(map));}

总结

学习了SpringTask,以及cron的编写格式,websocket,平时点外卖催单竟然是这样实现的