新建一个task包里面编写代码。
package com.sky.task;
/**
*定时任务类
*/
@Component
@Slf4j
public class OrderTask {
@Autowired
private OrderMapper orderMapper;
/**
* 处理超时订单的方法
*/
@Scheduled(cron = "0 * * * * ? ")//每分钟触发一次
public void processTimeOutOrder(){
log.info("定时处理超时订单:{}", LocalDateTime.now());
//select * from orders where status = ? and order_time < (当前时间-15分钟)
List<Orders> ordersList = orderMapper.getByStatusAndOrderTimeLT(Orders.PENDING_PAYMENT, LocalDateTime.now().plusMinutes(-15));
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点触发1次
public void processDeliveryOrder(){
log.info("定时处理处于派送中的订单:{}",LocalDateTime.now());
List<Orders> ordersList = orderMapper.getByStatusAndOrderTimeLT(Orders.DELIVERY_IN_PROGRESS, LocalDateTime.now().plusHours(-1));
if (ordersList != null && ordersList.size() > 0){
for (Orders orders : ordersList){
orders.setStatus(Orders.COMPLETED);
orderMapper.update(orders);
}
}
}
}
Mapper接口
/**
* 查询处理超时订单
* @return
*/
@Select("select * from orders where status = #{status} and order_time < #{orderTime}")
List<Orders> getByStatusAndOrderTimeLT(Integer status, LocalDateTime orderTime);
package com.sky.websocket;
import org.springframework.stereotype.Component;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* WebSocket服务
* 这个类使用了 @Component 注解,表明它是一个 Spring 管理的组件。
* @ServerEndpoint("/ws/{sid}") 注解表示这是一个 WebSocket 端点,路径为 /ws/{sid},其中 {sid} 是一个占位符。
* 在 onOpen 方法中,当有新的 WebSocket 连接建立时,将该连接的 Session 存储在 sessionMap 中。
* 在 onMessage 方法中,当收到客户端消息时,进行处理。
* 在 onClose 方法中,当连接关闭时,从 sessionMap 中移除相应的 Session。
* 提供了 sendToAllClient 方法,用于向所有连接的客户端广播消息。
*/
@Component
@ServerEndpoint("/ws/{sid}")
public class WebSocketServer {
//存放会话对象
private static Map<String, Session> sessionMap = new HashMap();
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("sid") String sid) {
System.out.println("客户端:" + sid + "建立连接");
sessionMap.put(sid, session);
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, @PathParam("sid") String sid) {
System.out.println("收到来自客户端:" + sid + "的信息:" + message);
}
/**
* 连接关闭调用的方法
*
* @param sid
*/
@OnClose
public 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();
}
}
}
}
导入配置类
/**
* WebSocket配置类,用于注册WebSocket的Bean
*/
@Configuration
public class WebSocketConfiguration {
/**
* WebSocket 配置类(WebSocketConfiguration):
* 这个配置类使用了 @Configuration 注解,表明它是一个配置类,Spring 会在启动时加载并处理它。
* 通过 @Bean 注解,它创建了一个 ServerEndpointExporter Bean,该 Bean 是 Spring WebSocket 标准的端点导出器。
* ServerEndpointExporter 的作用是将使用 @ServerEndpoint 注解声明的 WebSocket 端点注册到 Spring 容器中。
* @return
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
关系分析:
WebSocketConfiguration 中的 ServerEndpointExporter Bean 的存在,使得 Spring 能够自动检测并注册 WebSocketServer 中使用 @ServerEndpoint 注解声明的 WebSocket 端点。
WebSocketServer 类中通过 @ServerEndpoint 注解声明了一个 WebSocket 端点,并提供了处理连接建立、消息接收、连接关闭等逻辑。
当有新的 WebSocket 连接建立时,WebSocketServer 中的 onOpen 方法会被调用,将该连接的 Session 存储在 sessionMap 中。
当需要向所有客户端广播消息时,WebSocketServer 中的 sendToAllClient 方法会遍历 sessionMap,向每个客户端发送消息。
因此,通过 WebSocketConfiguration 的配置,WebSocketServer 中的 WebSocket 端点得以自动注册,而且可以在整个应用程序中共享 WebSocketServer 的实例。
在OrderService实现类中的函数修改
/**
* 支付成功,修改订单状态
*
* @param outTradeNo
*/
public void paySuccess(String outTradeNo) {
// 根据订单号查询订单
Orders ordersDB = orderMapper.getByNumber(outTradeNo);
// 根据订单id更新订单的状态、支付方式、支付状态、结账时间
Orders orders = Orders.builder()
.id(ordersDB.getId())
.status(Orders.TO_BE_CONFIRMED)
.payStatus(Orders.PAID)
.checkoutTime(LocalDateTime.now())
.build();
orderMapper.update(orders);
//通过websocket向客户端浏览器推送消息 type orderId Content
Map map = new HashMap();
map.put("type",1);//1表示来单提醒 2表示客户催单
map.put("orderId", ordersDB.getId());
map.put("content", "订单号:"+outTradeNo);
//转成json字符串
String jsonString = JSON.toJSONString(map);
webSocketServer.sendToAllClient(jsonString);
}
Controller层`
/**
*客户催单
*/
@GetMapping("/reminder/{id}")
@ApiOperation("客户催单")
public Result reminder(@PathVariable Long id){
orderService.reminder(id);
return Result.success();
}
Service实现类
/**
* 客户催单
* @param id
*/
@Override
public void reminder(Long id) {
//根据id查询订单
Orders orders = orderMapper.getByOrderId(id);
//校验订单是否存在
if (orders == null){
throw new OrderBusinessException(MessageConstant.ORDER_STATUS_ERROR);
}
Map map = new HashMap();
map.put("type", 2); //1表示来电提醒 2表示客户催单
map.put("orderId", id);
map.put("content", "订单号:" + orders.getNumber());
//通过websocket向客户端浏览器推送消息
webSocketServer.sendToAllClient(JSONObject.toJSONString(map));
}