Spring WebSockets: Erstellen Sie einen Benutzer-Chat

Spring WebSockets: Erstellen Sie einen Benutzerchat

1. Einführung

In diesem Tutorial wird beschrieben, wieuse Spring WebSockets to send STOMP messages to a single user. ausgeführt werden. Dies ist wichtig, da wir manchmal nicht jede Nachricht an jeden Benutzer senden möchten. Außerdem zeigen wir Ihnen, wie Sie diese Nachrichten auf sichere Weise senden können.

Eine Einführung in WebSockets finden Sie inthis's großartigem Tutorial für die Inbetriebnahme. Um einen tieferen Einblick in die Sicherheit zu erhalten, lesen Sie den Artikel vonthis, um Ihre WebSockets-Implementierung zu sichern.

2. Warteschlangen, Themen und Endpunkte

Es gibtthree main ways to say where messages are sent and how they are subscribed to, die Spring WebSockets und STOMP verwenden:

  1. Topics - allgemeine Konversationen oder Chat-Themen, die jedem Client oder Benutzer offen stehen

  2. Queues - reserviert für bestimmte Benutzer und deren aktuelle Sitzungen

  3. Endpoints - generische Endpunkte

Lassen Sie uns nun einen kurzen Blick auf einen Beispielkontextpfad für jeden werfen:

  • “/topic/movies”

  • “/user/queue/specific-user”

  • “/secured/chat”

Es ist wichtig zu beachten, dass we must use queues to send messages to specific users, as topics and endpoints don’t support this functionality.

3. Aufbau

Lassen Sie uns nun lernen, wie Sie unsere Anwendung so konfigurieren, dass wir Nachrichten an einen bestimmten Benutzer senden können:

public class SocketBrokerConfig extends
  AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/secured/user/queue/specific-user");
        config.setApplicationDestinationPrefixes("/spring-security-mvc-socket");
        config.setUserDestinationPrefix("/secured/user");
    }

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

Stellen Sie sicher, dass Sie ein Benutzerziel angeben, da dies bestimmt, welche Endpunkte für einzelne Benutzer reserviert sind.

Außerdem stellen wir allen Warteschlangen und Benutzerzielen“/secured”vor, damit sie authentifiziert werden müssen. Bei ungeschützten Endpunkten können wir das Präfix“/secured”löschen (aufgrund unserer anderen Sicherheitseinstellungen).

Aus Sicht vonpom.xmlind keine zusätzlichen Abhängigkeiten erforderlich.

4. URL-Zuordnungen

Wir möchten, dass unser Client eine Warteschlange mit einer URL-Zuordnung abonniert, die dem folgenden Muster entspricht:

"/user/queue/updates"

Diese Zuordnung wird automatisch umUserDestinationMessageHandler in die benutzersitzungsspezifische Adresse umgewandelt.

Wenn wir beispielsweise einen Benutzer mit dem Namen“user123” haben, lautet die entsprechende Adresse:

"/queue/updates-user123"

Auf der Serverseite senden wir unsere benutzerspezifische Antwort mithilfe des folgenden URL-Zuordnungsmusters:

"/user/{username}/queue/updates"

Auch dies wird in die korrekte URL-Zuordnung umgewandelt, die wir bereits clientseitig abonniert haben.

Wir sehen also, dassthe essential ingredients here are two-fold:

  1. Stellen Sie unser angegebenes Benutzerzielpräfix voran (konfiguriert inAbstractWebSocketMessageBrokerConfigurer).

  2. Verwenden Sie“/queue” irgendwo in der Zuordnung.

Im nächsten Abschnitt werden wir uns genau ansehen, wie das geht.

5. convertAndSendToUser() aufrufen

Wir könnenconvertAndSendToUser() nicht statisch ausSimpMessagingTemplate oderSimpMessageSendingOperations aufrufen:

@Autowired
private SimpMessagingTemplate simpMessagingTemplate;

@MessageMapping("/secured/room")
public void sendSpecific(
  @Payload Message msg,
  Principal user,
  @Header("simpSessionId") String sessionId) throws Exception {
    OutputMessage out = new OutputMessage(
      msg.getFrom(),
      msg.getText(),
      new SimpleDateFormat("HH:mm").format(new Date()));
    simpMessagingTemplate.convertAndSendToUser(
      msg.getTo(), "/secured/user/queue/specific-user", out);
}

Sie haben vielleicht bemerkt:

@Header("simpSessionId") String sessionId

The @Header annotation allows access to headers exposed by the inbound message. Zum Beispiel können wir die aktuellensessionId erfassen, ohne dass komplizierte Abfangjäger erforderlich sind. In ähnlicher Weise istwe can access the current user via Principal.

Wichtig ist, dass der in diesem Artikel verfolgte Ansatz eine bessere Anpassung der Annotation von@sendToUserin Bezug auf URL-Zuordnungen bietet. Weitere Informationen zu dieser Anmerkung finden Sie inthis's großartigem Artikel.

Auf der Clientseite verwenden wirconnect() in JavaScript bisinitialize a SockJS instance and connect to our WebSocket server using STOMP:

var socket = new SockJS('/secured/room');
var stompClient = Stomp.over(socket);
var sessionId = "";

stompClient.connect({}, function (frame) {
    var url = stompClient.ws._transport.url;
    url = url.replace(
      "ws://localhost:8080/spring-security-mvc-socket/secured/room/",  "");
    url = url.replace("/websocket", "");
    url = url.replace(/^[0-9]+\//, "");
    console.log("Your current session is: " + url);
    sessionId = url;
}

Wir greifen auch auf die bereitgestelltensessionId zu und hängen diese an die URL-Zuordnung vonsecured/room an. This gives us the ability to dynamically and manually supply a user-specific subscription queue:

stompClient.subscribe('secured/user/queue/specific-user'
  + '-user' + that.sessionId, function (msgOut) {
     //handle messages
}

Sobald alles eingerichtet ist, sollten wir sehen:

 

image

Und in unserer Serverkonsole:

image

6. Fazit

Weitere Informationen zu diesem Thema finden Sie in den offiziellen Springblog undofficial documentation.

Wie immer sind die in diesem Artikel verwendeten Codebeispieleover on GitHub verfügbar.