Scheduled websocket push with Springboot

Konstantine picture Konstantine · May 18, 2016 · Viewed 24.9k times · Source

I want to create a simple news feed feature on the front end that will automatically update through websocket push notifications.

The technologies involved are:

  • Angular for the general front-end application
  • SockJS for creating websocket communication
  • Stomp over webosocket for receiving messages from a message broker
  • Springboot Websockets
  • Stomp Message Broker (the java related framework)

What I want to achieve on the front end is:

  1. Create a websocket connection when the view is loaded
  2. Create s stomp provider using that websocket
  3. Have my client subscribe to it
  4. Catch server pushed messages and update the angular view

As far as the server side code:

  1. Configure the websocket stuff and manage the connection
  2. Have the server push messages every X amount of time (through an executor or @Scheduled?).

I think I have achieved everything so far except the last part of the server side code. The example I was following uses the websocket in full duplex mode and when a client sends something then the server immediately responds to the message queue and all subscribed clients update. But what I want is for the server itself to send something over Stomp WITHOUT waiting for the client to make any requests.

At first I created a spring @Controller and added a method to it with @SendTo("/my/subscribed/path") annotation. However I have no idea how to trigger it. Also I tried adding @Scheduled but this annotation works only on methods with void return type (and I'm returning a NewsMessage object).

Essentially what I need is to have the client initialize a websocket connection, and after have the server start pushing messages through it at a set interval (or whenever an event is triggered it doesn't matter for now). Also, every new client should listen to the same message queue and receive the same messages.

Answer

RMachnik picture RMachnik · May 18, 2016

Before starting, make sure that you have the websocket dependencies in your pom.xml. For instance, the most important one:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-websocket</artifactId>
    <version>${org.springframework-version}</version>
</dependency>

Then, you need to have your configuration in place. I suggest you start with simple broker.

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/portfolio").withSockJS();
    }

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

}

Then your controller should look like this. When your AngularJs app opens a connection on /portfolio and sends a subscription to channel /topic/greeting, you will reach the controller and respond to all subscribed users.

@Controller
public class GreetingController {
    
    @MessageMapping("/greeting")
    public String handle(String greeting) {
        return "[" + getTimestamp() + ": " + greeting;
    }
}

With regard to your scheduler question, you need to enable it via configuration:

@Configuration
@EnableScheduling
public class SchedulerConfig{}

And then schedule it:

@Component
public class ScheduledUpdatesOnTopic{

    @Autowired
    private SimpMessagingTemplate template;
    @Autowired
    private final MessagesSupplier messagesSupplier;

    @Scheduled(fixedDelay=300)
    public void publishUpdates(){
        template.convertAndSend("/topic/greetings", messagesSupplier.get());
    }
}

Hope this somehow clarified the concept and steps to be taken to make things work for you.