黑马苍穹外卖8 Spring Task+WebSocket 来单提醒和客户催单

Spring Task

Spring提供的任务调度工具,按照约定时间自动执行代码。【以前的都是基于请求(http)响应的】

cron表达式

通过cron表达式可以定义任务触发时间。

cron表达式生成器

(1)导入spring-context

(2)@EnableScheduling开启任务调度,在启动类上加。

(3)自定义定时任务类

订单状态定时处理

超时订单处理

  1. 下单后未支付,订单一直处于"待支付"状态
    每分钟检查一次,判断时候否存在支付超时订单(下单超过15分钟认为支付则判定为支付超时订单),
    存在则修改订单状态为"已取消"
  2. 用户收货,订单一直处于"派送中"
    每天凌晨一点检查是否存在"派送中"的订单,存在则修改订单状态为"已完成"

task.OrderTask.java

java 复制代码
@Component
@Slf4j
public class OrderTask {

    @Autowired
    private OrderMapper orderMapper;

    /**
     * 处理超时订单
     */
    @Scheduled(cron = "0 * * * * ?")//每分钟触发一次  秒 分 时 日 月 周 年(可选)
    public void processTimeOutOrders() {
        LocalDateTime time = LocalDateTime.now().plusMinutes(-15);//当前时间-15
        // 根据这个去查 (处于待付状态的,下单时间<当前时间-15)
        List<Orders> orders = orderMapper.getByStatusAndOrderTimeLT(Orders.PENDING_PAYMENT, time);
        if (orders != null && orders.size() != 0) {
            List<Long> ids = new ArrayList<>();
            orders.forEach((order) ->
                ids.add(order.getId())
            );
            orderMapper.updateTimeOutByIds(Orders.CANCELLED, "订单超时,自动取消", LocalDateTime.now(), ids);//修改订单状态
        }
    }

    /**
     * 检查一直处于派送中的订单
     */
    @Scheduled(cron = "0 0 1 * * ?")//每天凌晨一点触发一次
    public void processDeliveringOrders() {
        LocalDateTime time = LocalDateTime.now().plusMinutes(-60);
        List<Orders> orders = orderMapper.getByStatusAndOrderTimeLT(Orders.DELIVERY_IN_PROGRESS, time);
        if (orders != null && orders.size() != 0) {
            List<Long> ids = new ArrayList<>();
            orders.forEach((order) ->
                ids.add(order.getId())
            );
            orderMapper.updateDeliveringByIds(Orders.COMPLETED, ids);
        }
    }

}
java 复制代码
@Select("select * from orders where status=#{status} and order_time<#{orderTime}")
    List<Orders> getByStatusAndOrderTimeLT(Integer status, LocalDateTime orderTime);

WebSocket

基于TCP的一种新的网络协议。实现了浏览器与服务器全双工通信 ------浏览器和服务器只需完成一次握手,两者就可以建立连接,双向数据传输

HTTP:浏览器(客户端)---服务器:浏览器请求服务器才响应。

WebSocket:两边都可以主动通信。

应用场景:网页聊天、视频弹幕,股票信息实时更新(服务器主动推送到网页上的)

java 复制代码
/**
 * WebSocket服务
 */
@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//类似@controller
    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();
            }
        }
    }

}

定时任务类:

task.WebSocketTask.java

java 复制代码
@Component
public class WebSocketTask {//定时任务类
    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 通过WebSocket每隔5秒向客户端发送消息
     */
    @Scheduled(cron = "0/5 * * * * ?")
    public void sendMessageToClient() {
        //调群发的方法
        webSocketServer.sendToAllClient("这是来自服务端的消息:" + DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now()));
    }
}

来单提醒

用户下单且支付成功即使通知商家。

请求:ws://localhost/ws/0yf1emeoqu8a

先请求到ngnix,然后nginx把请求转发到后端的Tomcat服务器

基于nginx的反向代理然后把请求转发过来的

在OrderServiceImpl.java 里public void paySuccess(String outTradeNo) 类中添加

java 复制代码
 //通过websocket想客户端推送消息 type prderId content
        //来单提醒
        HashMap<String, Object> map = new HashMap<>();
        map.put("type", 1);//1 来单提醒  2 客户接单
        map.put("orderId", ordersDB.getId());
        map.put("content", "订单号:" + outTradeNo);

        //发送给客户端
        webSocketServer.sendToAllClient(JSONObject.toJSONString(map));

客户催单

客户触发,客户发起的接口请求:

Controller:

java 复制代码
@GetMapping("/reminder/{id}")
    @ApiOperation("用户催单")
    public Result reminder(@PathVariable Long id){
        orderService.reminder(id);
        return Result.success();
    }

service

java 复制代码
 @Override
    public void reminder(Long id) {
        Orders order = orderMapper.getById(id);
        if (order == null) {
            throw new  OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }

        HashMap<String, Object> map = new HashMap<>();
        map.put("type",2);
        map.put("orderId",id);
        map.put("content","订单号:"+ id);

        webSocketServer.sendToAllClient(JSONObject.toJSONString(map));//向客户端推送消息
    }
相关推荐
芒果披萨5 分钟前
El表达式和JSTL
java·el
duration~1 小时前
Maven随笔
java·maven
zmgst1 小时前
canal1.1.7使用canal-adapter进行mysql同步数据
java·数据库·mysql
跃ZHD1 小时前
前后端分离,Jackson,Long精度丢失
java
blammmp1 小时前
Java:数据结构-枚举
java·开发语言·数据结构
暗黑起源喵2 小时前
设计模式-工厂设计模式
java·开发语言·设计模式
WaaTong2 小时前
Java反射
java·开发语言·反射
狂放不羁霸2 小时前
idea | 搭建 SpringBoot 项目之配置 Maven
spring boot·maven·intellij-idea
九圣残炎2 小时前
【从零开始的LeetCode-算法】1456. 定长子串中元音的最大数目
java·算法·leetcode
wclass-zhengge2 小时前
Netty篇(入门编程)
java·linux·服务器