Spring WebSocket @SendToSession: send message to specific session

No need to create specific destinations, it's already done out of the box as of Spring 4.1 (see SPR-11309).

Given users subscribe to a /user/queue/something queue, you can send a message to a single session with:

As stated in the SimpMessageSendingOperations Javadoc, since your user name is actually a sessionId, you MUST set that as a header as well otherwise the DefaultUserDestinationResolver won't be able to route the message and will drop it.

SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor
    .create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
headerAccessor.setLeaveMutable(true);

messagingTemplate.convertAndSendToUser(sessionId,"/queue/something", payload, 
    headerAccessor.getMessageHeaders());

You don't need users to be authenticated for this.


It is very complicated and in my opinion, isn't worth it. You need to create a subscription for every user (even unauthenticated ones) by their session id.

Let's say that every user subscribes to a unique queue only for him:

stompClient.subscribe('/session/specific' + uuid, handler);

On the server, before the user subscribes you will need to notify and send a message for the specific session and save to a map:

    @MessageMapping("/putAnonymousSession/{sessionId}")
    public void start(@DestinationVariable sessionId) throws Exception {
        anonymousUserSession.put(key, sessionId);
    }

After that, when you want to send message to the user you will need to:

messagingTemplate.convertAndSend("/session/specific" + key); 

But I don't really know what you are trying to do and how you will find the specific session (who is anonymous).


You need to simply add the session id in

  • Server Side

    convertAndSendToUser(sessionId,apiName,responseObject);

  • Client Side

    $stomp.subscribe('/user/+sessionId+'/apiName',handler);

Note:
Dont forget to add '/user' in your end point in server side.


I was struggling with the same problem and presented solution didnt work for me, therefore I had to take different approach:

  1. modify web socket config so user will be identified by session ID:
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws-endpoint")
                .setHandshakeHandler(new DefaultHandshakeHandler() {
                    
                    @Override
                    protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
                        if (request instanceof ServletServerHttpRequest) {
                            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
                            HttpSession session = servletRequest.getServletRequest().getSession();
                            return new Principal() {
                                @Override
                                public String getName() {
                                    return session.getId();
                                }
                            };
                        } else {
                            return null;
                        }
                    }
                }).withSockJS();
    }
  1. send message to that session id (without headers):
    simpMessagingTemplate.convertAndSendToUser(sessionId, "/queue", payload);