9

I am reading the book Spring in Action 4 to work with STOMP messaging over WebSocket.

Suppose the user destination prefix is set as "/user" as below:

registry.setUserDestinationPrefix("/user");

Then client subscribes to a destination with below JavaScript code:

stomp.subscribe("/user/queue/notifications", handleNotifications);

Then on the server, the actual destination that the client subscribes to should be derived from its session, maybe like this:

/queue/notifications-user6hr83v6t  --- (1)

Then I use the SimpMessagingTemplate to send message to that user:

messaging.convertAndSendToUser( username, "/queue/notifications",
                           new Notification("You just got mentioned!"));

Then the message will be sent to destination like this:

/user/<username>/queue/notifications  ---(2)

Well, the two destinations (1) and (2) look different, how could the message ever reach the client?

1 Answer 1

7

The path

/user/<username>/queue/notifications 

seems to be the "logical" path which is used in documentation. It is also initially created with convertAndSendToUser method. It is then translated into a technical format which is done in UserDestinationMessageHandler class in this line

UserDestinationResult result = this.destinationResolver.resolveDestination(message);

eg.

Given the subscription:

stompClient.subscribe('/user/queue/reply', function (greeting) { ...

sending a message with

stompClient.send("/app/personal", ...

and intercepting it with

@MessageMapping("/personal")
public void personalMessage(SimpMessageHeaderAccessor headerAccessor, PoCRequestMessage message) {

    SimpMessageHeaderAccessor ha = SimpMessageHeaderAccessor
            .create(SimpMessageType.MESSAGE);
    ha.setSessionId(headerAccessor.getSessionId());
    ha.setLeaveMutable(true);
    PoCReplyMessage reply = new PoCReplyMessage("Personal Message" + message.getName());
    simpMessagingTemplate.convertAndSendToUser(headerAccessor.getSessionId(), "/queue/reply", reply, ha.getMessageHeaders());
}

the destination will be resolved as follows:

source destination: /user/zojdn53y/queue/reply
target destination: /queue/reply-userzojdn53y

this is how the final destination name is resolved. The target destination is the real name of the queue that is created (at least as long an external message broker is used - didn't check this for a simple in-memory broker but I assume this would be the same).

One important thing to note is that when you want to use an unauthenticated user (most often scenario when experimenting with Websockets) you need to additionally put the message headers in convertAndSendToUser method - this is well described in

Spring WebSocket @SendToSession: send message to specific session

Sign up to request clarification or add additional context in comments.

4 Comments

My subscribers list is empty at a point after the UserDestinationResult is created successfully and so the message does not get sent. Any idea about that? I have a SO question for the same here - stackoverflow.com/questions/49482735/…
Thanks - this finally helped me out - after looking at a TON of different ones ... now if only i can just get the @SendToUser annotation to work ...
Yup i did (finally)
So how do we prevent 3. person from being able to subscribe to this endpoint when a user (1. person) sends a message to another user (2. person) and the other user (2. person) subscribes to this endpoint?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.