4.1.1.1.1. Spring WebSocket
4.1.1.1.1.1. SockJS
http://host:port/myApp/myEndpoint/{server-id}/{session-id}/{transport}
{server-id} - useful for routing requests in a cluster but not used otherwise.
{session-id} - correlates HTTP requests belonging to a SockJS session.
{transport} - indicates the transport type, e.g. “websocket”, “xhr-streaming”, etc.
4.1.1.1.1.1.1. Enable SockJS
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/myHandler").withSockJS();
}
@Bean
public WebSocketHandler myHandler() {
return new MyHandler();
}
}
关键代码:withSockJS()
4.1.1.1.1.2. STOMP
spring-messaging和spring-websocket模块中提供了STOMP over WebSocket支持。 一旦有了这些依赖关系,就可以使用SockJS Fallback通过WebSocket公开STOMP端点。
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// /portfolio是WebSocket(或SockJS)所指向的终结点点HTTP URL,客户端需要连接此地址才能进行WebSocket握手。
registry.addEndpoint("/portfolio").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
// STOMP messages whose destination header begins with /app are routed to @MessageMapping methods in @Controller classes.
// 其目标标头以/app开头的STOMP消息被路由到@Controller类中的@MessageMapping方法。
config.setApplicationDestinationPrefixes("/app");
// Use the built-in message broker for subscriptions and broadcasting and route messages whose destination header begins with /topic `or `/queue to the broker.
// 使用内置的消息代理进行订阅和广播,以及将目标标头以/topic或/queue开头的消息路由到代理。
config.enableSimpleBroker("/topic", "/queue");
}
}
@Controller
public class GreetingController {
@MessageMapping("/greeting") {
public String handle(String greeting) {
return "[" + getTimestamp() + ": " + greeting;
}
}
以上代码可以在客户端使用SockJS连接。
var socket = new SockJS("/spring-websocket-portfolio/portfolio");
var stompClient = webstomp.over(socket);
stompClient.connect({}, function(frame) {
}
var socket = new WebSocket("/spring-websocket-portfolio/portfolio");
var stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
}
对于内置的简单代理,/topic和/queue前缀没有任何特殊含义。 它们仅是区分发布订阅消息传递和点对点消息传递的约定(即,许多订户与一个消费者)。 使用外部代理时,请检查代理的STOMP页面以了解其支持哪种STOMP目标和前缀。
4.1.1.1.1.2.1. Flow of Messages
无外部Message Broker的情况:
有外部Message Broker的情况:
前面两个图之间的主要区别是使用“代理中继”将消息通过TCP传递到外部STOMP代理,以及将消息从代理传递到订阅的客户端。
当从WebSocket连接接收到消息时,它们被解码为STOMP帧,转换为Spring消息表示形式,并发送到clientInboundChannel进行进一步处理。 例如,目标标头以/ app开头的STOMP消息可以路由到带注释的控制器中的@MessageMapping方法,而/ topic和/ queue消息可以直接路由到消息代理。
处理来自客户端的STOMP消息的带注释的@Controller可以通过brokerChannel将消息发送到消息代理,并且代理通过clientOutboundChannel将消息广播给匹配的订户。 相同的控制器还可以响应HTTP请求执行相同的操作,因此客户端可以执行HTTP POST,然后@PostMapping方法可以将消息发送到消息代理,以广播到订阅的客户端。
4.1.1.1.1.3. Enable a STOMP broker relay
enableStompBrokerRelay
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/topic", "/queue")
.setRelayHost("localhost") // rabbitmq-host服务器地址
.setRelayPort(61613) // rabbitmq-stomp 服务器服务端口
.setClientLogin("guest") // 登陆账户
.setClientPasscode("guest"); // 登陆密码
//定义一对一推送的时候前缀
registry.setUserDestinationPrefix("/user/");
//客户端需要把消息发送到/message/xxx地址
registry.setApplicationDestinationPrefixes("/message");
LOGGER.info("init rabbitmq websocket MessageBroker complated.");
}
STOMP的消息根据前缀的不同分为三种。
以/app开头的消息会被路由到带有@MessageMapping或@SubscribeMapping注解的方法中。
以/topic或/queue开头的消息都会被发送到STOMP代理中。
根据你所选择都STOMP代理不同,目的地都可选前缀也会有所限制;以/usr开头都消息会将消息重路由到某个用户独有的目的地商。