在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"); } }