1.消息广播
/** * 广播模式 */ @Configuration @EnableWebSocketMessageBroker public class WebSocketBroadcastConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/endpointWisely").withSockJS(); } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker("/topic"); } }
/** * 广播模式 */ @Controller public class WebSocketBroadcastController { @Autowired private SimpMessagingTemplate template; @MessageMapping("/welcome")//浏览器发送请求通过@messageMapping 映射/welcome 这个地址。 //TODO 1.第一种方式通过注解SendTo发送消息 //@SendTo("/topic/getResponse")//服务器端有消息时,会订阅@SendTo 中的路径的浏览器发送消息。 public Response say(Message message) throws Exception { Thread.sleep(1000); Response response = new Response("Welcome, " + message.getName() + "!"); //TODO 2.第二种方式通过SimpMessagingTemplate 发送 template.convertAndSend("/topic/getResponse", response); return response; } }只要订阅/topic/getResponse的客户端都能收到消息
订阅消息:
function connect() { var socket = new SockJS('/endpointWisely'); //链接SockJS 的endpoint 名称为"/endpointWisely" stompClient = Stomp.over(socket);//使用stomp子协议的WebSocket 客户端 stompClient.connect({}, function (frame) {//链接Web Socket的服务端。 setConnected(true); console.log('Connected: ' + frame); stompClient.subscribe('/topic/getResponse', function (respnose) { //订阅/topic/getResponse 目标发送的消息。这个是在控制器的@SendTo中定义的。 showResponse(JSON.parse(respnose.body).responseMessage); }); }); }发送消息:
//通过stompClient.send 向/welcome 目标 发送消息,这个是在控制器的@messageMapping 中定义的。 stompClient.send("/welcome", {}, JSON.stringify({'name': name}));
2.点对点模式
/** * 点对点模式 */ @Configuration @EnableWebSocketMessageBroker public class WebSocketP2PConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/endpointChat").withSockJS(); } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { //点对点式增加消息代理 registry.enableSimpleBroker("/user"); //默认前缀就是/user registry.setUserDestinationPrefix("/user"); } }
/** * 点对点模式 */ @Controller public class WebSocketP2PController { @Autowired private SimpMessagingTemplate template; @MessageMapping("/chat") public void handlerChat(Message message) { template.convertAndSendToUser(message.getName(), "/queue/notifications" , "-sendTo:" + message.getName()); } }订阅消息:
var sock = new SockJS("/endpointChat"); var stomp = Stomp.over(sock); stomp.connect({}, function(frame) { /** 订阅了/user/queue/notifications 发送的消息,这里雨在控制器的 convertAndSendToUser 定义的地址保持一致, * 这里多用了一个/user,并且这个user 是必须的,使用user 才会发送消息到指定的用户。 * */ stomp.subscribe("/user/chat2/queue/notifications", handleNotification); });
3.总结
广播模式和点对点模式实现是完全一样。如果有多个客户端订阅一个destination,那就是广播了,如果只有一个用户订阅了
destination,那就是点对点。
@Override public void convertAndSendToUser(String user, String destination, Object payload, Map<String, Object> headers, MessagePostProcessor postProcessor) throws MessagingException { Assert.notNull(user, "User must not be null"); user = StringUtils.replace(user, "/", "%2F"); super.convertAndSend(this.destinationPrefix + user + destination, payload, headers, postProcessor); }
默认前缀
private String destinationPrefix = "/user/";
最终还是调用convertAndSend方法。
@Override public void convertAndSend(D destination, Object payload, Map<String, Object> headers, MessagePostProcessor postProcessor) throws MessagingException { Message<?> message = doConvert(payload, headers, postProcessor); send(destination, message); }