Spring Boot 2+ Angular 11 + Websocket 2.3 + SockJS 1.0.2
Table of Contents
Spring Boot Changes:
Keep only websocket spring boot starter dependency:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
If you are facing any dependency related issues, then try adding all the other below jars and check,
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>webjars-locator-core</artifactId> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>sockjs-client</artifactId> <version>1.0.2</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>stomp-websocket</artifactId> <version>2.3.3</version> </dependency>
WebSocketConfig.java: Configuration file for websocket & route
Allowed origins must be your local host or your actual domain and make sure to declare the topic which websocket is going to expose the data to clients.
import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.web.socket.config.annotation.*; @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws") .setAllowedOrigins("http://localhost:4200") //.setAllowedOrigins("*") //.setAllowedOriginPatterns("") .withSockJS(); } }
How to push the data to websocket topic from any spring service layer ?
@Service public class NgService { @Autowired private SimpMessagingTemplate template; public void processMsg(String msg) { // pushing the data to websocket this.template.convertAndSend("/topic/ngdev-blog-data", msg); } } }
Angular changes:
Make sure to add or install the below dependencies in your Angular 11 project,
"net": "^1.0.2", "sockjs-client": "^1.3.0", "stompjs": "^2.3.3",
Websocket API (websocketapi.ts)
import * as Stomp from 'stompjs'; import * as SockJS from 'sockjs-client'; import { WebSocketShareService } from './websocketshare.service'; import { Injectable } from '@angular/core'; @Injectable() export class WebSocketAPI { webSocketEndPoint: string = 'http://localhost:8081/ngdev/api/ws'; topic: string = "/topic/ngdev-blog-data"; stompClient: any; constructor(private websocketShare: WebSocketShareService){ } _connect() { console.log("Initialize WebSocket Connection"); let ws = new SockJS(this.webSocketEndPoint); this.stompClient = Stomp.over(ws); const _this = this; _this.stompClient.connect({}, function (frame) { _this.stompClient.subscribe(_this.topic, function (sdkEvent) { _this.onMessageReceived(sdkEvent); }); //_this.stompClient.reconnect_delay = 2000; }, this.errorCallBack); }; _disconnect() { if (this.stompClient !== null) { this.stompClient.disconnect(); } console.log("Disconnected"); } // on error, schedule a reconnection attempt errorCallBack(error) { console.log("errorCallBack -> " + error) setTimeout(() => { this._connect(); }, 5000); } onMessageReceived(message) { this.websocketShare.onNewValueReceive(message.body); } }
WebSocketShareService.ts:
Service class with subject to observe the pushed(new) data changes to all the consumers.
import { Injectable, OnDestroy } from "@angular/core"; import { Observable, BehaviorSubject, ReplaySubject } from "rxjs"; @Injectable() export class WebSocketShareService implements OnDestroy { private blogDataSubject = new BehaviorSubject<string>(undefined); constructor() { } ngOnDestroy(): void { this.blogDataSubject .unsubscribe(); } onNewValueReceive(msg: string) { this.blogDataSubject .next(msg); } getNewValue(): Observable<string> { return this.blogDataSubject .asObservable(); } }
And from your Angular component, this is how you will consume and display in your template file:
DashboardComponent.ts:
import { Component, OnInit } from '@angular/core'; import { Subscription } from "rxjs"; import { WebSocketAPI } from 'src/app/shared/services/websocketapi'; import { WebSocketShareService } from 'src/app/shared/services/websocketshare.service'; @Component({ selector: 'app-dashboard', templateUrl: './dashboard.component.html', styleUrls: ['./dashboard.component.scss'] }) export class DashboardComponent implements OnInit { wsData: string = 'Hello'; // default data, will be updated when the new data is pushed from spring boot backend constructor(private websocketService: WebSocketShareService, private webSocketAPI: WebSocketAPI) { } ngOnInit() { this.webSocketAPI._connect(); this.onNewValueReceive(); } ngOnDestroy() { } connect() { this.webSocketAPI._connect(); } disconnect() { this.webSocketAPI._disconnect(); } // method to receive the updated data. onNewValueReceive() { this.websocketService.getNewValue().subscribe(resp => { this.wsData = resp; }); } }
Template file just prints the variable {{wsData}}
The level of my enthusiasm for your work is the same as yours. The sketch is tastefully done, and the authored material has excellent qualities. Despite your uneasiness, it appears that you are unwilling to proceed in a direction that might cause anxiety. I’m certain you’ll be able to handle this situation effectively.
Fourweekmba You’re so awesome! I don’t believe I have read a single thing like that before. So great to find someone with some original thoughts on this topic. Really.. thank you for starting this up. This website is something that is needed on the internet, someone with a little originality!
BaddieHub I just like the helpful information you provide in your articles
Henof Hi there to all, for the reason that I am genuinely keen of reading this website’s post to be updated on a regular basis. It carries pleasant stuff.
SocialMediaGirls naturally like your web site however you need to take a look at the spelling on several of your posts. A number of them are rife with spelling problems and I find it very bothersome to tell the truth on the other hand I will surely come again again.
Touch to Unlock There is definately a lot to find out about this subject. I like all the points you made
Thinker Pedia Very well presented. Every quote was awesome and thanks for sharing the content. Keep sharing and keep motivating others.
Mangaclash This is really interesting, You’re a very skilled blogger. I’ve joined your feed and look forward to seeking more of your magnificent post. Also, I’ve shared your site in my social networks!
Ezippi Very well presented. Every quote was awesome and thanks for sharing the content. Keep sharing and keep motivating others.
Blue Techker I very delighted to find this internet site on bing, just what I was searching for as well saved to fav
NY weekly Awesome! Its genuinely remarkable post, I have got much clear idea regarding from this post . NY weekly
gab You’re so awesome! I don’t believe I have read a single thing like that before. So great to find someone with some original thoughts on this topic. Really.. thank you for starting this up. This website is something that is needed on the internet, someone with a little originality!