Как отправить сообщение клиенту через websocket с помощью Spring

Я пытаюсь использовать Spring с websocket. Я начал свое исследование с помощью этого урока.

В моем стороннем клиенте у меня есть что-то вроде этого, чтобы инициализировать подключение к серверу:

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);
        });
    });
}

Он отлично работает, в моем контроллере Im способен выполнять мой процесс в следующем классе:

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

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

Теперь, что я хочу сделать, у него есть поток, отправляющий сообщение клиенту, прослушивающее "/topic/greeting". Я написал класс Runnable следующим образом:

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();
            }
        }   
    }
}

И завершил мой контроллер следующим образом:

@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");
    }
}

Метод PhotoController.fireGreeting вызывается как я хочу, но ничего не произошло на стороне клиента. Какие-либо предложения? Спасибо.

Ответы

Ответ 1

Я смог решить свою проблему благодаря @Boris the Spider. Правильное решение - сделать что-то вроде этого:

@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"));
    }
}

Ответ 2

Как подсказывает @Boris the Spider, лучше планировать периодические задачи, используя механизмы планирования Spring (см. это руководство).

Ради разделения проблем я бы также отделил связанный с расписанием код от кода контроллера.

В вашем случае вы можете использовать такой класс:

@Component
public class ScheduledTasks {

    @Autowired
    private SimpMessagingTemplate template;

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

И добавьте тег @EnableScheduling в свой класс Application.