苍穹外卖【day10| 来电提醒和客户催单】

🌈个人主页 :一条泥憨鱼(欢迎各位大佬莅临)

❄️《数据结构》 ❄️《AI与Agent那些事》

❄️《从0开始学计算机网络》 ❄️《后端开发》

WebSocket

代码开发

复制代码
用户端                           服务端                              管理员端
  │                               │                                    │
  │  ① 用户下单 POST /user/order/submit   │                                │
  ├──────────────────────────────>┤                                    │
  │                               │                                    │
  │                          ② OrderServiceImpl                        │
  │                          ┌─────────────────────┐                   │
  │                          │ webSocketServer     │                   │
  │                          │ .sendToAdmin(...)   │                   │
  │                          └─────────────────────┘                   │
  │                               │                                    │
  │                          ③ WebSocketServer                         │
  │                          遍历所有连接会话                            │
  │                          发送 JSON 消息                             │
  │                               ├────────────────────────────────────┤
  │                               │         ws://localhost:xxx/ws/admin │
  │  ④ 收到消息,前端弹窗提醒       │<───────────────────────────────────┘
  │                               │                                    │
  │  ⑤ 用户点击催单 POST /user/order/reminder/{id}                      │
  ├──────────────────────────────>┤                                    │
  │                               │ ⑥ 同样走 sendToAdmin 发给管理员      │
  │                               ├────────────────────────────────────┤
  │                               │                                    │

1. WebSocketMessage.java --- 消息载体

java 复制代码
@Data
@Builder
public class WebSocketMessage implements Serializable {
    private Integer type;       // 消息类型:1=来单,2=催单
    private Integer orderId;    // 订单ID
    private String content;     // 显示文本
    private String orderTime;   // 下单时间

    public static final Integer NEW_ORDER = 1;   // 来单提醒
    public static final Integer REMINDER = 2;    // 催单提醒
}

设计思路:所有 WebSocket 消息都用同一个 POJO 承载,type 字段区分业务类型。前端拿到消息后 switch(type) 做不同处理。

2. WebSocketServer.java --- WebSocket 服务端

java 复制代码
@Component
@ServerEndpoint("/ws/{sid}")   // 客户端连接时带一个 sid 参数,如 /ws/admin
public class WebSocketServer {

    // 用 HashMap 存放所有连接会话,key 是客户端传入的 sid
    private static Map<String, Session> sessionMap = new HashMap<>();

    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        sessionMap.put(sid, session);  // 管理员连接进来,存入会话
    }

    @OnClose
    public void onClose(@PathParam("sid") String sid) {
        sessionMap.remove(sid);         // 管理员断开,移除会话
    }

    // sendToAdmin:给所有在线的管理员发送消息
    public void sendToAdmin(Integer type, Integer orderId, String content, String orderTime) {
        Collection<Session> sessions = sessionMap.values();
        for (Session session : sessions) {
            session.getBasicRemote().sendText(WebSocketMessage.toJson(...));
        }
    }
}

关键点sessionMap静态的 ,因为 @ServerEndpoint 每次新建连接都会创建新的 WebSocketServer 实例,而 Spring 管理的 Bean 是单例的,这里用静态 Map 来共享所有会话。


3. 用户下单 → 来单提醒(OrderServiceImpl.java)

submitOrder 方法中,订单插入数据库后,立即调用 WebSocket:

java 复制代码
@Transactional
public OrderSubmitVO submitOrder(OrdersSubmitDTO ordersSubmitDTO) {
    // ... 校验地址、购物车、插入订单等业务逻辑 ...

    orderMapper.insert(orders);         // 订单入库
    orderDetailMapper.insertBatch(...); // 订单明细入库
    shoppingCartMapper.deleteByUserId(userId); // 清空购物车

    // ⬇️ 这里新增:推送来单提醒给管理员
    webSocketServer.sendToAdmin(
        1,                                    // type = NEW_ORDER
        orders.getId().intValue(),            // 订单ID
        "您有新的外卖订单,订单号:" + orders.getNumber(), // 显示内容
        orders.getOrderTime().toString()      // 下单时间
    );

    return orderSubmitVO;
}

时序 :用户下单 → 数据库写入成功 → 立刻 WebSocket 推送。不需要轮询,事件驱动,零延迟。

4. 用户催单(user/OrderController.java)

java 复制代码
@PostMapping("/reminder/{id}")
@ApiOperation("催单")
public Result reminder(@PathVariable("id") Long orderId) {
    webSocketServer.sendToAdmin(
        2,                              // type = REMINDER
        orderId.intValue(),             // 订单ID
        "有用户催单了,订单号:" + orderId, // 显示内容
        null                            // 催单不需要时间
    );
    return Result.success();
}

特点:催单只是一个"提示触发",不查数据库,不改状态,直接推 WebSocket 消息。轻量级,对数据库零压力。

5. 前端接收示例(websocket.html)

javascript 复制代码
// 连接 WebSocket,sid 用来区分身份(管理员用 "admin")
const ws = new WebSocket("ws://localhost:8080/ws/admin");

ws.onmessage = function(event) {
    const data = JSON.parse(event.data);

    switch(data.type) {
        case 1:
            // 来单提醒:播放提示音 + 弹窗
            playSound();
            showNotification("新订单:" + data.content);
            break;
        case 2:
            // 催单提醒:播放提示音 + 弹窗
            playSound();
            showNotification("催单提醒:" + data.content);
            break;
    }
};

function playSound() {
    // 用 Audio 对象播放提示音
    new Audio('/sound/notice.mp3').play();
}
相关推荐
SunnyDays10111 小时前
Java 设置 Excel 数据验证:整数、日期、文本长度、下拉列表和时间
java·excel·数据验证·下拉列表
编程_大白1 小时前
@SpringBootTest
java
ly76891 小时前
Spring Boot 3.2 虚拟线程在 Web 层与 JDBC 池的实践边界
前端·spring boot·后端·tomcat·jdbc·虚拟线程
刘天远1 小时前
Agent最小权限实现:策略表、临时令牌与撤权回归
java·jvm·人工智能·sqlite
盖伦发发1 小时前
SpringCloud Alibaba Sentinel 教学:限流、熔断、降级、线程/信号量隔离、活动过载保护
后端·软件工程
QQ_21696290961 小时前
基于SpringBoot+Vue的小生活平台的设计与实现
java·数据库·vue.js·spring boot·spring·微信小程序·生活
前端兰博2 小时前
06-并发
java
程序员-珍2 小时前
Android studio 突然打不开
android·java
重生之小比特2 小时前
【Java SE】字符串 - String类
java·开发语言·intellij-idea