Spring WebSocket @SendToSession: Senden einer Nachricht an eine bestimmte Sitzung
Ist es möglich, eine Nachricht zu senden, um bestimmte session?
Habe ich ein nicht authentifizierter websocket zwischen den clients und dem Spring-servlet. Ich muss senden Sie unaufgefordert eine Nachricht an eine bestimmte Verbindung, 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 sehen in diesem code, kann der client beginnen, einen asynchronen job und wenn es fertig ist, es braucht eine end-Nachricht. Natürlich, ich muss die Nachricht nur der Antragsteller und nicht-broadcast an alle.
Es wäre toll, einen @SendToSession
annotation oder messagingTemplate.convertAndSendToSession
Methode.
UPDATE
Habe ich versucht, dieses:
messagingTemplate.convertAndSend("/queue/jobend", true, Collections.singletonMap(SimpMessageHeaderAccessor.SESSION_ID_HEADER, sessionId));
Aber diese Sendungen zu allen Sitzungen, nicht nur die angegebene.
UPDATE 2
Test mit convertAndSendToUser () - Methode.
Dieser test ist und hacken auf der offiziellen Spring-tutorial: https://spring.io/guides/gs/messaging-stomp-websocket/
Dies ist der server-code:
@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));
});
});
}
Client leider nicht erhalten Ihre pro-Sitzungs-Antwort, die jeder 5000ms als erwartet. Ich bin mir sicher, dass "1" eine gültige sessionId für den 2. client angeschlossen, da sehe ich es im debug-Modus mit SimpMessageHeaderAccessor.getSessionId()
HINTERGRUND SZENARIO
Möchte ich das erstellen einer Statusanzeige für eine remote-job, client fragt server für eine asynchrone job und prüft es seinen Fortschritt durch websocket-Nachricht von server. Dies ist NICHT eine Datei hochladen, aber ein remote-Berechnung, so dass nur der server weiß, der Fortschritt der einzelnen Jobs.
Ich brauche, um eine Nachricht senden zu bestimmten Sitzung, weil jeder job wird gestartet durch die Sitzung.
Client fragt eine remote-Berechnung
Server startet diese Aufgabe und für jeden job-step-Antwort an Antragsteller AUFTRAGGEBER mit der job-status.
Client ruft die Nachrichten über seine Arbeit und bauen ein Fortschritt/status-bar.
Dies ist, warum brauche ich eine pro-session.
Ich könnte auch eine pro-user-Meldungen, aber der Frühling nicht pro Benutzer unerwünschte Nachrichten. (Kann nicht senden, Benutzer-Nachricht mit Spring Websocket)
FUNKTIONIERENDE LÖSUNG
__ __ ___ ___ _ __ ___ _ _ ___ ___ ___ _ _ _ _____ ___ ___ _ _
\ \ / //_ \ | _ \| |//|_ _|| \| | /__| /__| /_ \ | | | | | ||_ _||_ _|/_ \ | \| |
\ \/\//| (_) || /| ' < | | | .` || (_ | \__ \| (_) || |__| |_| | | | | || (_) || .` |
\_/\_/ \___/ |_|_\|_|\_\|___||_|\_| \___| |___/ \___/ |____|\___/ |_| |___|\___/ |_|\_|
Ab dem UPDATE2 Lösung musste ich komplett convertAndSendToUser Methode mit last param (MessageHeaders):
messagingTemplate.convertAndSendToUser("1","/queue/test", new Return("test"), createHeaders("1"));
wo createHeaders()
ist diese Methode:
private MessageHeaders createHeaders(String sessionId) {
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
headerAccessor.setLeaveMutable(true);
return headerAccessor.getMessageHeaders();
}
InformationsquelleAutor der Frage Tobia | 2016-01-21
Du musst angemeldet sein, um einen Kommentar abzugeben.
Keine Notwendigkeit, erstellen Sie spezifische Ziele, ist es schon fertig aus der box, wie Spring 4.1 (siehe SPR-11309).
Bestimmte Benutzer abonnieren
/user/queue/something
Warteschlange, können Sie senden eine Nachricht an eine single session mit:Als anders in der SimpMessageSendingOperations Javadocda Ihr Benutzername ist eigentlich eine sessionId, MÜSSEN Sie festlegen, wie ein Kopf, wie auch sonst die
DefaultUserDestinationResolver
werden nicht in der Lage, die Nachricht weiterleiten und ablegen.Brauchen Sie nicht die Benutzer authentifiziert werden.
InformationsquelleAutor der Antwort Brian Clozel
Es ist sehr kompliziert und meiner Meinung nach, ist es nicht Wert.
Sie benötigen ein Abonnement erstellen für jeden Benutzer (auch nicht authentifizierte), indem Sie Ihre session-id.
Lassen Sie uns sagen, dass jeder Benutzer abonniert einen einzigartigen Warteschlange nur für ihn:
Auf dem server, bevor der Benutzer abonniert, Sie werden müssen informieren und eine Nachricht senden, für die Sitzung und speichern Sie Sie auf einer Karte:
Danach, wenn Sie die Nachricht senden wollen, um die Benutzer benötigen Sie:
Aber ich weiß nicht wirklich, was Sie versuchen zu tun und wie finden Sie die jeweiligen session (die anonym ist).
InformationsquelleAutor der Antwort Aviad
Müssen Sie fügen Sie einfach die session-id in
Server-Seite
convertAndSendToUser(sessionId,apiName,responseObject);
Client-Seite
$stomp.subscribe('/user/+sessionId+'/apiName',handler);
Hinweis:
Vergessen Sie nicht, fügen Sie
'/user'
in Ihrem end-Punkt im server-Seite.InformationsquelleAutor der Antwort Sandy