前言
WebFlux 本身提供了对 WebSocket 协议的支持,处理 WebSocket 请求需要对应的 handler 实现 WebSocketHandler 接口,每一个 WebSocket 都有一个关联的 WebSocketSession,包含了建立请求时的握手信息 HandshakeInfo
,以及其它相关的信息。可以通过 session 的 receive()
方法来接收客户端的数据,通过 session 的 send()
方法向客户端发送数据。
示例
下面是一个简单的 WebSocketHandler 示例:
@Component
public class EchoHandler implements WebSocketHandler {
public Mono<Void> handle(WebSocketSession session) {
return session.send(
session.receive().map(
msg -> session.textMessage("ECHO -> " + msg.getPayloadAsText())));
}
}
有了 handler 之后,还需要让 WebFlux 知道哪些请求需要交给这个 handler 进行处理,因此要创建相应的 HandlerMapping。
在处理 HTTP 请求时,我们经常使用 WebFlux 中最简单的 handler 定义方式,即通过注解 @RequestMapping
将某个方法定义为处理特定路径请求的 handler。 但是这个注解是用于处理 HTTP 请求的,对于 WebSocket 请求而言,收到请求后还需要协议升级的过程,之后才是 handler 的执行,所以我们不能直接通过该注解定义请求映射,不过可以使用 SimpleUrlHandlerMapping 来添加映射。
@Configuration
public class WebSocketConfiguration {
@Bean
public HandlerMapping webSocketMapping(EchoHandler echoHandler) {
final Map<String, WebSocketHandler> map = new HashMap<>(1);
map.put("/echo", echoHandler);
final SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Ordered.HIGHEST_PRECEDENCE);
mapping.setUrlMap(map);
return mapping;
}
@Bean
public WebSocketHandlerAdapter handlerAdapter() {
return new WebSocketHandlerAdapter();
}
}
这样就能够将发往 /echo
的 WebSocket 请求交给 EchoHandler 处理。
我们还要为 WebSocket 类型的 handler 创建对应的 WebSocketHandlerAdapter,以便让 DispatcherHandler 能够调用我们的 WebSocketHandler。
完成这三个步骤后,当一个 WebSocket 请求到达 WebFlux 时,首先由 DispatcherHandler 进行处理,它会根据已有的 HandlerMapping 找到这个 WebSocket 请求对应的 handler,接着发现该 handler 实现了 WebSocketHandler 接口,于是会通过 WebSocketHandlerAdapter 来完成该 handler 的调用。
疑惑
从上面的例子不难看出,没接收一个请求后,就得在里面里面返回消息,后面就不能再给他发消息了。其次是我每次新添加或者删除一个消息的处理类Handler,就得每次去修改配置文件中的SimpleUrlHandlerMapping的UrlMap的内容,感觉不是很友好。于是针对这2点进行修改和调整如下: