一、什么是 WebSocket?为什么需要它?

WebSocket 是一种在单个 TCP 连接上进行 全双工通信 的协议。与传统的 HTTP 请求-响应模式不同,WebSocket 允许服务器主动向客户端推送数据,非常适合实时性要求高的场景。

特性 HTTP WebSocket
通信模式 请求-响应(被动) 全双工(双向主动)
连接状态 无状态,短连接 有状态,持久连接
实时性 低(需轮询,延迟高) 高(毫秒级推送)
头部开销 大(每次携带完整头信息) 小(握手后仅需少量字节)

典型应用场景 :即时聊天室、股票行情推送、在线协作编辑、游戏实时状态同步。

二、环境准备与依赖

本教程基于 Spring Boot 3.x (对应 Spring Framework 6.x)和 JDK 17+

1、创建项目
使用 Spring Initializr 创建项目,勾选以下依赖:

  • Spring Web
  • Spring WebSocket
  • Lombok(可选,用于简化代码)

2、Maven 依赖
确保 pom.xml 中包含以下核心依赖:

<dependencies> <!-- Web基础依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- WebSocket核心依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-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 + JavaScript)

Spring WebSocket 默认支持 SockJS,前端可以使用 sockjs-client stompjs 库进行连接。

1、引入依赖
在 HTML 文件中引入以下 CDN 资源:

<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>

2、连接与通信代码

<script type="text/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、自定义 Handler

import 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 CopyOnWriteArrayList<WebSocketSession> 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 服务。

源代码仓库:https://github . com/zhshuixian/learn- spring - boot -2 码云:https://gitee . com/ylooq/learn- spring - boot -2 Spring 5 中最重要的更新是支持 Reactive (反应式)编程,反应式编程是非阻塞的,意味着无需阻塞等待业务处理完成,可以减少服务器资源的占用,提高并发处理速度和并发量。非常适合低延迟、高吞吐量的项目。可以用来构建非阻塞的、异步的、弹性和事件驱动的企业级服务。 Spring WebFlux .