【WebSocket教程】第9节:WebSocket 服务端搭建(Java)

🖥️第9节:WebSocket 服务端搭建(Java)

💬 引言

🏃‍ 哈喽,大家好!我是老曹。在上一节课中,我们学习了如何使用 Node.js 和 ws 库搭建 WebSocket
服务端。今天,我们将切换到 Java 生态系统,使用 Spring Boot 框架结合 WebSocket 来创建一个功能强大的后端服务。

Spring Boot 是 Java 开发者最常用的框架之一,其简洁的配置和强大的功能使得 WebSocket 服务端的开发变得更加高效。通过本节课的学习,你将掌握如何快速搭建一个基于 Spring Boot 的 WebSocket 服务端,并实现消息广播、点对点通信等核心功能。


🎯 学习目标

  1. 掌握 Spring Boot 集成 WebSocket 的基本方法
  2. 学会创建 WebSocket 服务端并处理连接事件
  3. 实现消息广播和点对点通信
  4. 理解 Spring Boot 中 WebSocket 的配置与优化
  5. 构建可扩展的 WebSocket 服务端架构

🛠️1. 准备工作

🔧1.1 创建 Spring Boot 项目

首先,我们需要创建一个 Spring Boot 项目。可以通过以下方式快速生成:

  1. 使用 Spring Initializr

  2. 手动添加依赖
    如果你已经有一个 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 性能优化

在高并发场景下,可以通过以下方式优化性能:

  1. 连接池管理:限制最大连接数。
  2. 异步处理:使用异步方法处理消息。
  3. 负载均衡:部署多个服务端实例,并使用负载均衡器分发流量。
示例代码(连接池管理):
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 实时聊天室系统

在实时聊天室系统中,服务端需要支持多人在线聊天。以下是完整的实现步骤:

  1. 用户身份管理:为每个客户端分配唯一 ID。
  2. 消息路由:支持广播和点对点通信。
  3. 在线状态管理:显示当前在线用户列表。
示例代码(在线状态管理):
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 的其他高级特性,如订阅发布模型和权限控制。希望大家能够将本节课的知识运用到实际开发中,并不断优化自己的代码。

📌 课后思考题

  1. 如何设计一个支持房间隔离的聊天系统?
  2. 在分布式系统中,如何实现跨节点的消息同步?
  3. 如何结合 Redis 提升 WebSocket 服务端的性能?

🤔 记住,优秀的开发者不仅要知道如何写代码,更要懂得为什么这样写。老曹期待在下一节课与大家再次相见!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈前端老曹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值