Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/390.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在Spring Websocket上向特定用户发送消息_Java_Spring_Spring Mvc_Spring Websocket - Fatal编程技术网

Java 在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); 但我无法调用订阅回调。我尝

如何仅将websocket消息从服务器发送给特定用户?

我的webapp具有spring安全设置,并使用websocket。我在尝试仅将消息从服务器发送到特定用户时遇到了棘手的问题

我对阅读的理解来自于我们可以做的服务器

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