1. 添加依赖 (pom.xml)
<dependencies>
<!--
Spring Boot WebSocket 起步依赖
提供了对 Java WebSocket API (JSR-360 / Jakarta WebSocket) 的支持。
包含了 WebSocket 协议处理、会话管理、消息发送等核心功能。
注意:Spring Boot 3.x 基于 Jakarta EE,因此底层使用的是 jakarta.websocket 包。
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!--
Spring Messaging 模块
提供了对消息传递模式的支持,特别是 STOMP (Simple Text Oriented Messaging Protocol)。
使用 @EnableWebSocketMessageBroker 注解时必需,它允许在 WebSocket 上使用 STOMP 子协议。
STOMP 提供了更高级的抽象,如订阅、发布、消息代理等,比原始 WebSocket API 更易用。
-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
</dependency>
</dependencies>
2. 配置 WebSocket(Java Config)
package com.example.config;
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;
/**
* WebSocket 配置类
*
* 该类用于配置 Spring Boot 3.x 项目中的 WebSocket 支持,特别是基于 STOMP 协议的通信。
* 实现了 WebSocketMessageBrokerConfigurer 接口,可以自定义 WebSocket 消息代理的行为。
*
* 关键注解:
* - @Configuration: 将此类标记为 Spring 配置类,其定义的 Bean 会被 Spring 容器管理。
* - @EnableWebSocketMessageBroker: 启用 Spring 的 STOMP 消息代理功能。这是使用 STOMP over WebSocket 的核心注解。
* 它会自动配置必要的基础设施,如消息转换器、STOMP 帧处理、消息代理等。
*/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
/**
* 注册 STOMP 协议的端点(Endpoint)
*
* 这个方法定义了客户端如何连接到服务器的 WebSocket 服务。
* 客户端会通过这个端点建立初始的 HTTP 连接,并在此基础上升级为 WebSocket 连接。
*
* @param registry STOMP 端点注册器,用于注册和配置端点
*/
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws") // 添加一个名为 "/ws" 的端点
// .setAllowedOrigins("http://localhost:3000", "https://yourdomain.com") // 生产环境:只允许特定来源
.setAllowedOriginPatterns("*") // 允许所有来源的跨域请求
// 注意:setAllowedOriginPatterns("*") 在开发阶段方便,但**存在安全风险**。
// 生产环境中必须替换为具体的、受信任的域名列表,防止跨站请求伪造(CSRF)攻击。
.withSockJS(); // 启用 SockJS 支持
// SockJS 是一个浏览器 JavaScript 库,它提供了一个类似 WebSocket 的对象。
// 当浏览器或网络不支持原生 WebSocket 时(如某些防火墙限制),SockJS 会自动降级到
// 其他传输方式(如长轮询、iframe 流等),确保应用在各种环境下都能建立"类 WebSocket"连接。
// 这大大提高了应用的兼容性和健壮性。
}
/**
* 配置消息代理(Message Broker)
*
* 消息代理负责在客户端之间路由和广播消息。Spring 提供了两种主要的代理实现:
* 1. 简单内存代理 (Simple Broker): 由 Spring 内部实现,适用于单机部署和简单场景。
* 2. 外部代理 (External Broker): 如 RabbitMQ、ActiveMQ,支持更复杂的路由、持久化、集群等,适用于生产环境。
*
* 此方法配置了使用简单的内存消息代理。
*
* @param registry 消息代理注册器,用于配置消息代理的行为
*/
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// 启用一个简单的内存消息代理
// 该代理会监听以 "/topic" 和 "/queue" 开头的目的地(destination)。
// - "/topic" 前缀通常用于**发布-订阅**(Pub-Sub)模式:发送到 "/topic/greetings" 的消息会被所有订阅该主题的客户端收到(一对多广播)。
// - "/queue" 前缀通常用于**点对点**(Point-to-Point)模式:发送到 "/queue/tasks" 的消息通常只会被一个消费者处理(如果多个消费者订阅,行为可能取决于代理实现)。
// 注意:这里配置的前缀是客户端订阅或接收消息时使用的路径。
registry.enableSimpleBroker("/topic", "/queue");
// 设置应用的目的地前缀
// 所有以 "/app" 开头的消息会被路由到带有 @MessageMapping 注解的控制器方法进行处理。
// 例如,客户端发送一条目的地为 "/app/hello" 的消息,Spring 会查找并调用 @MessageMapping("/hello") 的方法。
// 这个前缀将“应用处理逻辑”与“消息代理广播”区分开来。
registry.setApplicationDestinationPrefixes("/app");
}
}
3. 定义消息模型(POJO)
package com.example.model;
/**
* 客户端发送的消息模型
* 表示客户端向服务器发送的请求数据,例如一个问候请求包含用户的名字。
*/
public class HelloMessage {
// 存储客户端发送的名字
private String name;
// 无参构造函数是 Jackson JSON 序列化/反序列化所必需的
public HelloMessage() {}
// 带参构造函数,方便创建对象
public HelloMessage(String name) {
this.name = name;
}
// Getter 方法,供 Jackson 库在序列化时读取属性值
public String getName() {
return name;
}
// Setter 方法,供 Jackson 库在反序列化 JSON 时设置属性值
public void setName(String name) {
this.name = name;
}
}
/**
* 服务器发送的响应消息模型
* 表示服务器处理完请求后,向客户端(或订阅者)广播的响应数据。
*/
public class GreetingMessage {
// 存储服务器生成的问候语内容
private String content;
// 无参构造函数是 Jackson JSON 序列化/反序列化所必需的
public GreetingMessage() {}
// 带参构造函数,方便创建对象
public GreetingMessage(String content) {
this.content = content;
}
// Getter 方法,供 Jackson 库在序列化时读取属性值
public String getContent() {
return content;
}
// Setter 方法,供 Jackson 库在反序列化 JSON 时设置属性值
public void setContent(String content) {
this.content = content;
}
}
4. 创建消息处理器(Controller)
package com.example.controller;
import com.example.model.GreetingMessage;
import com.example.model.HelloMessage;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
/**
* WebSocket 消息处理控制器
*
* 该类负责处理从客户端通过 WebSocket 发送过来的消息。
* 使用 @Controller 注解,使其成为 Spring MVC 控制器,能够处理消息映射。
*/
@Controller // 标记为 Spring 控制器,使其 Bean 能被组件扫描发现
public class GreetingController {
/**
* 处理客户端发送的问候消息
*
* 这个方法会被 Spring 框架调用,当有消息发送到 "/app/hello" 目的地时。
*
* @param message 由 Spring 自动反序列化传入的 HelloMessage 对象。
* 框架会根据消息的 payload(通常是 JSON)和类型信息,自动转换成 HelloMessage 实例。
* @return 返回一个 GreetingMessage 对象,该对象将被后续的 @SendTo 处理。
* @throws Exception 可能抛出异常(例如处理延迟时的 InterruptedException)
*
* 关键注解:
* - @MessageMapping("/hello"): 将此方法映射到目的地 "/app/hello"。
* 注意:完整的路径是 "应用前缀 + 映射路径" = "/app/hello"。
* 客户端需要发送消息到这个目的地才能触发此方法。
* - @SendTo("/topic/greetings"): 将此方法的返回值(GreetingMessage 对象)发送到 "/topic/greetings" 这个目的地。
* 所有订阅了 "/topic/greetings" 主题的客户端都会收到这个消息。
* 这实现了"请求-响应-广播"的模式:一个客户端发送请求,服务器处理后,结果广播给所有(或特定)订阅者。
*/
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public GreetingMessage greeting(HelloMessage message) throws Exception {
// 模拟服务器处理业务逻辑需要的时间(例如查询数据库、调用外部服务等)
Thread.sleep(1000);
// 构造响应消息
return new GreetingMessage("Hello, " + message.getName() + "!");
}
}
总结(后端要点与注释说明)
- 依赖清晰:
websocket提供协议支持,messaging提供 STOMP 高级功能。 - 配置核心:
@EnableWebSocketMessageBroker是启用 STOMP 的开关。registerStompEndpoints定义连接入口,configureMessageBroker定义消息路由规则(/app处理,/topic//queue广播)。 - 模型简单:POJO 类用于数据传输,需有无参构造和 Getter/Setter 以支持 JSON 序列化。
- 处理逻辑:
@MessageMapping接收请求,@SendTo发送响应到代理,实现广播。 - 安全注意:开发时
setAllowedOriginPatterns("*")方便,生产环境务必替换为具体可信域名。 - 兼容性:
withSockJS()提升了在复杂网络环境下的连接成功率。

2872

被折叠的 条评论
为什么被折叠?



