How can I send a message on connect event (SockJS, STOMP, Spring)?

Adam Soliński picture Adam Soliński · Jul 15, 2014 · Viewed 18.5k times · Source

I am connection through SockJS over STOMP to my Spring backend. Everything work fine, the configuration works well for all browsers etc. However, I cannot find a way to send an initial message. The scenario would be as follows:

  1. The client connects to the topic

    function connect() {
        var socket = new SockJS('http://localhost:8080/myEndpoint');
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function(frame) {
            setConnected(true);
            console.log('Connected: ' + frame);
            stompClient.subscribe('/topic/notify', function(message){
                showMessage(JSON.parse(message.body).content);
            });
        });
    }

and the backend config looks more or less like this:


    @Configuration
    @EnableWebSocketMessageBroker
    public class WebSocketAppConfig extends AbstractWebSocketMessageBrokerConfigurer {   
    ...
    @Override
    public void registerStompEndpoints(final StompEndpointRegistry registry) {
        registry.addEndpoint("/myEndpoint").withSockJS();
    }

  1. I want to send to the client an automatic reply from the backend (on the connection event) so that I can already provide him with some dataset (e.g. read sth from the db) without the need for him (the client) to send a GET request (or any other). So to sum up, I just want to send him a message on the topic with the SimMessagingTemplate object just after he connected.

Usually I do it the following way, e.g. in a REST controller, when the template is already autowired:


    @Autowired
    private SimpMessagingTemplate template;
    ...
    template.convertAndSend(TOPIC, new Message("it works!"));

How to achieve this on connect event?

UPDATE

I have managed to make it work. However, I am still a bit confused with the configuration. I will show here 2 configurations how the initial message can be sent:

1) First solution

JS part

stompClient.subscribe('/app/pending', function(message){
    showMessage(JSON.parse(message.body).content);
});
stompClient.subscribe('/topic/incoming', function(message){
    showMessage(JSON.parse(message.body).content);
});

Java part

@Controller
public class WebSocketBusController {
    @SubscribeMapping("/pending")

Configuration

@Override
public void configureMessageBroker(final MessageBrokerRegistry config) {
    config.enableSimpleBroker("/topic");
    config.setApplicationDestinationPrefixes("/app");
}

... and other calls

template.convertAndSend("/topic/incoming", outgoingMessage);

2) Second solution

JS part

stompClient.subscribe('/topic/incoming', function(message){
    showMessage(JSON.parse(message.body).content);
})

Java part

@Controller
public class WebSocketBusController {
    @SubscribeMapping("/topic/incoming")

Configuration

@Override
public void configureMessageBroker(final MessageBrokerRegistry config) {
    config.enableSimpleBroker("/topic");
    // NO APPLICATION PREFIX HERE
}

... and other calls

template.convertAndSend("/topic/incoming", outgoingMessage);

SUMMARY:

The first case uses two subscriptions - this I wanted to avoid and thought this can be managed with one only.

The second one however has no prefix for application. But at least I can have a single subscription to listen on the provided topic as well as send initial message.

Answer

mrUwa picture mrUwa · Jan 26, 2017

If you just want to send a message to the client upon connection, use an appropriate ApplicationListener:

@Component
public class StompConnectedEvent implements ApplicationListener<SessionConnectedEvent> {

    private static final Logger log = Logger.getLogger(StompConnectedEvent.class);

    @Autowired
    private Controller controller;

    @Override
    public void onApplicationEvent(SessionConnectedEvent event) {
        log.debug("Client connected.");
        // you can use a controller to send your msg here
    }
}