SpringTaskSpringTask是 Spring 框架Spring Framework中用于实现定时任务Task Scheduling的一个轻量级模块。在开发 Web 应用或后台管理系统时我们经常需要程序在特定的时间点如每天凌晨 2 点或者按固定的频率如每隔 5 分钟自动执行某些操作SpringTask 就是为了解决这类需求而生的。SpringTask是 Spring 框架Spring Framework中用于实现定时任务Task Scheduling的一个轻量级模块。在开发 Web 应用或后台管理系统时我们经常需要程序在特定的时间点如每天凌晨 2 点或者按固定的频率如每隔 5 分钟自动执行某些操作SpringTask 就是为了解决这类需求而生的。核心功能与特点轻量级相比于重量级的定时任务框架 QuartzSpringTask 配置更简单无需额外的数据库表或复杂的依赖。易用性只需简单的注解即可开启和定义任务。支持 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(cron0 * * * * ?)publicvoidprocessTimeOutOrder(){log.info(定时处理超时订单:{},LocalDateTime.now());LocalDateTimetimeLocalDateTime.now().plusMinutes(-15);ListOrdersordersListorderMapper.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})ListOrdersgetByStatusAndOrderTimeLT(Integerstatus,LocalDateTimeorderTime);定时处理未完成配送的订单/设置执行时间为凌晨1点下单时间为当前时间-1h查询未完成配送以及下单时间小于当前时间的订单Scheduled(cron0 0 1 * * ?)publicvoidprocessDelivery(){log.info(定时处理未完成的配送:{},LocalDateTime.now());LocalDateTimetimeLocalDateTime.now().plusMinutes(-60);ListOrdersordersListorderMapper.getByStatusAndOrderTimeLT(Orders.DELIVERY_IN_PROGRESS,time);for(Ordersorders:ordersList){orders.setStatus(Orders.COMPLETED);orders.setCancelReason(凌晨自动完成);orders.setCancelTime(LocalDateTime.now());orderMapper.update(orders);}}用户下单与催单提醒WebSocketWebSocket 是一种基于 TCP 的全双工通信协议客户端与服务器建立连接后双方都可以主动发送消息。WebSocket 特点长连接连接建立后不会频繁断开双向通信客户端、服务端都能主动发消息实时性高减少 HTTP 请求开销HTTP 与 WebSocket 区别HTTPWebSocket短连接长连接请求-响应双向通信服务端不能主动推送服务端可主动推送实时性一般实时性高工作流程1. 客户端发送 HTTP Upgrade 请求 2. 服务器返回 101 Switching Protocols 3. 建立 WebSocket 长连接 4. 双方实时通信常见应用聊天室在线游戏AI 流式输出实时通知直播弹幕用户下单WebSocket/** * WebSocket服务 */ComponentServerEndpoint(/ws/{sid})publicclassWebSocketServer{//存放会话对象privatestaticMapString,SessionsessionMapnewHashMap();/** * 连接建立成功调用的方法 */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){CollectionSessionsessionssessionMap.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){// 根据订单号查询订单OrdersordersDBorderMapper.getByNumber(outTradeNo);// 根据订单id更新订单的状态、支付方式、支付状态、结账时间OrdersordersOrders.builder().id(ordersDB.getId()).status(Orders.TO_BE_CONFIRMED).payStatus(Orders.PAID).checkoutTime(LocalDateTime.now()).build();orderMapper.update(orders);MapmapnewHashMap();map.put(type,1);//1表示来单提醒2是催单map.put(orderId,ordersDB.getId());map.put(content,订单号outTradeNo);StringjsonJSONObject.toJSONString(map);webSocketServer.sendToAllClient(json);}按照约定格式将typeorderIdcontent的键值对封装到map中转为json格式发送前端用户催单Controller/** * 用户催单 * param id * return */GetMapping(/reminder/{id})ApiOperation(用户催单)publicResultreminder(PathVariableLongid){log.info(用户催单);orderService.reminder(id);returnResult.success();}Service实现类publicvoidreminder(Longid){OrdersordersorderMapper.getById(id);if(ordersnull){thrownewOrderBusinessException(MessageConstant.ORDER_NOT_FOUND);}MapmapnewHashMap();map.put(type,2);map.put(orderId,id);map.put(content,订单号orders.getNumber());webSocketServer.sendToAllClient(JSONObject.toJSONString(map));}总结学习了SpringTask以及cron的编写格式websocket平时点外卖催单竟然是这样实现的