Konstantine Konstantine - 3 months ago 30
Java Question

Scheduled websocket push with Springboot

I'm kinda new to spring-boot and spring in general. I got thrown in a project and my first "exercise" in order to get my feet wet is 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

First of all you need tho have your websocket enabled in spring, before make sure that you have according dependencies in your pom.xml

For instance 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 to 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 will open connection on '/portfolio' and send subscription to this channel /topic/greeeting you will receive this in controller and respond to all subscribed users.

@Controller
public class GreetingController {

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

Regarding 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;

    @Scheduler(fixedDelay=300)
    public void publishUpdates(String text){
        template.convertAndSend("/topic/greetings", text);
    }
}

Hope this somehow clarified concept and steps needs to be taken to make things working for you.