在Spring Websocket上发送消息给特定的用户
如何将websocket消息从服务器发送到特定用户?
我的web应用程序有弹簧安全设置,并使用websocket。 我遇到了一个棘手的问题,试图从服务器发送消息到特定的用户只 。
我从阅读手册的理解是从我们可以做的服务器
simpMessagingTemplate.convertAndSend("/user/{username}/reply", reply); 而在客户端:
 stompClient.subscribe('/user/reply', handler); 
但是我永远无法获得调用的订阅callback。 我尝试了许多不同的道路,但没有运气。
如果我把它发送到/话题/回复它的作品,但所有其他连接的用户也将收到它。
为了说明这个问题,我在github上创build了这个小项目: https : //github.com/gerrytan/wsproblem
重现步骤:
1)克隆并build立项目(确保你使用JDK 1.7和Maven 3.1)
 $ git clone https://github.com/gerrytan/wsproblem.git $ cd wsproblem $ mvn jetty:run 
  2)导航到http://localhost:8080 ,使用bob / test或者jim / testlogin 
3)点击“请求用户特定的信息”。 预期:仅针对该用户的“收到的邮件给我”旁边显示“hello {用户名}”消息,实际:没有任何内容被接收
 哦, client side no need to known about current user ,服务器将为您做到这一点。 
在服务器端,使用下面的方式向用户发送消息:
 simpMessagingTemplate.convertAndSendToUser(username, "/queue/reply", message); 
  注意:使用queue ,而不是topic ,Spring总是使用带有sendToUser queue 
在客户端
 stompClient.subscribe("/user/queue/reply", handler); 
说明
 当任何websocket连接打开时,Spring将为其分配一个session id (而不是HttpSession ,每个连接分配)。 当你的客户端订阅一个以/user/开头的频道时,例如: /user/queue/reply ,你的服务器实例将订阅一个名为queue/reply-user[session id] 
 当使用发送消息给用户,例如:用户名是admin您将编写simpMessagingTemplate.convertAndSendToUser("admin", "/queue/reply", message); 
  Spring将确定映射到用户admin哪个session id 。 例如:它发现两个会话wsxedc123和thnujm456 ,Spring会将它转换为2个目的地queue/reply-userwsxedc123和queue/reply-userthnujm456 ,并且将带有2个目的地的消息发送给你的消息代理。 
 消息代理接收消息并将其提供回服务器实例,该实例拥有与每个会话相对应的会话(WebSocket会话可以由一个或多个服务器保存)。  Spring会将消息转换为destination (例如: user/queue/reply )和session id (例如: wsxedc123 )。 然后,它将消息发送到相应的Websocket session 
 啊,我发现我的问题是什么。 首先,我没有在简单的代理上注册/user前缀 
 <websocket:simple-broker prefix="/topic,/user" /> 
 那么发送时我不需要额外/user前缀: 
 convertAndSendToUser(principal.getName(), "/reply", reply); 
  Spring会自动将"/user/" + principal.getName()加到目的地,因此parsing成“/ user / bob / reply”。 
这也意味着在JavaScript中,我不得不订阅每个用户不同的地址
 stompClient.subscribe('/user/' + userName + '/reply,...) 
我的解决scheme基于Thanh Nguyen Van的最佳解释,但是除此之外,我已经configuration了MessageBrokerRegistry:
 @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/queue/", "/topic/"); ... } ... } 
我也使用STOMP创build了一个示例websocket项目。 我注意到的是
 @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic", "/queue");// including /user also works config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/getfeeds").withSockJS(); } 
}
它的作品,无论“/用户”是否包含在config.enableSimpleBroker(…
确实,我做了相同的工作,而不使用用户
 @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/gs-guide-websocket").withSockJS(); } @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic" , "/queue"); config.setApplicationDestinationPrefixes("/app"); } }