苍穹外卖项目日记(day10)

发布于:2025-07-17 ⋅ 阅读:(19) ⋅ 点赞:(0)

苍穹外卖|项目日记(day10)

​ 前言: 第10天的任务相对接单, 主要是熟悉一下SpringTask和WebSocket, 不过由于WebSocket代码比较固定, 直接导入即可

吐槽下, md文件导入到csdn上, 本地上传的图片老是丢失, 需要重新导入, 这是我比较讨厌的一点, 害的我再做笔记时都尽量不使用图片.
在这里插入图片描述

今日收获:

1.熟悉SpingTask

2.了解WebSocket

3. 来单提醒和客户催单业务实现

一.SpringTask

1.Spring Task 是 Spring 框架提供的任务调度模块,用于实现定时任务功能。

2.核心特性

  1. 轻量级:作为 Spring 框架的一部分,无需额外依赖
  2. 注解驱动:通过 @Scheduled注解即可定义定时任务
  3. 灵活配置:支持 cron 表达式、固定延迟、固定速率等多种调度方式
  4. 线程池支持:可以配置任务执行的线程池

3.基本使用

a.在项目启动类上加上开启任务调度注解
@SpringBootApplication
@EnableTransactionManagement //开启注解方式的事务管理
@Slf4j
@EnableCaching // 增加缓存注解
@EnableScheduling // 开启任务调度
public class SkyApplication {
    public static void main(String[] args) {
        SpringApplication.run(SkyApplication.class, args);
        log.info("server started");
    }
}

b.创建任务调度, 加上Scheduled注解,并设置cron
Component
@Slf4j
public class OrderTask {

    @Autowired
    private OrderMapper orderMapper;
    /**
     * 处理超时订单
     */
    @Scheduled(cron = "0 * * * * ?") // 每分钟触发一次
//    @Scheduled(cron = "1/5 * * * * ?")
    public void processTimeoutOrder(){
        log.info("定时处理超时订单: {}", LocalDateTime.now());
        // 待付款订单超时15分钟取消
        LocalDateTime time = LocalDateTime.now().plusMinutes(-15);
        Integer status = Orders.PENDING_PAYMENT;

        List<Orders> list = orderMapper.getByStatusandOrderTime(status, time);

        if(list != null && list.size() > 0){
            for (Orders orders : list) {
                // 取消订单, 设置修改时间
                orders.setStatus(Orders.CANCELLED);
                orders.setCancelTime(LocalDateTime.now());
                orders.setCancelReason("订单超时, 自动取消");
                orderMapper.update(orders);

            }
        }
    }
}

[!tip]

cron表达式可以通过网页在线生成, 并不需要耗费太长时间去记

二. 了解websocket

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,它使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。

1. WebSocket 基础

1.1 WebSocket 特点
  • 全双工通信:客户端和服务器可以同时发送和接收数据
  • 低延迟:相比 HTTP 轮询,WebSocket 通信更高效
  • 持久连接:建立连接后保持打开状态
  • 基于事件:通过事件监听处理消息

Java WebSocket 详解

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,它使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。

1. WebSocket 基础

1.1 WebSocket 特点

  • 全双工通信:客户端和服务器可以同时发送和接收数据
  • 低延迟:相比 HTTP 轮询,WebSocket 通信更高效
  • 持久连接:建立连接后保持打开状态
  • 基于事件:通过事件监听处理消息

1.2 WebSocket 与 HTTP 对比

特性 HTTP WebSocket
通信方式 请求-响应 全双工
连接 短连接 长连接
服务器推送 不支持 支持
协议 无状态 有状态

2 核心注解

  • @ServerEndpoint: 声明一个 WebSocket 服务端点
  • @OnOpen: 连接建立时触发
  • @OnClose: 连接关闭时触发
  • @OnMessage: 收到消息时触发
  • @OnError: 发生错误时触发

3. Spring WebSocket 实现

Spring 框架提供了对 WebSocket 的高级支持,包括:

  • STOMP 协议支持
  • 消息代理集成
  • 更简单的编程模型
3.1基本配置
/**
 * WebSocket配置类,用于注册WebSocket的Bean
 */
@Configuration
public class WebSocketConfiguration {

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

}

3.2自定义处理
/**
 * 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
    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();
            }
        }
    }

}

三.来单提醒和客户催单业务实现

1.来单提醒

​ 由于我是跳过微信支付的, 只是简单的模拟来电提醒, 并不是真的支付,.

​ 逻辑: 在用户支付成功后, 让服务端向商家管理端发送来电提醒, 所以只需在paysuccess中使用websocket方法就行

如图:

在这里插入图片描述

代码:

/**
     * 支付成功,修改订单状态
     *
     * @param outTradeNo
     */
    public void paySuccess(String outTradeNo) {

        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();

        // 根据订单号查询当前用户的订单
        Orders ordersDB = orderMapper.getByNumberAndUserId(outTradeNo, userId);

        // 根据订单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);

        String json = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(json);

    }

2.客户催单

​ 此接口也相对简单, 没有过多的业务逻辑, 只需服务端向商家发送催单信息

代码:

/**
     * 用户催单
     * @param id
     */
    @Override
    public void reminder(Long id) {

        // type orderid content
        // 根据id查询订单
        Orders ordersDB = orderMapper.getById(id);

        // 校验订单是否存在
        if (ordersDB == null) {
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }

        Map map = new HashMap();
        map.put("orderid", ordersDB.getId());
        map.put("type", 2);
        map.put("content", "订单号: " + ordersDB.getNumber());

        String json = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(json);
    }




网站公告

今日签到

点亮在社区的每一天
去签到