25

I try to use Spring with websocket. I started my investigation with this tutorial.

In my side client I have something like that to initialize the connection to the server :

function connect() {
    var socket = new SockJS('/myphotos/form');
    stompClient = Stomp.over(socket);
    stompClient.connect({}, function(frame) {
        setConnected(true);
        console.log('Connected: ' + frame);
        stompClient.subscribe('/topic/greetings', function(greeting){
            showGreeting(JSON.parse(greeting.body).content);
        });
    });
}

It works great, in my controller I’m able to do my process in the following class :

@Controller
@RequestMapping("/")
public class PhotoController {

    @MessageMapping("/form")
    @SendTo("/topic/greetings")
    public Greeting validate(AddPhotosForm addPhotosForm) {
        return new Greeting("Hello world !");
    }
}

Now what I want to do it’s having a thread sending a message to the client listening on “/topic/greeting”. I wrote my Runnable class like this :

public class FireGreeting implements Runnable {

    private PhotoController listener;

    public FireGreeting(PhotoController listener) {
        this.listener = listener;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep( 2000 );
                listener.fireGreeting();
            } catch ( InterruptedException e ) {
                e.printStackTrace();
            }
        }   
    }
}

And completed my controller like that :

@Controller
@RequestMapping("/")
public class PhotoController {

    @MessageMapping("/form")
    @SendTo("/topic/greetings")
    public Greeting validate(AddPhotosForm addPhotosForm) {

        // added this part
        FireGreeting r = new FireGreeting( this );
        new Thread(r).start();

        return new Greeting("Hello world !");
    }

    // added this method
    @SendTo("/topic/greetings")
    public Greeting fireGreeting() {
        System.out.println("Fire");
        return new Greeting("Fire");
    }
}

The method PhotoController.fireGreeting is called as I want but nothing happened on the client side. Any suggestions ? Thank you.

cheb1k4
  • 1,920
  • 5
  • 21
  • 37
  • 11
    Please read [21.4.5 Sending Messages](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp-handle-send) from the Spring Websocket tutorial. This is certainly not how you do it. Also consider reading about Spring [scheduling mechanism](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/scheduling/annotation/EnableScheduling.html) rather than using raw threads (incorrectly). – Boris the Spider Jan 31 '15 at 10:56
  • Thank you for the link, it is exactly what I want to do. About thread I use, obviousely I won't use it in the final state of my application. I have a long process in the server side which will send informations to the client to let him know what steps are already done. – cheb1k4 Jan 31 '15 at 15:20

2 Answers2

49

I was able to solve my problem thanks to @Boris the Spider. The correct solution is to do something like that :

@Controller
@RequestMapping("/")
public class PhotoController {

    @Autowired
    private SimpMessagingTemplate template;

    @MessageMapping("/form")
    @SendTo("/topic/greetings")
    public Greeting validate(AddPhotosForm addPhotosForm) {

        FireGreeting r = new FireGreeting( this );
        new Thread(r).start();

        return new Greeting("Hello world !");
    }

    public void fireGreeting() {
        System.out.println("Fire");
        this.template.convertAndSend("/topic/greetings", new Greeting("Fire"));
    }
}
cheb1k4
  • 1,920
  • 5
  • 21
  • 37
  • Which `MessageChannel` class is being used with the injected `SimpMessagingTemplate`? – clD Dec 22 '20 at 20:27
6

A better way to schedule periodic tasks is, as suggested by @Boris the Spider, to use Spring scheduling mechanisms (see this guide).

For the sake of Separation of Concerns, I would also separate scheduled-related code from controller code.

In your case you could use a class like this one:

@Component
public class ScheduledTasks {

    @Autowired
    private SimpMessagingTemplate template;

    @Scheduled(fixedRate = 2000)
    public void fireGreeting() {
        this.template.convertAndSend("/topic/greetings", new Greeting("Fire"));
    }
}

And add the @EnableScheduling tag to your Application class.

mfilippo
  • 94
  • 1
  • 1