SpringWebFlux对WebSocket有良好的支持,基于SpringWebFlux的异步非阻塞特性我们能很容易的开发高并发WebSocket服务,而且它的API设计与SpringMVC保持了一致,使用起来也相对简单。这篇笔记我们对SpringWebFlux中WebSocket的使用进行介绍。
和SpringMVC一样,SpringWebFlux中使用WebSocket需要创建一个实现WebSocketHandler
的类,只不过这里的WebSocketHandler
来自org.springframework.web.reactive.socket
包下。
package com.gacfox.demo.ws;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketMessage;
import org.springframework.web.reactive.socket.WebSocketSession;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
@Slf4j
public class DemoWebSocketHandler implements WebSocketHandler {
@Override
public Mono<Void> handle(WebSocketSession session) {
Flux<WebSocketMessage> outputFlux = session.receive()
.map(message -> {
String payload = message.getPayloadAsText(StandardCharsets.UTF_8);
log.info("payload: {}", payload);
return payload;
})
.map(messageText -> {
String payload = "echo: " + messageText;
return session.textMessage(payload);
});
return session.send(outputFlux);
}
}
代码中,我们的handle()
方法接收WebSocketSession
类型的参数,它是SpringWebFlux中处理WebSocket的会话对象,这个对象用于在服务器和客户端之间管理WebSocket连接,它提供了发送和接收消息的方法,并包含了会话上下文相关的信息。方法内部,我们首先调用了WebSocketSession
的receive()
方法,它返回Flux<WebSocketMessage>
类型的Publisher,我们在这里开始以响应式流的方式定义消息的处理管线,我们先取出收到的消息字符串并打印了消息内容,生成了响应信息字符串,然后将其封装回WebSocketMessage
作为响应。最后,我们调用了send()
方法向客户端发送消息。
定义好DemoWebSocketHandler
后我们还需要将其注册到SpringWebFlux框架,这需要构建并注册一个HandlerMapping
对象,下面是一个例子。
package com.gacfox.demo.config;
import com.gacfox.demo.ws.DemoWebSocketHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.reactive.socket.WebSocketHandler;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class WebConfig {
@Bean
public HandlerMapping handlerMapping() {
Map<String, WebSocketHandler> map = new HashMap<>();
map.put("/ws", new DemoWebSocketHandler());
int order = -1;
return new SimpleUrlHandlerMapping(map, order);
}
}
代码中,我们指定DemoWebSocketHandler
处理的URL是/ws
,它的order
被设置为-1
,表示这个HandlerMapping
的优先级最高,确保/ws
路径能被我们的DemoWebSocketHandler
最优先处理。