Spring Boot 3.x WebSocket 实战教程
一、什么是 WebSocket为什么需要它WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。与传统的 HTTP 请求-响应模式不同WebSocket 允许服务器主动向客户端推送数据非常适合实时性要求高的场景。特性HTTPWebSocket通信模式请求-响应被动全双工双向主动连接状态无状态短连接有状态持久连接实时性低需轮询延迟高高毫秒级推送头部开销大每次携带完整头信息小握手后仅需少量字节典型应用场景即时聊天室、股票行情推送、在线协作编辑、游戏实时状态同步。二、环境准备与依赖本教程基于Spring Boot 3.x对应 Spring Framework 6.x和JDK 17。1、创建项目使用 Spring Initializr 创建项目勾选以下依赖Spring WebSpring WebSocketLombok可选用于简化代码2、Maven 依赖确保pom.xml中包含以下核心依赖dependencies !-- Web基础依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- WebSocket核心依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-websocket/artifactId /dependency /dependencies三、核心实现基于 STOMP 的消息代理模式Spring 提供了基于 STOMP 协议的 WebSocket 支持它比原生 API 更易于使用类似于消息队列的发布/订阅模式。1、配置 WebSocket创建一个配置类启用 WebSocket 消息代理并注册端点。import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; Configuration EnableWebSocketMessageBroker // 启用WebSocket消息代理 public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { Override public void configureMessageBroker(MessageBrokerRegistry registry) { // 启用简单的内存消息代理客户端订阅以 /topic 开头的目的地 registry.enableSimpleBroker(/topic); // 设置客户端发送消息的前缀即 /app registry.setApplicationDestinationPrefixes(/app); } Override public void registerStompEndpoints(StompEndpointRegistry registry) { // 注册端点 /ws客户端将通过此路径建立连接 // withSockJS() 提供了对不支持 WebSocket 浏览器的降级支持 registry.addEndpoint(/ws).withSockJS(); } }2、编写消息控制器创建一个控制器来处理客户端的消息发送和广播。import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.stereotype.Controller; Controller public class ChatController { /** * 处理客户端发送的消息 * MessageMapping(/chat) 对应客户端发送目标 /app/chat * SendTo(/topic/messages) 将返回值广播给所有订阅 /topic/messages 的客户端 */ MessageMapping(/chat) SendTo(/topic/messages) public ChatMessage sendChatMessage(ChatMessage message) { // 这里可以添加业务逻辑如保存消息到数据库 System.out.println(收到消息: message.getContent()); return message; } }3、定义消息实体import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; Data NoArgsConstructor AllArgsConstructor public class ChatMessage { private String username; private String content; private long timestamp; }四、前端客户端连接HTML JavaScriptSpring WebSocket 默认支持 SockJS前端可以使用sockjs-client和stompjs库进行连接。1、引入依赖在 HTML 文件中引入以下 CDN 资源script srchttps://cdn.jsdelivr.net/npm/sockjs-client1/dist/sockjs.min.js/script script srchttps://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js/script2、连接与通信代码script typetext/javascript var stompClient null; // 1. 建立连接 function connect() { // 创建 SockJS 对象指向后端注册的端点 /ws var socket new SockJS(/ws); // 使用 STOMP 协议包装 stompClient Stomp.over(socket); stompClient.connect({}, function (frame) { console.log(连接成功: frame); // 2. 订阅消息主题 stompClient.subscribe(/topic/messages, function (message) { // 接收服务器广播的消息 showMessage(JSON.parse(message.body)); }); }); } // 3. 发送消息 function sendMessage() { var messageContent document.getElementById(inputMessage).value; var chatMessage { username: User_ Math.floor(Math.random() * 1000), content: messageContent, timestamp: new Date().getTime() }; // 发送到 /app/chat (对应后端的 MessageMapping(/chat)) stompClient.send(/app/chat, {}, JSON.stringify(chatMessage)); } function showMessage(message) { var response document.getElementById(response); var p document.createElement(p); p.innerText message.username : message.content; response.appendChild(p); } // 页面加载完成后连接 window.onload connect; /script五、进阶使用原生 WebSocketHandler如果你不需要 STOMP 协议只想处理简单的文本消息可以使用WebSocketHandler。1、自定义 Handlerimport org.springframework.stereotype.Component; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; import java.util.concurrent.CopyOnWriteArrayList; Component public class MyCustomHandler extends TextWebSocketHandler { // 线程安全的会话列表 private static final CopyOnWriteArrayListWebSocketSession sessions new CopyOnWriteArrayList(); Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { sessions.add(session); session.sendMessage(new TextMessage(欢迎连接当前在线人数: sessions.size())); } Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { // 广播消息给所有连接者 for (WebSocketSession s : sessions) { if (s.isOpen()) { s.sendMessage(new TextMessage(广播: message.getPayload())); } } } Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { sessions.remove(session); } }2、注册 Handler在配置类中注入并注册Configuration EnableWebSocket // 注意这里启用原生 WebSocket 支持 public class NativeWebSocketConfig implements WebSocketConfigurer { Autowired private MyCustomHandler myCustomHandler; Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { // 注册路径 /ws-native允许跨域 registry.addHandler(myCustomHandler, /ws-native).setAllowedOrigins(*); } }六、常见问题排查404 Not Found检查EnableWebSocketMessageBroker或EnableWebSocket是否遗漏以及端点路径/ws是否正确。跨域问题确保在registerWebSocketHandlers中配置了.setAllowedOrigins(*)或指定具体域名。握手失败如果是生产环境使用 Nginx 反向代理需要配置 Upgrade 头proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade;通过以上步骤你可以在 Spring Boot 3.x 中快速搭建起稳定高效的 WebSocket 服务。