spring框架对websocket有很好的支持,stomp协议作为websocket的子协议,Spring也做了很多封装,让我们在开发中易于使用。
学习使用Spring的Websocket模块,当然最好的办法就是看官网说明了。本篇文章对官网做一些简述和个人的理解。
开始使用
依赖引入
第一步当然是引入SpringBoot的包了
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
这个包实际上引入了两个依赖spring-messaging 和 spring-websocket
如何开启stomp的支持
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/portfolio");
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.setApplicationDestinationPrefixes("/app");
config.enableSimpleBroker("/topic", "/queue");
}
}
- registry.addEndpoint(“/portfolio”); 添加一个后端,前端可以通过这个端点,进行websocket通信
对应的前端代码可以这么写
var socket = new SockJS('/portfolio');
stompClient = Stomp.over(socket);
- config.setApplicationDestinationPrefixes(“/app”); 这个是前端可以往这个路径发送消息。
前端代码这么写的:
stompClient.send("/app/echo", {}, JSON.stringify(msg));
后端可以定义一个controller,来接收这个消息,所以这个/app的意思可以理解为所有@MessageMapping的前缀。
@Controller
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class StompController {
@MessageMapping("/echo")
public void echo(Principal principal, Msg msg) {
//代码略
}
}
- config.enableSimpleBroker(“/topic”, “/queue”); 这个是启用消息broker。广播消息的前缀。当我们需要发送广播消息给客户端时,需要满足这个前缀条件。
前端这么订阅消息,是topic前缀
//订阅广播消息topic
stompClient.subscribe("/topic/boardCast/hello", function (response) {
});
后端代码通过消息broker,可以将此消息发送给订阅了"/topic/boardCast/hello"的客户端。
public class StompController {
private final SimpMessageSendingOperations msgOperations;
public void test(message) {
msgOperations.send("/topic/boardCast/hello",message);
}
}
消息的流转过程
首先得理解以下几个概念
- Message: 消息,包括消息头和消息体.
- MessageHandler: 处理消息的处理器
- MessageChannel:消息通道,客户端发送消息,到达服务器(inboundChannel)。服务器通过通道(outboundChannel)发送消息给客户端
- MessageBroker:消息分发的处理器,消息怎么流转,是由broker分发的
代码示例
前端往/app/echo发送了一条消息
//主动发送消息给服务器,对应的后端topic为/app/echo2
function send() {
var value = document.getElementById("content").value;
var msg = {
msgType: 1,
content: value
};
stompClient.send("/app/echo2", {}, JSON.stringify(msg));
}
后端代码得注册/app前缀
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.setApplicationDestinationPrefixes("/app");
config.enableSimpleBroker("/topic", "/queue");
}
}
然后定义一个Controller来接收用户消息, @MessageMapping(“/echo”),这里就是子路径了,拼起来正好是/app/echo,这时Wesocket请求会到达echo方法。
@Controller
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class StompController {
private final SimpMessageSendingOperations msgOperations;
@MessageMapping("/echo2")
public void echo2() {
msgOperations.convertAndSend("/topic/boardCast/hello", "hello boardCast Message");
}
}
上面示例代码的执行流程,消息的流转如下图所示
- 消息通过inboundChannel到服务器
- 此时根据消息的前缀,会匹配出/app开头的,是需要找SimpAnnotationMethodMessageHandler。这个处理器,是找Controller来执行
- Controller中收到该消息,其方法中调用了一个发送方法。发往/topic/boardCast/hello
- 此时也会根据消息的前缀,找到消息处理器,SimpleBrokerMessageHandler
- SimpleBrokerMessageHandler遍历用户会话,找到订阅了/topic/boardCast/hello的用户。通过outboundChannel将消息发送出去
以上就是用户发送一个消息,服务端接收。服务端同时再发送一条广播消息给对应的客户端的过程。
总结
通过本节内容,我们学到了以下内容
- 几个配置的含义
- registry.addEndpoint(“/portfolio”); 配置WebSocket端点
- config.setApplicationDestinationPrefixes(“/app”); 配置Controller的目的前缀。这是用于服务端接收客户端消息的前缀
- config.enableSimpleBroker(“/topic”, “/queue”); 配置用户可以订阅的destination。服务端通过msgOperations.convertAndSend(“/topic/boardCast/hello”, “hello boardCast Message”);可以发送消息给订阅了此destination的用户
- 消息的流转过程,大家可以根据上面的流程图,阅读一下源码
本节的示例源码,都在开源项目中:文章链接【stomp实战】搭建一套websocket推送平台。文章最后有项目地址。