Sending message to specific user on Spring Websocket

Oh, client side no need to known about current user, server will do that for you.

On server side, using following way to send message to an user:

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

Note: Using queue, not topic, Spring always using queue with sendToUser

On client side

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

Explain

When any websocket connection is open, Spring will assign it a session id (not HttpSession, assign per connection). And when your client subscribe to an channel start with /user/, eg: /user/queue/reply, your server instance will subscribe to a queue named queue/reply-user[session id]

When use send message to user, eg: username is admin You will write simpMessagingTemplate.convertAndSendToUser("admin", "/queue/reply", message);

Spring will determine which session id mapped to user admin. Eg: It found two session wsxedc123 and thnujm456, Spring will translate it to 2 destination queue/reply-userwsxedc123 and queue/reply-userthnujm456, and it send your message with 2 destinations to your message broker.

The message broker receive the messages and provide it back to your server instance that holding session corresponding to each session (WebSocket sessions can be hold by one or more server). Spring will translate the message to destination (eg: user/queue/reply) and session id (eg: wsxedc123). Then, it send the message to corresponding Websocket session


Ah I found what my problem was. First I didn't register the /user prefix on the simple broker

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

Then I don't need the extra /user prefix when sending:

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

Spring will automatically prepend "/user/" + principal.getName() to the destination, hence it resolves into "/user/bob/reply".

This also means in javascript I had to subscribe to different address per user

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

I created a sample websocket project using STOMP as well. What I am noticing is that

@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();
}

}

it works whether or not "/user" is included in config.enableSimpleBroker(...


My solution of that based on Thanh Nguyen Van's best explanation, but in addition I have configured MessageBrokerRegistry:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

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