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

苍穹外卖实战:Spring Task与WebSocket联袂出击,打造高可靠订单状态与实时提醒系统

1. 为什么外卖系统需要订单状态自动处理与实时提醒?

想象一下你中午12点下单了一份外卖,支付完成后却迟迟不见商家接单。或者更糟的是,商家接单后骑手迟迟不来取餐,而系统却没有任何提醒。这种体验有多糟糕?这正是传统外卖系统的痛点——订单状态更新不及时,用户和商家都处于"盲等"状态。

在真实的苍穹外卖系统中,我们主要面临两个技术挑战:

  • 状态滞后:超时未支付订单占用库存,派送超时影响用户体验
  • 通知延迟:传统HTTP轮询消耗服务器资源,实时性差

我去年参与改造的一个餐饮系统就遇到过这样的问题:每天约有15%的订单因超时未处理引发客诉,客服团队30%的工作量都花在处理这类问题上。通过引入Spring Task+WebSocket的组合方案,最终实现了:

  • 超时订单自动处理准确率100%
  • 实时通知延迟从原来的平均8秒降低到200毫秒以内
  • 服务器负载下降40%

2. Spring Task定时任务实战:精准管理订单生命周期

2.1 定时任务配置三步走

首先在Spring Boot启动类加上@EnableScheduling注解:

@SpringBootApplication @EnableScheduling // 关键注解 public class SkyApplication { public static void main(String[] args) { SpringApplication.run(SkyApplication.class, args); } }

然后创建我们的订单任务类,这里有个坑我踩过——记得要用@Component注解让Spring管理:

@Component @Slf4j public class OrderTask { @Autowired private OrderMapper orderMapper; // 其他方法... }

2.2 超时订单处理实战

处理支付超时的核心逻辑是:查询状态为"待支付"且下单时间超过15分钟的订单。这里的时间计算有个技巧——使用LocalDateTime的plusMinutes方法:

@Scheduled(cron = "0 * * * * ?") // 每分钟执行 public void processTimeout() { LocalDateTime threshold = LocalDateTime.now().plusMinutes(-15); List<Orders> timeoutOrders = orderMapper.getByStatusAndTime( Orders.PENDING_PAYMENT, threshold ); timeoutOrders.forEach(order -> { order.setStatus(Orders.CANCELLED); order.setCancelReason("超时未支付"); orderMapper.update(order); log.info("已取消订单:{}", order.getNumber()); }); }

2.3 配送超时自动完成

对于配送中的订单,我们设置每天凌晨1点检查超过24小时的订单:

@Scheduled(cron = "0 0 1 * * ?") // 每天1点执行 public void processDeliveryTimeout() { LocalDateTime threshold = LocalDateTime.now().plusHours(-24); List<Orders> deliveringOrders = orderMapper.getByStatusAndTime( Orders.DELIVERY_IN_PROGRESS, threshold ); deliveringOrders.forEach(order -> { order.setStatus(Orders.COMPLETED); orderMapper.update(order); log.info("自动完成配送超时订单:{}", order.getNumber()); }); }

提示:测试阶段可以用"0/5 * * * * ?"这样的表达式每5秒执行一次,但生产环境一定要调整回合理频率

3. WebSocket实时通信深度整合

3.1 快速搭建WebSocket服务端

首先在pom.xml添加依赖:

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

配置类要注意的是需要暴露ServerEndpointExporter:

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

3.2 消息服务端核心实现

这个WebSocketServer类有几个关键点需要注意:

