📘 Premium Read: Access my best content on Medium member-only articles — deep dives into Java, Spring Boot, Microservices, backend architecture, interview preparation, career advice, and industry-standard best practices.
✅ Some premium posts are free to read — no account needed. Follow me on Medium to stay updated and support my writing.
🎓 Top 10 Udemy Courses (Huge Discount): Explore My Udemy Courses — Learn through real-time, project-based development.
▶️ Subscribe to My YouTube Channel (172K+ subscribers): Java Guides on YouTube
All Angular 8 tutorials and examples at https://www.javaguides.net/p/angular-8-tutorial-with-examples.html
What we will build?
- springboot-websocket (backend): This project is used to develop a WebSocket endpoint at the server-side using spring boot, STOMP, and sock js support.
- angular8-springboot-websocket(frontend): This project is used to develop single-page application using Angular 8 as front-end technology. This Angular 8 client application subscribes and exchanges the messages over a WebSocket.
Backend - Spring Boot App Development
1. Creating a Spring Boot Application
>> Create Spring Boot Project in Spring Tool Suite [STS]
2. Project Structure
3. Create a resource representation class
HelloMessage
package net.javaguides.springboot.websocket.model
public class HelloMessage {
private String name;
public HelloMessage() {}
public HelloMessage(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Greeting.java
package net.javaguides.springboot.websocket.model
public class Greeting {
private String content;
public Greeting() {}
public Greeting(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
4. Create a message-handling controller
package net.javaguides.springboot.websocket.controller;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.web.util.HtmlUtils;
import net.javaguides.springboot.websocket.model.Greeting;
import net.javaguides.springboot.websocket.model.HelloMessage;
@Controller
public class GreetingController {
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Greeting greeting(HelloMessage message) throws Exception {
Thread.sleep(1000); // simulated delay
return new Greeting("Hello, " + HtmlUtils.htmlEscape(message.getName()) + "!");
}
}
5. Configure Spring for STOMP messaging
package net.javaguides.springboot.websocket.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@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").withSockJS();
}
}
We have handled the CORS issue with the following code:
public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws").setAllowedOrigins("http://localhost:4200").withSockJS(); }
Front-End - Angular 8 Client App Development
C:\Angular>node -v
v10.15.3
C:\Angular>npm -v
6.9.0
1. Install the latest version of Angular CLI
npm install -g @angular/cli
C:\angular>ng --version
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI: 8.0.1
Node: 10.15.3
OS: win32 x64
Angular:
...
Package Version
------------------------------------------------------
@angular-devkit/architect 0.800.1
@angular-devkit/core 8.0.1
@angular-devkit/schematics 8.0.1
@schematics/angular 8.0.1
@schematics/update 0.800.1
rxjs 6.4.0
2. Create Angular 8 client application using Angular CLI
ng new angular8-springboot-websocket
- npm install stompjs;
- npm install sockjs-client
- npm install jquery (just to quickly access the DOM elements)
3. package.json
{
"name": "angular8-springboot-websocket",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "~8.0.0",
"@angular/common": "~8.0.0",
"@angular/compiler": "~8.0.0",
"@angular/core": "~8.0.0",
"@angular/forms": "~8.0.0",
"@angular/platform-browser": "~8.0.0",
"@angular/platform-browser-dynamic": "~8.0.0",
"@angular/router": "~8.0.0",
"jquery": "^3.4.1",
"net": "^1.0.2",
"rxjs": "~6.4.0",
"sockjs-client": "^1.3.0",
"stompjs": "^2.3.3",
"tslib": "^1.9.0",
"zone.js": "~0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.800.0",
"@angular/cli": "~8.0.1",
"@angular/compiler-cli": "~8.0.0",
"@angular/language-service": "~8.0.0",
"@types/node": "~8.9.4",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "^5.0.0",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.1.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.15.0",
"typescript": "~3.4.3"
}
}
4. WebSocket API
import * as Stomp from 'stompjs';
import * as SockJS from 'sockjs-client';
import { AppComponent } from './app.component';
export class WebSocketAPI {
webSocketEndPoint: string = 'http://localhost:8080/ws';
topic: string = "/topic/greetings";
stompClient: any;
appComponent: AppComponent;
constructor(appComponent: AppComponent){
this.appComponent = appComponent;
}
_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);
}
/**
* Send message to sever via web socket
* @param {*} message
*/
_send(message) {
console.log("calling logout api via web socket");
this.stompClient.send("/app/hello", {}, JSON.stringify(message));
}
onMessageReceived(message) {
console.log("Message Recieved from Server :: " + message);
this.appComponent.handleMessage(JSON.stringify(message.body));
}
}
5. app.component.ts -> AppComponent
import { Component } from '@angular/core';
import { WebSocketAPI } from './WebSocketAPI';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'angular8-springboot-websocket';
webSocketAPI: WebSocketAPI;
greeting: any;
name: string;
ngOnInit() {
this.webSocketAPI = new WebSocketAPI(new AppComponent());
}
connect(){
this.webSocketAPI._connect();
}
disconnect(){
this.webSocketAPI._disconnect();
}
sendMessage(){
this.webSocketAPI._send(this.name);
}
handleMessage(message){
this.greeting = message;
}
}
6. app.component.html
<!--The content below is only a placeholder and can be replaced.-->
<<noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websocket relies on Javascript being
enabled. Please enable
Javascript and reload this page!</h2></noscript>
<div id="main-content" class="container">
<div class="row">
<div class="col-md-12">
{{ greeting }}
</div>
</div>
<div class="row">
<div class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label for="connect">WebSocket connection:</label>
<button (click)="connect()" class="btn btn-default" type="submit">Connect</button>
<button (click)="disconnect()" class="btn btn-default" type="submit" disabled="disabled">Disconnect
</button>
</div>
</form>
</div>
<div class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label for="name">What is your name?</label>
<input type="text" [(ngModel)]="name" class="form-control" name="name"> <br>
</div>
<button (click)="sendMessage()" class="btn btn-default" type="submit">Send</button>
</form>
</div>
<p> {{ greeting }}</p>
</div>
</div>
<router-outlet></router-outlet>
7. index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Angular8SpringbootWebsocket</title>
<base href="/">
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<script>
if (global === undefined) {
var global = window;
}
</script>
</head>
<body>
<app-root></app-root>
</body>
</html>
8. app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { FormsModule } from '@angular/forms'
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
9. Running Angular 8 Client Application
ng serve
ng serve --port 4201
Demo
Source Code on GitHub
Follow the below steps to run the back-end application:
1. Extract the back-end zip file
2. cd back-end/springboot-stomp-websocket
3. mvn spring-boot:run
Thank you for this awesome tutorial
ReplyDeleteHow i will initialize the web socket API if my app component has a lot of services, for example...
ReplyDeleteconstructor(
@Inject(DOCUMENT) private document: any,
private _platform: Platform,
private idle: Idle,
private keepalive: Keepalive,
private router: Router,
private gw: ApiGateway,
private snackBar: SnackBarService,
private userService: UserService
) {
What do u think if i change the handlerMessage with a event emmiter, can get the value directly in app component. Let me know what is ur opinion about?
DeleteThanks a lot for the tutorial
ReplyDeleteI need to send message after updating a record in db to client.
ReplyDeleteHow to achieve this in spring boot.
Spring application will push notifications to client after every change in record
you can use Spring webflux
Deletethat greeting field is not updating after after the success ,can you pls tell me why it is
ReplyDeletefinally i found out the issue
Deletewhat is the issue?
Deletei'd like to know too, can't figure it out
DeleteI'd like to know aswell
DeleteI have this error when trying to connect:
ReplyDeleteAccess to XMLHttpRequest at 'http://localhost:8080/ws/info?t=1576698440026' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
download and Enable the cors extension from chrome store. this will resolve the issue.
DeleteHello,
ReplyDeleteit's great with the tutorial, thank you so much for good job :-)
I've tried it and works very well by using ng serve -o.
But there is indeed a little bit problem by running it after running
ng build --prod
Within the Directory dist/angular8-springboot-websocket there is an index.html.
The application does not work by opening of it:
Error:
Access to script at 'file:///C:/runtime-es2015.edb2....js' from orgin 'null' has bin blocked by CORS Policy: cross index.html:1 origin requests are only supported for protocol schemes: http,data, Chrome, Chrome-Extension, https.
The same error for other js-files polyfills-es2015..., main-es2015.... and so on
Question: What is wrong and how can this Problem be solved ?
Thanks in advanced
and with best reguards
Mr. Dang
I have a question. How to print the conversation on screen except console.???..
ReplyDeleteBackend folder is empty could you please upload that also
ReplyDeleteHi, this only works for me if I 1)
ReplyDeleteimplement OnInit in step 5:
export class AppComponent implements OnInit { etc etc
and 2) if I do not switch to another port.
(why would you want to change ports in Angular for this? You set it up in the back end to only allow port 4200. If you switch to 4201 you get CORS errors)
I'm using Angular 9 by the way. Although I think both issues would also be present in older versions.
DeleteERROR in ./node_modules/stompjs/lib/stomp-node.js
ReplyDeleteModule not found: Error: Can't resolve 'net' in 'D:\angular8-springboot-websocket\node_modules\stompjs\lib'
you have to install npm "net" package:
Deletenpm install --save-dev net
After hours of trying to print the message to the screen I finally managed
ReplyDeleteJust had to write the handleMessage + connect inside the component i.e -> the connec . subscription part
can you dive a bit further into your solution? It would be great if you can share the code !!
DeleteJust remember what a service and component are meant for
DeleteService gives API access to url and components implements the "methods" and renders the data to the view (e.g .html)
So in the api/service connect func... you can return a stompClient after Stomp.over(ws), and in the component where you'll call the api_connect handle the message output
That's it, two way data binding will handle the rest
Thanks alot . It is so helpful .
Deleteapp.component.ts
Deletebefore...
handleMessage(message){
this.greeting = message;
}
after...
handleMessage(message){
this.greeting = message.body;
}
The port 8080 is common for all or it might be different.
ReplyDeletehttp://localhost:8080/ws
Thanks for the article.
ReplyDeleteWhat if I want to share WebSocketAPI with mutiple components?
_connect service / API must return stompClient after connection to Stomp.over(ws)
DeleteAnd implement the rest in their components
Hi. How about add Auth2 and use wss?
ReplyDeletein reconnect function, this is not accessible, it is appearing as undefined.
ReplyDeleteI need to display the greeting in webpage. No idea how it is
ReplyDeletedid you find any solution ?
DeleteGreat tutorial!
ReplyDeleteI know it's just to show something quickly, but please don't advice people to install jquery in an Angular project, that's really not a good thing to do!
Great tutoriel but i need ti send notification to a specific user(profil) ? any idea
ReplyDelete'this' keyword is undefined on errorCallBack function. Any solution for this
ReplyDeleteadding this.errorCallBack.bind(this) worked for me
Delete