2014-03-13 46 views
42

如何从服务器向特定用户发送websocket消息?在Spring上发送消息给特定用户Websocket

我的web应用程序有弹簧安全设置并使用websocket。我遇到了棘手的问题,试图从服务器发送消息到特定用户只有

我从阅读理解the manual从服务器我们可以做

simpMessagingTemplate.convertAndSend("/user/{username}/reply", reply); 

而且在客户端:

stompClient.subscribe('/user/reply', handler); 

但我永远无法获得订阅调用的回调。我尝试了很多不同的道路,但没有运气。

如果我把它发送到/topic/reply它可以工作,但所有其他连接的用户也会收到它。

为了说明问题,我创建了在github上这个小项目:https://github.com/gerrytan/wsproblem

重现步骤:

1)克隆和构建项目(请确保您使用JDK 1.7和Maven的3.1)

$ git clone https://github.com/gerrytan/wsproblem.git 
$ cd wsproblem 
$ mvn jetty:run 

2)导航至http://localhost:8080,登录使用任一摆锤/试验或吉姆/测试

3)点击“请求用户特定的信息”。预期:仅显示此用户的“收到的邮件给我”旁边显示“hello {用户名}”消息,实际:没有收到任何邮件

+0

工作你一直在寻找convertAndSendToUser(用户字符串,字符串目的地,T消息)?http://docs.spring.io/spring/docs/4.0.0.M3/javadoc-api /组织/春天框架/消息/ simp/SimpMessagingTemplate.html#convertAndSendToUser%28java.lang.String,%20java.lang.String,%20T%29 –

+0

是试过,但也没有运气 – gerrytan

+0

我一直在私人项目工作,这是我们使用的方法,它正在为我们工作。我认为一个潜在的问题可能是您订阅了“/ user/reply”,并且您正在向“/ user/{username}/reply”发送消息。我认为你应该删除{username}部分并使用convertAndSendToUser(String user,String destination,T message)。 –

回答

23

啊我发现我的问题是什么。首先,我没有发送时的简单代理注册/user前缀

<websocket:simple-broker prefix="/topic,/user" /> 

然后我不需要额外的/user前缀:

convertAndSendToUser(principal.getName(), "/reply", reply); 

,Spring将自动预先准备"/user/" + principal.getName()到目的地,因此,它解析为“/ user/bob/reply”。

这也意味着在JavaScript中,我不得不订阅不同的地址,每个用户

stompClient.subscribe('/user/' + userName + '/reply,...) 
+3

嗯......有没有办法避免设置userName客户端?通过更改该值(例如通过使用其他用户名),您将能够看到其他用户的消息。 – vdenotaris

+1

请参阅我的解决方案:http://stackoverflow.com/questions/25646671/check-auth-while-sending-a-message-to-a-specific-user-by-using-stomp-and-websock/25647822#25647822 – vdenotaris

+0

如何**订阅**从用@ RequestMapping注解的方法回复用户,还有'@ MessageMapping'请参阅这里[如何使用特定用户名(userId)上的Sping Websocket集成进行订阅+从方法中通过@请求映射?](https://stackoverflow.com/q/47628608/3425489) –

39

哦,client side no need to known about current user,服务器会为你做的。

在服务器端,使用下面的方法来发送消息到用户:

simpMessagingTemplate.convertAndSendToUser(username, "/queue/reply", message); 

注意:使用queue,不topic,春天总是使用queuesendToUser

在客户端

stompClient.subscribe("/user/queue/reply", handler); 

Exp lain

当任何websocket连接打开时,Spring会为其分配一个session id(不是HttpSession,按连接分配)。当你的客户端订阅的频道开始/user/,例如:/user/queue/reply,服务器实例将订阅一个名为queue/reply-user[session id]

队列使用时发送消息给用户,例如:用户名是admin 你会写simpMessagingTemplate.convertAndSendToUser("admin", "/queue/reply", message);

Spring将确定哪个session id映射到用户admin。例如:它发现两个会话wsxedc123thnujm456,Spring会将其翻译为2个目的地queue/reply-userwsxedc123queue/reply-userthnujm456,并且它将带有2个目的地的消息发送到您的消息代理。

消息代理接收消息并将其提供回服务器实例,该实例拥有与每个会话相对应的会话(WebSocket会话可由一个或多个服务器保存)。 Spring会将消息翻译为destination(例如:user/queue/reply)和session id(例如:wsxedc123)。然后,将消息发送到相应的Websocket session

+5

你能解释你如何知道用户名吗?在你的例子中你说用户名是'admin',你收到用户名? – Jorj

+1

用户名是在发起websocket连接 –

+0

时从'HttpSession'获得的,请您提供更多关于如何设置用户名的信息。无论如何,我可以发送用户名上的提示信息? – Andres

2

我的,基于清阮文的最好解释的解决方案,但除了我已经配置MessageBrokerRegistry:

@Configuration 
@EnableWebSocketMessageBroker 
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { 

    @Override 
    public void configureMessageBroker(MessageBrokerRegistry config) { 
     config.enableSimpleBroker("/queue/", "/topic/"); 
     ... 
    } 
    ... 
} 
2

我使用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(); 
} 

}

它的作品是否“/用户”被包括在config.enableSimpleBroker(...

2

正是我做同样的,它是不使用用户

@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"); 
    } 
} 
相关问题