Как отправить сообщение клиенту через 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.