SpringBoot + WebSocket 实现实时消息推送(在线聊天/通知)

SpringBoot + WebSocket 实现实时消息推送(在线聊天/通知)

WebSocket 是实现服务端主动推送消息的常用技术,适用于在线聊天、系统通知、实时数据展示等场景。本文从零搭建一个 SpringBoot + WebSocket 的实时消息推送系统。

一、WebSocket 是什么

传统 HTTP 通信只能由客户端发起请求,服务端被动响应。WebSocket 建立连接后,服务端可以主动向客户端推送消息

对比HTTPWebSocket
通信方向客户端→服务端双向通信
连接方式每次请求新建连接建立连接后保持
实时性需要轮询即时推送
适用场景普通 API聊天、通知、实时数据

二、SpringBoot 整合 WebSocket

1. 引入依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>

2. 配置 WebSocket

@ConfigurationpublicclassWebSocketConfig{@BeanpublicServerEndpointExporterserverEndpointExporter(){returnnewServerEndpointExporter();}}

三、核心:WebSocket 服务端

@Component@ServerEndpoint("/ws/{userId}")@Slf4jpublicclassWebSocketServer{/** 存放每个用户的 WebSocket 连接 */privatestaticMap<String,Session>sessionMap=newConcurrentHashMap<>();/** * 连接建立成功 */@OnOpenpublicvoidonOpen(Sessionsession,@PathParam("userId")StringuserId){sessionMap.put(userId,session);log.info("用户 {} 已连接,当前在线人数: {}",userId,sessionMap.size());}/** * 连接关闭 */@OnClosepublicvoidonClose(@PathParam("userId")StringuserId){sessionMap.remove(userId);log.info("用户 {} 已断开,当前在线人数: {}",userId,sessionMap.size());}/** * 收到客户端消息 */@OnMessagepublicvoidonMessage(Stringmessage,@PathParam("userId")StringuserId){log.info("收到用户 {} 的消息: {}",userId,message);}/** * 发生错误 */@OnErrorpublicvoidonError(Sessionsession,Throwableerror){log.error("WebSocket 错误",error);}/** * 向指定用户推送消息 */publicstaticvoidsendToUser(StringuserId,Stringmessage){Sessionsession=sessionMap.get(userId);if(session!=null&&session.isOpen()){try{session.getBasicRemote().sendText(message);}catch(IOExceptione){log.error("推送消息失败",e);}}}/** * 向所有用户广播消息 */publicstaticvoidbroadcast(Stringmessage){sessionMap.values().forEach(session->{try{session.getBasicRemote().sendText(message);}catch(IOExceptione){log.error("广播消息失败",e);}});}/** * 获取在线用户数 */publicstaticintgetOnlineCount(){returnsessionMap.size();}}

四、服务端主动推送消息

在 Controller 中调用 WebSocket 推送消息:

@RestController@RequestMapping("/push")publicclassPushController{/** * 推送给指定用户 */@PostMapping("/user/{userId}")publicResultVOpushToUser(@PathVariableStringuserId,@RequestBodyStringmessage){WebSocketServer.sendToUser(userId,message);returnResultVO.success("推送成功");}/** * 广播给所有用户 */@PostMapping("/broadcast")publicResultVObroadcast(@RequestBodyStringmessage){WebSocketServer.broadcast(message);returnResultVO.success("广播成功");}/** * 获取在线人数 */@GetMapping("/online")publicResultVOgetOnlineCount(){returnResultVO.success(WebSocketServer.getOnlineCount());}}

五、前端页面连接 WebSocket

<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>WebSocket 消息推送</title></head><body><h3>WebSocket 实时消息</h3><div><inputtype="text"id="userId"placeholder="用户ID"value="user001"><buttononclick="connect()">连接</button><buttononclick="disconnect()">断开</button></div><divstyle="margin-top:10px;"><divid="messages"style="border:1px solid #ccc;height:300px;overflow-y:scroll;padding:10px;"></div></div><script>letwebsocket=null;functionconnect(){constuserId=document.getElementById('userId').value;websocket=newWebSocket('ws://localhost:8080/ws/'+userId);websocket.onopen=function(){appendMessage('✅ 连接成功,用户ID: '+userId);};websocket.onmessage=function(event){appendMessage('📩 收到消息: '+event.data);};websocket.onclose=function(){appendMessage('❌ 连接已断开');};websocket.onerror=function(error){appendMessage('⚠️ 连接出错');};}functiondisconnect(){if(websocket){websocket.close();}}functionappendMessage(msg){constdiv=document.getElementById('messages');div.innerHTML+='<div>'+msg+'</div>';div.scrollTop=div.scrollHeight;}</script></body></html>

六、实战:系统通知推送

实际项目中,在业务代码中调用推送:

@ServicepublicclassOrderService{publicvoidcreateOrder(Orderorder){// 1. 保存订单orderMapper.insert(order);// 2. 推送通知给用户JSONObjectmsg=newJSONObject();msg.put("type","order_notify");msg.put("orderId",order.getId());msg.put("message","您的订单已创建成功");WebSocketServer.sendToUser(order.getUserId().toString(),msg.toJSONString());}}

客户端收到消息后,根据type字段做相应处理:

websocket.onmessage=function(event){constdata=JSON.parse(event.data);if(data.type==='order_notify'){showNotification('📦 '+data.message);}elseif(data.type==='system_notify'){showNotification('🔔 '+data.message);}};

七、常见问题

1. WebSocket 连接被拦截

如果项目中有拦截器,需要放行 WebSocket 请求:

registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/ws/**");// 放行 WebSocket

2. 跨域问题

@BeanpublicServerEndpointExporterserverEndpointExporter(){returnnewServerEndpointExporter();}// WebSocket 原生不支持跨域配置// SpringBoot 方式需要在配置中添加@BeanpublicWebSocketConfigurerwebSocketConfigurer(){returnregistry->registry.addHandler(webSocketHandler(),"/ws/{userId}").setAllowedOrigins("*");}

3. 心跳保活

WebSocket 长时间空闲可能被断开,定期发送心跳包:

// 客户端每 30 秒发送心跳setInterval(()=>{if(websocket&&websocket.readyState===WebSocket.OPEN){websocket.send('ping');}},30000);

总结

WebSocket 是实时消息推送的首选方案。SpringBoot 整合 WebSocket 非常简单,三步走:

  1. 引入依赖+配置
  2. 编写 WebSocketServer—— @OnOpen、@OnClose、@OnMessage
  3. 业务代码调用推送—— 面向指定用户或广播

如果对你有帮助,欢迎点赞、评论、关注【张老师技术栈】,持续分享 Java/Python/爬虫 实战干货。