1 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2 编写 WebSocket Handler
创建一个类来处理 WebSocket 连接的生命周期事件(建立、关闭、接收消息、发送错误)。
java
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.io.IOException;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* 创建一个类来处理 WebSocket 连接的生命周期事件(建立、关闭、接收消息、发送错误)
*/
public class MyTextWebSocketHandler extends TextWebSocketHandler {
// 存储所有活跃的会话,用于广播或其他操作
private static final CopyOnWriteArraySet<WebSocketSession> sessions = new CopyOnWriteArraySet<>();
/**
* 连接建立后执行
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.add(session);
System.out.println("WebSocket 连接建立: " + session.getId());
session.sendMessage(new TextMessage("欢迎连接到 WebSocket 服务!"));
}
/**
* 接收到客户端消息后执行
*/
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
System.out.println("收到消息: " + payload);
// 简单地回复客户端
session.sendMessage(new TextMessage("服务器已收到: " + payload));
session.sendMessage(new TextMessage("处理中..."));
// 模拟处理过程(随机等待 2-10s)
Thread.sleep(new Random().nextInt(8) * 1000 + 2000);
session.sendMessage(new TextMessage("处理完成: " + payload));
// 也可以广播给所有客户端
// broadcast(new TextMessage("📢 广播: " + payload));
}
/**
* 连接关闭后执行
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session);
System.out.println("WebSocket 连接关闭: " + session.getId() + ", 状态: " + status);
}
/**
* 发生错误时执行
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
if (session.isOpen()) {
session.close();
}
sessions.remove(session);
System.err.println("WebSocket 传输错误: " + exception.getMessage());
}
/**
* 广播消息给所有连接的客户端
*/
private void broadcast(TextMessage message) {
for (WebSocketSession session : sessions) {
if (session.isOpen()) {
try {
session.sendMessage(message);
} catch (IOException e) {
System.err.println("广播消息失败: " + e.getMessage());
}
}
}
}
}
3 编写 WebSocket 配置类
创建一个配置类来启用 WebSocket 功能,并注册一个或多个 WebSocket Endpoint。
java
@Configuration
@EnableWebSocket // 启用 WebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 注册一个 WebSocket Handler,并指定它的访问路径
// withAllowedOrigins("*") 允许所有来源(实际生产环境应限制)(生产环境应限制为具体域名)
registry.addHandler(new MyTextWebSocketHandler(), "/ws/myTextWeb")
.setAllowedOrigins("*");
}
}
4 客户端测试(HTML/JavaScript)
你可以使用一个简单的 HTML 页面和 JavaScript 来连接和测试你的 WebSocket 服务。
测试页位置:src/main/resources/static/websocket_test.html
html
<!DOCTYPE html>
<html>
<head>
<title>WebSocket 客户端测试</title>
<meta charset="utf-8">
</head>
<body>
<h1>WebSocket 客户端</h1>
<div id="messages"></div>
<input type="text" id="inputMessage" placeholder="输入消息">
<button onclick="sendMessage()">发送</button>
<script>
var webSocket;
var messagesDiv = document.getElementById('messages');
var inputMessage = document.getElementById('inputMessage');
// 假设你的 Spring Boot 应用运行在 8080 端口
var url = "ws://localhost:8080/ws/myTextWeb";
function connect() {
// 检查浏览器是否支持 WebSocket
if ('WebSocket' in window) {
webSocket = new WebSocket(url);
} else {
messagesDiv.innerHTML += '<p style="color:red;">当前浏览器不支持 WebSocket.</p>';
return;
}
// 连接成功事件
webSocket.onopen = function(event) {
messagesDiv.innerHTML += '<p style="color:green;"><b>连接成功!</b></p>';
};
// 接收消息事件
webSocket.onmessage = function(event) {
messagesDiv.innerHTML += '<p><b>收到:</b> ' + event.data + '</p>';
};
// 连接关闭事件
webSocket.onclose = function(event) {
messagesDiv.innerHTML += '<p style="color:red;"><b>连接关闭.</b></p>';
};
// 发生错误事件
webSocket.onerror = function(event) {
messagesDiv.innerHTML += '<p style="color:red;"><b>发生错误!</b></p>';
};
}
function sendMessage() {
var message = inputMessage.value;
if (webSocket && webSocket.readyState === WebSocket.OPEN) {
webSocket.send(message);
messagesDiv.innerHTML += '<p><b>发送:</b> ' + message + '</p>';
inputMessage.value = ''; // 清空输入框
} else {
messagesDiv.innerHTML += '<p style="color:orange;">连接未建立或已关闭,请先连接.</p>';
}
}
// ==========================================================
// 实现回车发送的关键代码
// ==========================================================
// 监听输入框的键盘抬起事件
inputMessage.addEventListener('keyup', function(event) {
// 检查按下的键是否是 Enter 键 (现代浏览器推荐 event.key)
if (event.key === 'Enter') {
// 阻止默认的表单提交等行为
event.preventDefault();
// 执行发送消息的函数
sendMessage();
}
});
// ==========================================================
// 页面加载完成后自动连接
window.onload = connect;
</script>
</body>
</html>
测试截图如下:

