Im letzten Beitrag haben wir uns ums Backend gekümmert, heute werfen wir Blick auf die Angular Seite, wenn es um die Einbindung von WebSockets geht.
In unserer Spring Boot Anwendung haben wir uns für die Verwendung von STOMP als Nachrichtenformat entschieden, was natürlich entsprechende Auswirkung auf unseren Angular Client hat.
Der erste Schritt ist die Installation von rx-stomp, einem STOMP-Client der über WebSockets kommuniziert:
npm i @stomp/rx-stomp
Über unsere Modul-Provider konfigurieren wir einen entsprechenden Provider, der hier lediglich die Basis-URL definiert. Zusätzliche Konfigurationen bezüglich Timeouts, Reconnects und Debugging sind hier jedoch möglich
providers: [
{
provide: RxStomp,
useFactory: () => {
const rxStomp = new RxStomp();
rxStomp.configure({
brokerURL: environment.wsUrl // ../ws
});
rxStomp.activate();
return rxStomp;
},
},
],
Nun können wir über den Standard DI Mechanismus von Angular einen entsprechenden Service injiziert bekommen, den wir mittels .watch bzw. .publish Methode dazu veranlassen können auf Nachrichten zu reagieren oder Nachrichten zu verschicken. In diesem Beispiel kapseln wir diese Logik in einen eigenen Service:
export class NotifierService {
notify: Observable<any> = new Subject();
newMessage: Observable<any> = new Subject();
constructor(private stomp: RxStomp) {
this.notify = stomp.watch('/notifier/message')
.pipe(
map(message => JSON.parse(message.body)),
share({resetOnRefCountZero: true})
);
this.newMessage = stomp.watch('/notifier/new-message')
.pipe(
map(message => JSON.parse(message.body)),
share({resetOnRefCountZero: true})
)
}
send(message: any) {
this.stomp.publish({
destination: '/app/message',
body: JSON.stringify(message),
headers: {'content-type': 'application/json'}
});
}
}
Wir registrieren uns auf 2 Endpunkte “notifier/message” und “notifier/new-message”, dabei nutzen wir die Möglichkeiten von rxjs, um einen möglichst flexiblen und transparenten Service anzubieten:
- unsere Komponenten registrieren sich auf die beiden definierten Observables (mittels subscribe )
- damit spielt es für die Komponente keine Rolle, ob der Aufruf ein normaler Rest Endpoint, eine WebSocket Nachricht oder einfach ein Stream von Daten ist
- mittels der “map” konvertieren wir den Nachrichteninhalt in ein JSON Objekt
- mittels “share” verarbeiten wir nur dann die Nachrichten, wenn wir mindestens einen Subscriber haben, sich also mindestens eine Komponente mittels .subscribe registriert hat
Alles Live und in Farbe: https://github.com/GEDOPLAN/spring-angular-websocket