Czy można wysłać wiadomość do określonej sesji?Spring WebSocket @SendToSession: wyślij wiadomość do konkretnej sesji
Mam nieuwierzytelnionego websocket między klientami a serwletem Spring. Muszę wysłać niezamawianą wiadomość do określonego połączenia, gdy zakończy się zadanie asynchroniczne.
@Controller
public class WebsocketTest {
@Autowired
public SimpMessageSendingOperations messagingTemplate;
ExecutorService executor = Executors.newSingleThreadExecutor();
@MessageMapping("/start")
public void start(SimpMessageHeaderAccessor accessor) throws Exception {
String applicantId=accessor.getSessionId();
executor.submit(() -> {
//... slow job
jobEnd(applicantId);
});
}
public void jobEnd(String sessionId){
messagingTemplate.convertAndSend("/queue/jobend"); //how to send only to that session?
}
}
Jak widać w tym kodzie, klient może rozpocząć zadanie asynchroniczne, a po jego zakończeniu potrzebuje komunikatu końcowego. Oczywiście, muszę wysłać tylko wnioskodawcę i nie przekazywać go wszystkim. Byłoby wspaniale mieć metodę adnotacji @SendToSession
lub .
UPDATE
Próbowałem to:
messagingTemplate.convertAndSend("/queue/jobend", true, Collections.singletonMap(SimpMessageHeaderAccessor.SESSION_ID_HEADER, sessionId));
Ale ten nadaje się do wszystkich sesji, a nie tylko jeden określonych. Sposób
UPDATE 2
testu z convertAndSendToUser(). Ten test jest i siekać oficjalnego tutoriala wiosny: https://spring.io/guides/gs/messaging-stomp-websocket/
Jest to kod serwera:
@Controller
public class WebsocketTest {
@PostConstruct
public void init(){
ScheduledExecutorService statusTimerExecutor=Executors.newSingleThreadScheduledExecutor();
statusTimerExecutor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
messagingTemplate.convertAndSendToUser("1","/queue/test", new Return("test"));
}
}, 5000,5000, TimeUnit.MILLISECONDS);
}
@Autowired
public SimpMessageSendingOperations messagingTemplate;
}
i jest to kod klienta:
function connect() {
var socket = new WebSocket('ws://localhost:8080/hello');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/user/queue/test', function(greeting){
console.log(JSON.parse(greeting.body));
});
});
}
Niestety klient nie otrzyma odpowiedź na sesję co 5000 ms zgodnie z oczekiwaniami. Jestem pewien, że „1” jest poprawnym sessionId na 2. klienta podłączonego bo widzę go w trybie debugowania z SimpMessageHeaderAccessor.getSessionId()
TŁO SCENARIUSZ
Chcę utworzyć pasek postępu dla zdalnej pracy, klient prosi serwer o zadanie asynchroniczne i sprawdza jego postęp za pomocą wiadomości websocket wysłanej z serwera. To NIE jest przesyłanie pliku, ale zdalne obliczenia, więc tylko serwer zna postęp każdego zadania. Muszę wysłać wiadomość do określonej sesji, ponieważ każde zadanie jest uruchamiane przez sesję. Klient prosi o zdalne obliczenia Serwer uruchamia to zlecenie i dla każdego kroku zadania odpowiada klientowi składającemu wniosek o statusie postępu pracy. Klient otrzymuje komunikaty o swojej pracy i tworzy pasek postępu/stanu. Dlatego potrzebuję wiadomości na sesję. Mogę również używać wiadomości dla poszczególnych użytkowników, ale Wiosna nie dostarcza dla niezamawianych wiadomości.(Cannot send user message with Spring Websocket)
roztwór roboczy
__ __ ___ ___ _ __ ___ _ _ ___ ___ ___ _ _ _ _____ ___ ___ _ _
\ \ /// _ \ | _ \| |/ /|_ _|| \| |/__| /__|/_ \ | | | | | ||_ _||_ _|/ _ \ | \| |
\ \/\/ /| (_) || /| ' < | | | .` || (_ | \__ \| (_) || |__| |_| | | | | || (_) || .` |
\_/\_/ \___/ |_|_\|_|\_\|___||_|\_| \___| |___/ \___/ |____|\___/ |_| |___|\___/ |_|\_|
Wychodząc z roztworu Update2 miałem z Metody convertAndSendToUser z ostatniego param (MessageHeaders)
messagingTemplate.convertAndSendToUser("1","/queue/test", new Return("test"), createHeaders("1"));
gdzie createHeaders()
Jest to metoda:
private MessageHeaders createHeaders(String sessionId) {
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
headerAccessor.setLeaveMutable(true);
return headerAccessor.getMessageHeaders();
}
Znalazłem to: https://jira.spring.io/browse/SPR-12143 – Tobia
Napisałem ci przykład. Jak określić, do kogo jest określona sesja, do której chcesz wysłać wiadomość? – Aviad
To jest zdalne zarządzanie zadaniami, gdy kontroler odbiera zdalne zlecenie zadania, powinien przechowywać sesję wnioskodawcy, aby przekierować odpowiedzi o przyszłym stanie pracy. – Tobia