5 WebSocket 介绍
5.1 概述
WebSocket 是一种网络传输协议,旨在通过单个 TCP 连接提供全双工 (full-duplex)、双向 (bidirectional)、持久化 (persistent) 的通信通道。
-
全双工通信: 允许客户端和服务器在同一时间独立地发送和接收数据,无需等待另一方。
-
双向通信: 客户端和服务器都可以主动发送消息给对方。
-
持久化连接: 与传统的 HTTP 请求-响应模型不同,WebSocket 连接在建立后会保持打开状态,直到一方关闭,从而实现了低延迟的实时数据交换,减少了 HTTP 轮询的开销。
-
协议升级: WebSocket 连接通常是通过 HTTP 握手(
Upgrade请求头)开始,然后"升级"到 WebSocket 协议。
ws://localhost:8080/ws/myTextWeb

- URL 方案: 使用
ws://(非加密) 或wss://(加密) 作为 URL 方案。
5.2 构造函数
在 Web 浏览器环境中,通过 WebSocket() 构造函数来创建一个新的 WebSocket 对象并立即尝试建立连接:
javascript
new WebSocket(url);
new WebSocket(url, protocols);
-
url: 目标 WebSocket 服务器的 URL,必须使用ws或wss方案。 -
protocols(可选): 一个字符串或一个字符串数组,表示客户端希望使用的子协议(sub-protocol)。服务器会从列表中选择一个子协议,并可以通过WebSocket.protocol属性读取。
5.3 主要属性
|----------------|-------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 属性 | 类型 | 描述 |
| readyState | Number (常量) | 连接的当前状态。包括以下四个常量值: - WebSocket.CONNECTING (0): 正在尝试建立连接。 - WebSocket.OPEN (1): 连接已建立,可以进行通信。 - WebSocket.CLOSING (2): 正在关闭连接。 - WebSocket.CLOSED (3): 连接已关闭或无法打开。 |
| url | String | 构造函数中解析后的绝对 URL。 |
| protocol | String | 服务器选定的子协议的名称。如果未选择任何子协议,则为空字符串。 |
| binaryType | String | 连接接收二进制数据时如何暴露给脚本。可以是 "blob" (默认) 或 "arraybuffer"。 |
| bufferedAmount | Number | 已经进入排队但尚未发送到网络的数据字节数。 |
| onopen | Function | 用于监听 open 事件的事件处理器,连接建立时触发。 |
| onmessage | Function | 用于监听 message 事件的事件处理器,从服务器接收到数据时触发。 |
| onerror | Function | 用于监听 error 事件的事件处理器,发生错误时触发。 |
| onclose | Function | 用于监听 close 事件的事件处理器,连接关闭时触发。 |
5.4 主要方法
|------------------------------|-----------------------------------------------------------------------------|
| 方法 | 描述 |
| send(data) | 将数据(可以是字符串、Blob、ArrayBuffer 或 ArrayBufferView)放入队列,以便通过 WebSocket 连接传输到服务器。 |
| close([code] [, reason]) | 启动关闭握手,关闭连接。 |
| close([code] [, reason]) | - code (可选): 一个表示关闭状态码的数字(例如 1000 表示正常关闭)。 |
| close([code] [, reason]) | - reason (可选): 一个字符串,解释连接关闭的原因。 |