2014-03-13 12 views
42

Wie Websocket Nachricht vom Server an bestimmte Benutzer senden?Senden einer Nachricht an bestimmte Benutzer auf Spring Websocket

Meine Webapp hat Feder Sicherheitseinstellungen und verwendet Websocket. Ich habe ein schwieriges Problem beim Versuch, eine Nachricht vom Server an spezifischen Benutzer nur zu senden.

aus Mein Verständnis the manual Lesen ist vom Server wir

simpMessagingTemplate.convertAndSend("/user/{username}/reply", reply); 

Und auf der Client-Seite tun können:

stompClient.subscribe('/user/reply', handler); 

Aber ich konnte nie das Abonnement Rückruf aufgerufen erhalten. Ich habe viele verschiedene Wege ausprobiert, aber kein Glück.

Wenn ich es an senden/Thema/Antwort es funktioniert, aber alle anderen verbundenen Benutzer erhalten es auch.

das Problem zu veranschaulichen, habe ich dieses kleine Projekt auf Github erstellt: https://github.com/gerrytan/wsproblem

Schritte zum Reproduzieren:

1) Clone und erstellen Sie das Projekt (stellen Sie sicher, dass Sie mit jdk 1.7 und maven 3,1)

$ git clone https://github.com/gerrytan/wsproblem.git 
$ cd wsproblem 
$ mvn jetty:run 

2) Navigieren Sie zu http://localhost:8080, Login entweder bob/Test oder jim/test

3) Klicken Sie auf "Benutzerspezifische Nachricht anfordern". Erwartet: eine Meldung "Hallo {Benutzername}" wird nur für diesen Benutzer neben "Empfangene Nachricht an mich" angezeigt. Aktuell: nichts ist erhalten

+0

Haben Sie bei convertAndSendToUser (String Benutzer, String Ziel, T-Nachricht) gesucht? http://docs.spring.io/spring/docs/4.0.0.M3/javadoc-api/org/Frühling Framework/messaging/simp/SimpMessagingTemplate.html # convertAndSendToUser% 28java.lang.String,% 20java.lang.String,% 20T% 29 –

+0

Ja versucht, aber auch kein Glück – gerrytan

+0

Ich habe an privaten Projekt gearbeitet und das ist die Methode, die wir verwenden und es funktioniert für uns. Ich denke, dass ein mögliches Problem sein könnte, dass Sie "/ user/reply" abonnieren und Sie Nachrichten an "/ user/{username}/reply" senden. Ich denke, dass Sie den {username} Teil entfernen und den convertAndSendToUser (String Benutzer, String Ziel, T Nachricht) verwenden sollten. –

Antwort

23

Ah ich fand, was mein Problem war. Zuerst habe ich nicht den /user Präfix auf dem einfachen Broker registriere

<websocket:simple-broker prefix="/topic,/user" /> 

Dann kann ich nicht den zusätzlichen /user Präfix muß beim Senden:

convertAndSendToUser(principal.getName(), "/reply", reply); 

Frühling wird automatisch voranstellen "/user/" + principal.getName() an das Ziel, daher Es wird in "/ user/bob/reply" aufgelöst.

Dies bedeutet auch, in javascript ich pro Benutzer andere Adresse abonnieren hatte

