Spring Boot WebSocket Angular 8 Gradle Example

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:

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.

spring boot websocket angular js

Source Code

download source code

Thanks for reading.

Leave a Reply

Your email address will not be published. Required fields are marked *