在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 。 例如:它发现两个会话wsxedc123thnujm456 ,Spring会将它转换为2个目的地queue/reply-userwsxedc123queue/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"); } }