stompClient.subscribe('/user/' + userName + '/reply,...) 
+3

Mmm ... Gibt es eine Möglichkeit zu vermeiden, die clientseitige userName-Seite einzurichten ? Wenn Sie diesen Wert ändern (z. B. durch Verwendung eines anderen Benutzernamens), können Sie Nachrichten anderer Benutzer anzeigen. – vdenotaris

+1

Siehe meine Lösung: http://stackoverflow.com/questions/25646671/check-auth-while-sending-a-message-to-a-specific-user-by-using-stomp-and-websock/25647822#25647822 – vdenotaris

+0

Wie ** subscribe ** für die Antwort an Benutzer aus Methoden, die mit '@ RequestMapping' und auch' @ MessageMapping' versehen sind, siehe hier [Wie abonniere ich die Sping WebSocket-Integration für einen bestimmten Benutzernamen (userId) + erhält Benachrichtigungen von einer Methode mit @ RequestMapping?] (Https://stackoverflow.com/q/47628608/3425489) –

39

Oh, client side no need to known about current user, Server, dass für Sie tun.

Auf Server-Seite folgt mit Nachricht an einen Benutzer senden:

simpMessagingTemplate.convertAndSendToUser(username, "/queue/reply", message); 

Hinweis: queue verwendet, nicht topic, mit Spring immer queue mit sendToUser

Auf Client-Seite

stompClient.subscribe("/user/queue/reply", handler); 

Vergl

Wenn eine Websocket-Verbindung geöffnet ist, weist Spring eine session id (nicht HttpSession, Zuordnung pro Verbindung) zu. Und wenn Ihr Client an einen Kanal abonniert mit /user/ starten, zB: /user/queue/reply, Ihre Server-Instanz in einer Warteschlange queue/reply-user[session id]

genannt abonnieren werden, wenn die Verwendung Nachricht an Benutzer senden, zB: username is admin Sie schreiben simpMessagingTemplate.convertAndSendToUser("admin", "/queue/reply", message);

Spring bestimmt, welche session id dem Benutzer admin zugeordnet ist. ZB: Es fand zwei Sitzungen wsxedc123 und thnujm456, Spring wird es in 2 Ziel queue/reply-userwsxedc123 und queue/reply-userthnujm456 übersetzen, und es sendet Ihre Nachricht mit 2 Zielen zu Ihrem Nachrichtenbroker.

Der Nachrichtenbroker empfängt die Nachrichten und stellt sie der Serverinstanz zur Verfügung, die für jede Sitzung die Sitzung hält (WebSocket-Sitzungen können von einem oder mehreren Servern gehalten werden). Spring übersetzt die Nachricht in destination (z. B. user/queue/reply) und session id (z. B. wsxedc123). Dann senden Sie die Nachricht an entsprechenden Websocket session

+5

Können Sie bitte erklären, wie Sie den Benutzernamen kennen? In deinem Beispiel hast du gesagt, dass der Benutzername 'admin' ist, du erhältst den Benutzernamen vom Benutzer? – Jorj

+1

Der Benutzername wurde von "HttpSession" erhalten, wenn eine Websocket-Verbindung initiiert wurde. –

+0

könnten Sie bitte weitere Informationen zum Festlegen des Benutzernamens geben ?. Gibt es da trotzdem kann ich den username auf suscription message schicken? – Andres

2

Meine Lösung, dass basierend auf Thanh Nguyen Van beste Erklärung, aber zusätzlich habe ich konfiguriert MessageBrokerRegistry:

@Configuration 
@EnableWebSocketMessageBroker 
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { 

    @Override 
    public void configureMessageBroker(MessageBrokerRegistry config) { 
     config.enableSimpleBroker("/queue/", "/topic/"); 
     ... 
    } 
    ... 
} 
2

ich eine Probe websocket Projekt erstellt STOMP mit als auch . Was ich zu bemerken ist, dass

@Configuration 
@EnableWebSocketMessageBroker 
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { 

@Override 
public void configureMessageBroker(MessageBrokerRegistry config) { 
    config.enableSimpleBroker("/topic", "/queue");// including /user also works 
    config.setApplicationDestinationPrefixes("/app"); 
} 

@Override 
public void registerStompEndpoints(StompEndpointRegistry registry) { 
    registry.addEndpoint("/getfeeds").withSockJS(); 
} 

}

es funktioniert, ob "/ user" in config.enableSimpleBroker enthalten (...

2

Genau habe ich das gleiche und es ist ohne zu arbeiten Anwender mit

@Configuration 
@EnableWebSocketMessageBroker 
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { 

    @Override 
    public void registerStompEndpoints(StompEndpointRegistry registry) { 
     registry.addEndpoint("/gs-guide-websocket").withSockJS(); 
    } 

    @Override 
    public void configureMessageBroker(MessageBrokerRegistry config) { 
     config.enableSimpleBroker("/topic" , "/queue"); 
     config.setApplicationDestinationPrefixes("/app"); 
    } 
} 
Verwandte Themen