Java 在Spring Websocket上向特定用户发送消息
如何仅将websocket消息从服务器发送给特定用户? 我的webapp具有spring安全设置,并使用websocket。我在尝试仅将消息从服务器发送到特定用户时遇到了棘手的问题 我对阅读的理解来自于我们可以做的服务器Java 在Spring Websocket上向特定用户发送消息,java,spring,spring-mvc,spring-websocket,Java,Spring,Spring Mvc,Spring Websocket,如何仅将websocket消息从服务器发送给特定用户? 我的webapp具有spring安全设置,并使用websocket。我在尝试仅将消息从服务器发送到特定用户时遇到了棘手的问题 我对阅读的理解来自于我们可以做的服务器 simpMessagingTemplate.convertAndSend("/user/{username}/reply", reply); 在客户端: stompClient.subscribe('/user/reply', handler); 但我无法调用订阅回调。我尝
simpMessagingTemplate.convertAndSend("/user/{username}/reply", reply);
在客户端:
stompClient.subscribe('/user/reply', handler);
但我无法调用订阅回调。我尝试过很多不同的方法,但都没有成功
如果我将它发送到/topic/reply,它会工作,但所有其他连接的用户也会收到它
为了说明这个问题,我在github上创建了这个小项目:
复制步骤:
1) 克隆并构建项目(确保您使用的是JDK1.7和maven 3.1)
2) 导航到http://localhost:8080
,使用bob/test或jim/test登录
3) 单击“请求用户特定消息”。预期:仅针对该用户,在“Received message to Me Only”旁边显示一条消息“hello{username}”,实际:未收到任何信息啊,我发现了我的问题所在。首先,我没有在简单代理上注册
/user
前缀
<websocket:simple-broker prefix="/topic,/user" />
Spring将自动将“/user/”+principal.getName()
前置到目标,因此它解析为“/user/bob/reply”
这也意味着在javascript中,我必须为每个用户订阅不同的地址
stompClient.subscribe('/user/' + userName + '/reply,...)
哦,
客户端不需要知道当前用户的情况,服务器会为您这样做
在服务器端,使用以下方式向用户发送消息:
simpMessagingTemplate.convertAndSendToUser(username, "/queue/reply", message);
注意:使用队列
,而不是主题
,Spring总是将队列
与发送者
在客户端
stompClient.subscribe("/user/queue/reply", handler);
解释
当任何websocket连接打开时,Spring将为其分配一个会话id
(不是HttpSession
,为每个连接分配)。当您的客户端订阅以/user/
开头的频道时,例如:/user/queue/reply
,您的服务器实例将订阅名为queue/reply user[session id]
使用“向用户发送消息”时,例如:用户名为admin
您将编写simpMessagingTemplate.convertandsendouser(“admin”,“/queue/reply”,message)代码>
Spring将确定哪个会话id映射到用户admin
。例如:它找到了两个会话wsxedc123
和thnumjm456
,Spring将把它翻译成两个目的地queue/reply-userwsxedc123
和queue/reply-userthnumjm456
,并将您的消息发送到您的消息代理
MessageBroker接收消息并将其提供回您的服务器实例,该实例包含与每个会话相对应的会话(WebSocket会话可以由一个或多个服务器持有)。Spring将消息转换为目的地(例如:user/queue/reply
)和会话id
(例如:wsxedc123
)。然后,它将消息发送到相应的Websocket会话
我的解决方案基于Thanh Nguyen Van的最佳解释,但除此之外,我还配置了MessageBrokerRegistry:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue/", "/topic/");
...
}
...
}
我还使用STOMP创建了一个示例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();
}
}
无论“/user”是否包含在config.enableSimpleBroker(…中,它都可以工作。我也做了同样的事情,它在不使用user的情况下工作
@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");
}
}
您是否一直在关注convertAndSendToUser(字符串用户、字符串目的地、T消息)?是的,您也尝试过,但没有luckI一直在处理私人项目,这是我们使用的方法,它对我们有效。我认为一个潜在的问题可能是您订阅了“/user/reply”,并且正在向“/user/{username}发送消息/我认为您应该删除{username}部分并使用convertAndSendToUser(字符串用户、字符串目标、T消息)。谢谢,但我尝试了SimpMessageTemplate.convertAndSendToUser(principal.getName(),“/user/reply”,reply)
当消息从服务器发送时,它抛出此异常java.lang.IllegalArgumentException:Expected destination pattern”/principal/{userId}/**“
@ViktorK.是正确的,并且您非常接近正确的解决方案。您在客户端的订阅是正确的,您只需尝试:convertAndSendToUser(principal.getName(),“/reply”,reply);
Mmm…有没有办法避免在客户端设置用户名?通过更改该值(例如使用另一个用户名),您将能够看到其他人的消息。请参阅我的解决方案:如何从带有@RequestMapping
注释的方法订阅以回复用户,以及@MessageMapping
请参见此处嘿,我的朋友,您能告诉我这个吗?这个“用户”到底是什么?我使用的是Spring Security和我的用户(用户名)是电子邮件地址。当每个用户登录时,他都会在Spring Security上获得他的JWT令牌。我遇到了同样的问题,搜索了几个小时才找到你的答案。只有你的解释对我有帮助。非常感谢!!你能解释一下你是如何知道用户名的吗?在你的示例中,你说用户名是“admin”,你收到了用户名?用户名是在启动websocket连接时从HttpSession
获取的。请您提供有关如何设置用户名的更多信息。我是否可以在SUScript消息中发送用户名?@Andres:您可以扩展DefaultHandsheHandler
并覆盖方法DeterminizeUser
您的解释非常有效.然而,在官方文件中,队列/回复用户[session id]
部分在哪里?嘿,在这种情况下,你在哪里使用过这个/app
?
@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();
}
@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");
}
}