Spring Boot 集成 WebSocket

  1. 1. 发消息给用户
  2. 2. 广播发消息
  3. 3. 处理消息
  4. 4. 消息拦截处理 ChannelInterceptor

得益于 Spring Boot 约定大于配置的特性,集成 Websocket 非常简单,只需在依赖中加入对应的 starter 就可完成引入。

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

加入 starter 后,websocket 已经完成引入,这时可以使用 @Configuration 类来配置,然后使用 @EnableWebSocketMessageBroker 来启用 WS。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@EnableWebSocketMessageBroker
@Configuration
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOrigins("*");
}

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(1);
taskScheduler.setThreadNamePrefix("wss-heartbeat-thread-");
taskScheduler.initialize();

registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/notice", "/message")
.setHeartbeatValue(new long[] {20000,20000})
.setTaskScheduler(taskScheduler);
}
}

WebSocketMessageBrokerConfigurer 的实现类用于对 WS 进行配置。上面代码中 registerStompEndpoints 方法注册了 ws 的处理 URL 前缀, /ws 开头的请求将由 WS 对应的 handler 处理,客户端将通过 /ws 来连接到服务器中。

ApplicationDestinationPrefixes 表示 destination 前缀为该值的时候,消息会由 @MessageMapping 注解的方法处理。

SimpleBroker 对应的是 destination 前缀为该值的时候,消息会发给 message broker 处理,相当于发给订阅了对应的 destination 的客户。

发消息给用户

用户可以订阅 /user/message 表示订阅用户专属的 /message 消息。/user 前缀表示用户标识的 destination。例如用户 A 订阅了该消息, 服务器发送消息给用户 A 应该发送给 /user/A/message destination,而 A 用户应该订阅的 destination 是 /user/message

广播发消息

/user/message 消息是专属消息,Spring Boot 的 STOMP 可以和 MQ 样支持发布订阅形式,多个订阅了该 destination 的用户都可以同时收到消息。

专属消息其实也是一种发布订阅的消息,只是只有当前用户订阅了该 destination 而已。

/user/message 实际上会转为 /user/message{userId}
/user/A/message 实际上也是 /user/message{userId}

处理消息

前面使用 message broker 相当于只是使用了集成的 WebSocket 实现了简单的 MQ 而已,我们更多的是需要自定义一些消息处理逻辑,然后再通过 message broker 将消息转发给用户。

要实现消息的处理也很简单,就像处理 HTTP 请求一样使用 @Controller 既可,不一样的只是 @RequestMapping 换成了 @MessageMapping

注解 说明
@MessageMapping 用于配置对应的 destination
@Payload 用于 @MessageMapping 注解的方法参数中,表示消息的内容。
@DestinationVariable 类似于 @PathVariable,用于从请求的 destination 中取出变量。
@SendToUser 表示返回值发给当前用户的 destination。
@SendTo 表示返回值发给指定的 destination。

消息拦截处理 ChannelInterceptor

通过实现 ChannelInterceptor 接口,我们可以实现 WebSocket 的鉴权等特殊处理。