Spring WebSocket @SendToSession: Nachricht an bestimmte Sitzung senden

Ist es möglich, eine Nachricht an eine bestimmte Sitzung zu senden?

Ich habe ein nicht authentifiziertes Websocket zwischen Clients und einem Spring-Servlet. Ich muss eine unerwünschte Nachricht an eine bestimmte Verbindung senden, wenn ein asynchroner Job endet.

@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?
    }
}

Wie Sie in diesem Code sehen können, kann der Client einen asynchronen Job starten und benötigt nach dessen Abschluss die Endnachricht. Offensichtlich muss ich nur dem Antragsteller eine Nachricht senden und nicht an alle senden. Es wäre toll, ein @ zu hab@SendToSession annotation odermessagingTemplate.convertAndSendToSession Methode

AKTUALISIERE

Ich habe es versucht:

messagingTemplate.convertAndSend("/queue/jobend", true, Collections.singletonMap(SimpMessageHeaderAccessor.SESSION_ID_HEADER, sessionId));

Aber dies sendet an alle Sitzungen, nicht nur an die angegebene Sitzung.

UPDATE 2

Test mit der Methode convertAndSendToUser (). Dieser Test ist ein Hack des offiziellen Spring Tutorials:https: //spring.io/guides/gs/messaging-stomp-websocket

Dies ist der Servercode:

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

und dies ist der Client-Code:

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

Der Client erhält leider nicht alle 5000 ms die erwartete Antwort pro Sitzung. Ich bin sicher, dass "1" eine gültige Session-ID für den 2. verbundenen Client ist, da ich sie im Debug-Modus mit @ sehSimpMessageHeaderAccessor.getSessionId()

HINTERGRUND-SZENARIO

Ich möchte einen Fortschrittsbalken für einen Remote-Job erstellen. Der Client fragt den Server nach einem Async-Job und überprüft den Fortschritt anhand einer vom Server gesendeten Websocket-Nachricht. Dies ist KEIN Datei-Upload, sondern eine Fernberechnung, sodass nur der Server den Fortschritt jedes Jobs kennt. Ich muss eine Nachricht an eine bestimmte Sitzung senden, da jeder Job von einer Sitzung gestartet wird. Der Client fragt nach einem Remote-Rechenserver, der diesen Job startet, und antwortet dem antragstellenden Client bei jedem Jobschritt mit seinem Jobfortschrittsstatus. Der Client erhält Nachrichten über seinen Job und erstellt eine Statusleiste. Aus diesem Grund benötige ich Nachrichten pro Sitzung. Ich könnte auch Nachrichten pro Benutzer verwenden, aber Springbietet kein pro Benutzer unerwünschte Nachrichten. Kann keine Benutzermeldung mit Spring Websocket senden)

ARBEITSLÖSUNG

 __      __ ___   ___  _  __ ___  _  _   ___      ___   ___   _    _   _  _____  ___  ___   _  _ 
 \ \    / // _ \ | _ \| |/ /|_ _|| \| | / __|    / __| / _ \ | |  | | | ||_   _||_ _|/ _ \ | \| |
  \ \/\/ /| (_) ||   /| ' <  | | | .` || (_ |    \__ \| (_) || |__| |_| |  | |   | || (_) || .` |
   \_/\_/  \___/ |_|_\|_|\_\|___||_|\_| \___|    |___/ \___/ |____|\___/   |_|  |___|\___/ |_|\_|

Ausgehend von der UPDATE2-Lösung musste ich die convertAndSendToUser-Methode mit dem letzten Parameter (MessageHeaders) abschließen:

messagingTemplate.convertAndSendToUser("1","/queue/test", new Return("test"), createHeaders("1"));

wocreateHeaders() ist diese Methode:

private MessageHeaders createHeaders(String sessionId) {
        SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
        headerAccessor.setSessionId(sessionId);
        headerAccessor.setLeaveMutable(true);
        return headerAccessor.getMessageHeaders();
    }

Antworten auf die Frage(6)

Ihre Antwort auf die Frage