  1. 使用@ServerEndpoint定义访问路径
  2. 静态Map保存会话(注意线程安全)
  3. 三个核心生命周期方法
@Component @ServerEndpoint("/ws/{sid}") public class WebSocketServer { private static final Map<String, Session> sessions = new ConcurrentHashMap<>(); @OnOpen public void onOpen(Session session, @PathParam("sid") String sid) { sessions.put(sid, session); log.info("新连接:{}", sid); } @OnMessage public void onMessage(String message, @PathParam("sid") String sid) { log.debug("收到消息:{}", message); } @OnClose public void onClose(@PathParam("sid") String sid) { sessions.remove(sid); log.info("连接关闭:{}", sid); } public void sendToAll(String message) { sessions.forEach((sid, session) -> { try { session.getBasicRemote().sendText(message); } catch (IOException e) { log.error("发送消息失败", e); } }); } }

4. 订单状态与提醒的完整闭环实现

4.1 来单提醒的代码魔术

在订单支付成功后触发提醒,这里用到了消息类型区分(1=来单提醒):

public void paySuccess(String outTradeNo) { Orders order = orderMapper.getByNumber(outTradeNo); order.setStatus(Orders.TO_BE_CONFIRMED); orderMapper.update(order); Map<String, Object> message = new HashMap<>(); message.put("type", 1); // 来单提醒 message.put("orderId", order.getId()); message.put("content", "新订单:" + outTradeNo); webSocketServer.sendToAll(JSON.toJSONString(message)); }

4.2 客户催单功能实现

催单功能需要前后端配合,后端接口这样实现:

@GetMapping("/reminder/{id}") public Result reminder(@PathVariable Long id) { Orders order = orderMapper.getById(id); if (order == null) { throw new BusinessException("订单不存在"); } Map<String, Object> message = new HashMap<>(); message.put("type", 2); // 催单提醒 message.put("orderId", id); message.put("content", "催单:" + order.getNumber()); webSocketServer.sendToAll(JSON.toJSONString(message)); return Result.success(); }

4.3 前端如何处理WebSocket消息

前端需要根据消息类型做不同处理:

websocket.onmessage = function(event) { const msg = JSON.parse(event.data); switch(msg.type) { case 1: // 新订单 showNewOrderAlert(msg.content); break; case 2: // 催单 showReminderAlert(msg.content); break; default: console.warn('未知消息类型', msg); } };

5. 生产环境中的实战经验

在实际部署时,我们发现几个关键问题需要特别注意:

  1. WebSocket重连机制:网络不稳定时客户端需要自动重连
  2. 消息幂等处理:防止重复消息导致业务异常
  3. 集群环境适配:多节点时需要借助Redis的Pub/Sub功能

对于消息可靠性,我们最终采用的方案是:

  • 客户端收到消息后发送ACK确认
  • 服务端维护待确认消息队列
  • 超过3次未确认则转为短信通知

在性能优化方面,有两个特别有效的措施:

  1. 对WebSocket消息进行压缩(特别是包含订单详情时)
  2. 使用Protobuf替代JSON可减少30%以上的传输量

记得有一次线上事故:由于没有限制单个连接的消息频率,导致某个客户端异常发送大量消息拖垮服务端。后来我们增加了这样的限流逻辑:

@OnMessage public void onMessage(String message, @PathParam("sid") String sid) { if (rateLimiter.tryAcquire()) { // 限流 processMessage(message); } else { log.warn("消息频率过高:{}", sid); session.close(); } }
http://www.jsqmd.com/news/562813/

相关文章:

  • 3种突破实现Switch平台本地视频无缝播放
  • 用Verilog手搓一个IEEE754浮点加法器:从状态机设计到FPGA上板验证(附完整代码)
  • P12342 [蓝桥杯 2025 省 B/Python B 第二场] 数列差分
  • 3分钟上手:ControlNet-v1-1_fp16_safetensors让你的AI绘画更精准可控 [特殊字符]
  • 避坑指南:STM32 FATFS移植到SPI Flash的5个常见错误(附解决方案)
  • 2026含铜废水处理药剂除铜效率深度评测报告:锌镍专用重金属捕捉剂/锌镍除镍剂/高效破乳剂/高效重金属捕捉剂/选择指南 - 优质品牌商家
  • AGV、RGV、四向车调度系统(一)openTCS核心架构解析
  • conda创建环境报错repodata.json failed?手把手教你更换国内镜像源(2024最新)
  • 华硕笔记本性能释放新玩法:G-Helper CPU降压实战指南
  • 手把手教你用STM32F103C8T6和TB6612驱动直流电机(附HAL库代码)
  • I2C协议详解:从基础原理到工程实践
  • 从60+犬种数据集中,我总结出训练目标检测模型的3个关键避坑点
  • 鱼鱼刘怀旧手游|永恒岛高清重置版:4K 焕新归来,重走彩虹青春路
  • 用OpenMV和STM32F765VI做个追球小车:从硬件接线到PID调参的保姆级避坑指南
  • Matrix Color Sensor嵌入式RGBW色彩传感驱动设计
  • I2C总线信号特性与上拉电阻设计详解
  • 【Java工业互联网协议解析实战指南】:覆盖OPC UA、MQTT、Modbus TCP等7大协议的高可用解析框架设计与源码级拆解
  • 深入解析Infineon BTS54040-LBF高边芯片的SPI控制与汽车电子应用
  • Claude 4.7多模态Agent深度测评:实时视频推理能力到底提升了多少?
  • 孤能子视角:数字时代,“社会生产关系“[4],具身虚拟身份,耦合强度追责
  • 从Lending Club数据看机器学习在金融风控中的实战应用
  • 2026年硝酸钠公司权威推荐:粒硝/钠硝石/土硝/火硝/盐硝/粉硝/钾硝/农业级硝酸钾/工业级硝酸钾/硝石/选择指南 - 优质品牌商家
  • 等式方程的可满足性
  • 【电力系统】机会约束置信度参数以及安全裕量系数在综合能源系统调度中的应用研究(Matlab代码实现)
  • 3个信号预示你的应用不适合虚拟线程:IO密集型误判率高达79%,附自动检测工具Jar包下载
  • Linux下C程序编译全流程详解与实战
  • 虚拟线程CPU飙升、GC暴增、调度失序全复现,3大反模式避坑指南,附可复用监控脚本
  • 基于SpringBoot的老年人食堂系统
  • 基于中点电位平衡的光伏NPC三电平逆变器并网仿真研究:额定功率100kW、直流电压750V的M...
  • FinalBurn Neo终极指南:如何免费重温经典街机游戏体验