8

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?

smwikipedia
  • 61,609
  • 92
  • 309
  • 482

1 Answers1

6

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

Community
  • 1
  • 1
  • 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 - https://stackoverflow.com/questions/49482735/cannot-send-messages-to-unauthenticated-users-using-springstompsockjs – mns Mar 26 '18 at 02:05
  • 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 ... – Jeef Apr 04 '18 at 18:04
  • Yup i did (finally) – Jeef Apr 11 '18 at 12:13
  • 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? – ZootHii Nov 27 '21 at 12:35