Introduction
WebSocket is a very thin, lightweight layer above TCP used to build interactive web applications that send messages back and forth between a browser and the server.
The best examples are live updates websites, where once user access the website neither user nor browser sends request to the server to get the latest updates. Server only keeps sending the messages to the browser.
In this example, I am building a WebSocket application with Spring Boot using STOMP Messaging to provide automatic updates on the greeting message depending on the time of the day for every 3 seconds.
Server Application
Prerequisites
Eclipse 4.12, Java 12 or 8, Gradle 5.6, Spring Boot WebSocket 2.1.8
Creating Project
Create gradle project called spring-websocket in the Eclipse IDE.
The corresponding build.gradle script is updated with the below content to include required dependency and configurations.
buildscript {
ext {
springBootVersion = '2.1.8.RELEASE'
}
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
sourceCompatibility = 12
targetCompatibility = 12
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-websocket:${springBootVersion}")
}
Creating POJO
We will create a simple POJO class to represent message that will be sent to the client as a push notification.
package com.roytuts.spring.websocket.vo;
public class Message {
private String msg;
public Message(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
}
WebSocket Configuration
Configure Spring to enable WebSocket and STOMP messaging.
package com.roytuts.spring.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 registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket").setAllowedOrigins("*").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
}
The above WebSocketConfig
class is annotated with @Configuration
to indicate that it is a Spring configuration class.
The class is also annotated @EnableWebSocketMessageBroker
and @EnableWebSocketMessageBroker
enables WebSocket message handling, backed by a message broker.
The configureMessageBroker()
method overrides the default method in WebSocketMessageBrokerConfigurer
interface to configure the message broker.
It starts by calling enableSimpleBroker()
to enable a simple memory-based message broker to carry the greeting messages back to the client on destinations prefixed with /topic
.
It also designates the /app
prefix for messages that are bound for @MessageMapping
annotated methods. This prefix will be used to define all the message mappings; for example, /app/hello
is the endpoint that the GreetingRestController.greeting()
method is mapped to handle.
The registerStompEndpoints()
method registers the /websocket
endpoint, enabling SockJS fallback options so that alternate transports may be used if WebSocket is not available.
The SockJS client will attempt to connect to /websocket
and use the best transport available (websocket, xhr-streaming, xhr-polling, etc).
Related Posts:
- Server Sent Events with Spring – Push Notifications
- Messaging with STOMP over WebSockets using Spring, Angular 8 and ActiveMQ
Creating Service Class
This class will generate different greet messages depending upon the time of the day. I have also appended random generated string so that we will get different random string appended with actual greet message to differentiate from each other every 3 seconds and it will actually tell us that we are getting every time the new message.
package com.roytuts.spring.websocket.service;
import java.util.Calendar;
import java.util.UUID;
import org.springframework.stereotype.Service;
import com.roytuts.spring.websocket.vo.Message;
@Service
public class GreetingService {
public Message getMessage() {
Calendar c = Calendar.getInstance();
int timeOfDay = c.get(Calendar.HOUR_OF_DAY);
StringBuilder sb = new StringBuilder();
String message = "Have a Good Day";
if (timeOfDay >= 0 && timeOfDay < 12) {
message = "Good Morning";
} else if (timeOfDay >= 12 && timeOfDay < 16) {
message = "Good Afternoon";
} else if (timeOfDay >= 16 && timeOfDay < 21) {
message = "Good Evening";
} else if (timeOfDay >= 21 && timeOfDay < 24) {
message = "Good Night";
}
sb.append(message).append(" - ").append(generateString());
return new Message(sb.toString());
}
private String generateString() {
String uuid = UUID.randomUUID().toString();
return uuid;
}
}
Creating REST Controller Class
In Spring’s approach to working with STOMP messaging, STOMP messages can be routed to @Controller
or @RestController
classes.
For example the GreetingRestController
is mapped to handle messages to destination /hello
.
package com.roytuts.spring.websocket.rest.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.web.bind.annotation.RestController;
import com.roytuts.spring.websocket.service.GreetingService;
import com.roytuts.spring.websocket.vo.Message;
@RestController
public class GreetingRestController {
@Autowired
private GreetingService greetingService;
@MessageMapping("/hello")
@SendTo("/topic/greeting")
public Message greeting() {
return greetingService.getMessage();
}
}
The @MessageMapping
annotation ensures that if a message is sent to destination /hello
, then the greeting() method is called.
Creating Scheduler
Create scheduler to push updates every 3 seconds to client.
package com.roytuts.spring.websocket.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import com.roytuts.spring.websocket.service.GreetingService;
@Configuration
@EnableScheduling
public class WebSocketSchedulerConfig {
@Autowired
private SimpMessagingTemplate template;
@Autowired
private GreetingService greetingService;
@Scheduled(fixedRate = 3000)
public void publishUpdates() {
System.out.println("Message: " + greetingService.getMessage().getMsg());
template.convertAndSend("/topic/greeting", greetingService.getMessage());
}
}
Running the application
Run the main class file SpringWebSocketApp and you will see the greeting message is getting displayed in the console.
Console Output
...
Message: Good Evening - 683407fd-22ef-43a5-87f8-85d20b7d4668
Message: Good Evening - 31817e2e-084f-4529-ad2b-c85cc61f8e2b
Message: Good Evening - ba628369-6f3a-4605-a8cf-876acadd578a
Message: Good Evening - f39c0f0d-2bb3-4a74-93d7-82583f561500
...
That’s all about server application. Now we will move to client application.
Client Application
With the server side pieces in place, now let’s turn our attention to the client that will send messages to and receive messages from the server side.
Prerequisites
Angular 8, Windows 10
Creating Angular Project
Create an Angular project called angular-spring-websocket.
Installing Required Modules
Install the required modules with the following commands:
npm install stompjs
npm install sockjs-client
npm install jquery
npm i net -S
The stompjs
is required to connect over STOMP.
The sockjs-client
is required to establish connection with WebSocket server.
The jquery
is required to directly access DOM elements in the HTML page.
To avoid net
issue we need to install net
module.
Updating index.html
We need to declare window in the src/index.html file to avoid the below issue:
Uncaught ReferenceError: global is not defined
at Object../node_modules/sockjs-client/lib/utils/browser-crypto.js
The complete content of src/index.html file is given below:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AngularSpringWebsocket</title>
<base href="/">
<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>
Updating app.component.html
We will update the src/app/app.component.html file to put a div tag where greeting message will be updated.
<div class="msg"></div>
<router-outlet></router-outlet>
Updating app.component.ts
We will update src/app/app.component.ts file to consume the message over STOMP.
We set the page title by implementing OnInit
interface in the ngOnInit()
method.
We establish connection to the WebSocket server, client socket subscribe to the topic /topic/greeting
destination, where the server will publish greeting messages and finally we update the div (having a class msg
) on HTML page.
import { OnInit, Component } from '@angular/core';
import { Title } from '@angular/platform-browser';
import * as Stomp from 'stompjs';
import * as SockJS from 'sockjs-client';
import $ from 'jquery';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
url = 'http://localhost:8080/websocket'
client: any;
greeting: string;
ngOnInit() {
this.title.setTitle('Angular Spring Websocket');
}
constructor(private title: Title){
this.connection();
}
connection(){
let ws = new SockJS(this.url);
this.client = Stomp.over(ws);
let that = this;
this.client.connect({}, function(frame) {
that.client.subscribe("/topic/greeting", (message) => {
if(message.body) {
this.greeting = message.body;
//$(".msg").append(this.greeting)
$(".msg").html(this.greeting)
//alert(this.greeting);
//console.log(this.greeting);
}
});
});
}
}
We do not want to send any message to the destination /app/hello
, so we don’t need to call this endpoint. We are here to just get the message from server as a push notification towards clients.
Testing the Application
With your server running now run the client application by executing command ng serve --open
.
Your application opens at http://localhost:4200 and you will see the message being updated every 3 seconds.

Source Code
Thanks for reading.