Spring WebSocket ================================================== 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. Enable SockJS `````````````````````````````` .. code-block:: java @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() STOMP ---------------------------------------- spring-messaging和spring-websocket模块中提供了STOMP over WebSocket支持。 一旦有了这些依赖关系,就可以使用SockJS Fallback通过WebSocket公开STOMP端点。 .. code-block:: java 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连接。 .. code:: javascript var socket = new SockJS("/spring-websocket-portfolio/portfolio"); var stompClient = webstomp.over(socket); stompClient.connect({}, function(frame) { } .. code:: javascript var socket = new WebSocket("/spring-websocket-portfolio/portfolio"); var stompClient = Stomp.over(socket); stompClient.connect({}, function(frame) { } 对于内置的简单代理,/topic和/queue前缀没有任何特殊含义。 它们仅是区分发布订阅消息传递和点对点消息传递的约定(即,许多订户与一个消费者)。 使用外部代理时,请检查代理的STOMP页面以了解其支持哪种STOMP目标和前缀。 Flow of Messages `````````````````````````````` 无外部Message Broker的情况: .. image:: https://docs.spring.io/spring/docs/current/spring-framework-reference/images/message-flow-simple-broker.png 有外部Message Broker的情况: .. image:: https://docs.spring.io/spring/docs/current/spring-framework-reference/images/message-flow-broker-relay.png 前面两个图之间的主要区别是使用“代理中继”将消息通过TCP传递到外部STOMP代理,以及将消息从代理传递到订阅的客户端。 当从WebSocket连接接收到消息时,它们被解码为STOMP帧,转换为Spring消息表示形式,并发送到clientInboundChannel进行进一步处理。 例如,目标标头以/ app开头的STOMP消息可以路由到带注释的控制器中的@MessageMapping方法,而/ topic和/ queue消息可以直接路由到消息代理。 处理来自客户端的STOMP消息的带注释的@Controller可以通过brokerChannel将消息发送到消息代理,并且代理通过clientOutboundChannel将消息广播给匹配的订户。 相同的控制器还可以响应HTTP请求执行相同的操作,因此客户端可以执行HTTP POST,然后@PostMapping方法可以将消息发送到消息代理,以广播到订阅的客户端。 Enable a STOMP broker relay ---------------------------------------- enableStompBrokerRelay .. code-block:: java @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开头都消息会将消息重路由到某个用户独有的目的地商。 .. image:: https://images2018.cnblogs.com/blog/1153954/201805/1153954-20180506222500876-639399590.png