🖥️第9节:WebSocket 服务端搭建(Java)
💬 引言
🏃 哈喽,大家好!我是老曹。在上一节课中,我们学习了如何使用 Node.js 和
ws
库搭建 WebSocket
服务端。今天,我们将切换到 Java 生态系统,使用 Spring Boot 框架结合 WebSocket 来创建一个功能强大的后端服务。
Spring Boot 是 Java 开发者最常用的框架之一,其简洁的配置和强大的功能使得 WebSocket 服务端的开发变得更加高效。通过本节课的学习,你将掌握如何快速搭建一个基于 Spring Boot 的 WebSocket 服务端,并实现消息广播、点对点通信等核心功能。
🎯 学习目标
- 掌握 Spring Boot 集成 WebSocket 的基本方法
- 学会创建 WebSocket 服务端并处理连接事件
- 实现消息广播和点对点通信
- 理解 Spring Boot 中 WebSocket 的配置与优化
- 构建可扩展的 WebSocket 服务端架构
🛠️1. 准备工作
🔧1.1 创建 Spring Boot 项目
首先,我们需要创建一个 Spring Boot 项目。可以通过以下方式快速生成:
-
使用 Spring Initializr:
- 访问 https://start.spring.io/
- 选择 Maven 或 Gradle 作为构建工具。
- 添加依赖:
Spring Web
和WebSocket
。
-
手动添加依赖:
如果你已经有一个 Spring Boot 项目,可以在pom.xml
中添加以下依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
💡 关键点:
spring-boot-starter-websocket
提供了 WebSocket 支持。spring-boot-starter-web
用于构建 RESTful API(如果需要)。
🖥️2. 配置 WebSocket 服务端
🧩2.1 启用 WebSocket 支持
在 Spring Boot 中,通过实现 WebSocketConfigurer
接口来配置 WebSocket。
示例代码:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 注册 WebSocket 处理器
registry.addHandler(new ChatWebSocketHandler(), "/chat").setAllowedOrigins("*");
}
}
📌 注意:
/chat
是 WebSocket 的端点路径。setAllowedOrigins("*")
允许跨域访问(生产环境中应限制来源)。
🔄3. 实现 WebSocket 处理器
🧰3.1 创建 WebSocket 处理器
WebSocket 处理器负责处理客户端的连接、消息接收和发送等逻辑。我们可以通过继承 TextWebSocketHandler
类来实现。
示例代码:
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.concurrent.CopyOnWriteArrayList;
public class ChatWebSocketHandler extends TextWebSocketHandler {
// 保存所有连接的客户端会话
private final CopyOnWriteArrayList<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.add(session);
System.out.println("新客户端连接: " + session.getId());
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
System.out.println("收到消息: " + payload);
// 广播消息给所有客户端
broadcastMessage(payload);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session);
System.out.println("客户端断开连接: " + session.getId());
}
private void broadcastMessage(String message) throws IOException {
for (WebSocketSession session : sessions) {
if (session.isOpen()) {
session.sendMessage(new TextMessage(message));
}
}
}
}
💡 关键点:
CopyOnWriteArrayList
是线程安全的集合,适合多线程环境下的并发操作。handleTextMessage
方法用于处理接收到的消息。
📢4. 消息广播与点对点通信
🔄4.1 消息广播的实现
广播消息是指将一条消息发送给所有连接的客户端。以下是改进后的广播逻辑:
private void broadcastMessage(String senderId, String message) throws IOException {
String formattedMessage = String.format("{\"sender\":\"%s\",\"content\":\"%s\",\"timestamp\":%d}",
senderId, message, System.currentTimeMillis());
for (WebSocketSession session : sessions) {
if (!session.getId().equals(senderId) && session.isOpen()) {
session.sendMessage(new TextMessage(formattedMessage));
}
}
}
📌 优化点:
- 使用 JSON 格式封装消息,便于客户端解析。
- 排除发送者本身,避免消息回传。
📩4.2 点对点通信的实现
点对点通信是指将消息发送给特定的客户端。为了实现这一点,我们需要为每个客户端分配一个唯一的标识符。
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
JSONObject json = new JSONObject(payload);
String to = json.optString("to");
String content = json.optString("content");
if (to != null && !to.isEmpty()) {
// 点对点消息
WebSocketSession targetSession = findSessionById(to);
if (targetSession != null && targetSession.isOpen()) {
targetSession.sendMessage(new TextMessage(
String.format("{\"from\":\"%s\",\"content\":\"%s\",\"timestamp\":%d}",
session.getId(), content, System.currentTimeMillis())
));
} else {
System.out.println("目标客户端不存在或未连接");
}
} else {
// 广播消息
broadcastMessage(session.getId(), content);
}
}
private WebSocketSession findSessionById(String id) {
return sessions.stream()
.filter(session -> session.getId().equals(id))
.findFirst()
.orElse(null);
}
📌 注意:
- 使用
JSONObject
解析消息内容(需引入org.json
库)。 findSessionById
方法根据客户端 ID 查找对应的会话。
🚀5. 配置与优化
🔒5.1 跨域支持
在实际项目中,WebSocket 通常需要支持跨域访问。可以通过 setAllowedOrigins
方法进行配置:
registry.addHandler(new ChatWebSocketHandler(), "/chat")
.setAllowedOrigins("https://example.com");
📌 注意:
- 生产环境中应严格限制允许的来源,避免安全风险。
🧮5.2 性能优化
在高并发场景下,可以通过以下方式优化性能:
- 连接池管理:限制最大连接数。
- 异步处理:使用异步方法处理消息。
- 负载均衡:部署多个服务端实例,并使用负载均衡器分发流量。
示例代码(连接池管理):
private static final int MAX_CONNECTIONS = 100;
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
if (sessions.size() >= MAX_CONNECTIONS) {
System.out.println("超过最大连接数,拒绝新连接");
session.close();
return;
}
sessions.add(session);
System.out.println("新客户端连接: " + session.getId());
}
📊6. 实战案例分析
📢6.1 实时聊天室系统
在实时聊天室系统中,服务端需要支持多人在线聊天。以下是完整的实现步骤:
- 用户身份管理:为每个客户端分配唯一 ID。
- 消息路由:支持广播和点对点通信。
- 在线状态管理:显示当前在线用户列表。
示例代码(在线状态管理):
private final Map<String, String> userNames = new ConcurrentHashMap<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
String userId = session.getId();
sessions.add(session);
// 用户登录时记录昵称
userNames.put(userId, "User" + userId.substring(0, 4));
broadcastOnlineUsers();
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
String userId = session.getId();
sessions.remove(session);
// 用户登出时移除昵称
userNames.remove(userId);
broadcastOnlineUsers();
}
private void broadcastOnlineUsers() throws IOException {
String onlineUsers = new JSONArray(userNames.values()).toString();
for (WebSocketSession session : sessions) {
session.sendMessage(new TextMessage(
"{\"type\":\"onlineUsers\",\"users\":" + onlineUsers + "}"
));
}
}
🌟总结与展望
通过本节课的学习,我们掌握了如何使用 Spring Boot 搭建一个 WebSocket 服务端,并实现了消息广播、点对点通信等功能。这些知识将为后续的多人聊天室实战提供坚实的基础。
在接下来的课程中,我们将继续探索 WebSocket 的其他高级特性,如订阅发布模型和权限控制。希望大家能够将本节课的知识运用到实际开发中,并不断优化自己的代码。
📌 课后思考题:
- 如何设计一个支持房间隔离的聊天系统?
- 在分布式系统中,如何实现跨节点的消息同步?
- 如何结合 Redis 提升 WebSocket 服务端的性能?
🤔 记住,优秀的开发者不仅要知道如何写代码,更要懂得为什么这样写。老曹期待在下一节课与大家再次相见!