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?
Messages sent by the server to the client can include plain text messages, binary data, or images. Whenever data is sent, the onmessage function is fired. This event acts as a client's ear to the server. Whenever the server sends data, the onmessage event gets fired.
In order to communicate using the WebSocket protocol, you need to create a WebSocket object; this will automatically attempt to open the connection to the server. The URL to which to connect; this should be the URL to which the WebSocket server will respond.
In order to tell Spring to forward client requests to the endpoint , we need to register the handler. Start the application- Go to http://localhost:8080 Click on start new chat it opens the WebSocket connection. Type text in the textbox and click send. On clicking end chat, the WebSocket connection will be closed.
The WebSocket. send() method enqueues the specified data to be transmitted to the server over the WebSocket connection, increasing the value of bufferedAmount by the number of bytes needed to contain the data.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With