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

❄️《数据结构》 ❄️《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();
}