16

I need to react on a user destination subscription.

Example:

A user subscribes to /user/messages, because he wants to receive all incoming messages. Now I'd like to look up any messages for this user, which were created while he was offline, and then send them to that user.

Working code:

Client code:

stompClient.subscribe('/user/messages', function(msg){
    alert(msg.body);
});

Server code:

template.convertAndSendToUser(p.getName(), "/messages", "message content");

What I need:

It seems like it's not possible to catch an user destination subscription on server side, i.e.:

@SubscribeMapping("/user/messages")
public void test(Principal p) { 
    sendMessagesThatWereReceivedWhileUserWasOffline();
}

What I tried:

@SubscribeMapping("/messages")
public void test(Principal p) { ... }

This works, if the client subscribes to /app/messages, but it won't get called for /user/messages.

My Configuration:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/stomp").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/app");
        registry.enableSimpleBroker("/queue", "/topic");
        registry.setUserDestinationPrefix("/user");
    }

    @Override
    public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
        return true;
    }

    // all other methods left empty
}

Using Spring 4.1.


I can't imagine that this isn't possible. What have I missed / done wrong?

Thank you :)

Benjamin M
  • 23,599
  • 32
  • 121
  • 201

1 Answers1

20

Define the user prefix also as an application prefix, and you'll then be able to map the subscription in your controller. Configuration:

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
    registry.setApplicationDestinationPrefixes("/app", "/user");
    registry.enableSimpleBroker("/queue", "/topic");
    registry.setUserDestinationPrefix("/user");
}

Controller:

@SubscribeMapping("/messages")
public void test(Principal p) { 
    sendMessagesThatWereReceivedWhileUserWasOffline();
}
Sergi Almar
  • 8,054
  • 3
  • 32
  • 30
  • Thank you ! Does this config "destroy" anything or change default behavior? I just wonder why this isn't the default setting – Benjamin M Sep 19 '14 at 15:17
  • this configuration doesn't break anything, messages starting with /user will be delivered to both the user destination handler and your controllers – Sergi Almar Sep 19 '14 at 15:37
  • Is there also a solution without using Principal? – Pepster Feb 16 '15 at 13:07
  • Pepster, you might ask in a separate question. You could use @Headers to get data from the headers of the message.. but this might be not what you wanted to ask. – rwitzel May 23 '15 at 17:47
  • Great answer thanks, however I am getting the following error? Any Suggestions? org.springframework.messaging.simp.annotation.support.MissingSessionUserException: No "user" header in message – Robert Leggett May 26 '16 at 03:10
  • Hi @SergiAlmar, I'm implementing Post and Comment module, how many subscriptions channel should I create e.g. addPost, updatePost, addComment, updateComment. Should I create individual subscription channel for all of them? This is not per user, visible for all users. – Shantaram Tupe Jun 05 '18 at 10:34