Spring Boot Angular Websocket

Spring Boot Angular Websocket thumbnail
74K
By Dhiraj 08 March, 2018

In this tutorial, we will be discussing about creating a spring boot app to use WebSocket protocol for communication between client and server.Obviously, the server will be a spring framework based application and client will be an angular js application.Hence, this article will be integrating spring boot web socket app with an angular application and the communication between these two applications will be over WebSocket protocol.The angular version used here is Angular 5.

In the server side configuration, we will be using AbstractWebSocketMessageBrokerConfigurer to configure our websocket protocol to use STOMP as a message broker and common annotations such as @MessageMapping, @SendTo, @MessageExceptionHandler provided by spring-boot-starter-websocket. This example is using STOMP as a message broker but it is optional and here is an example of spring boot websocket without using STOMP.

In the client side, we will have an angular application running and connecting to server over websocket protocol. To integrate with websocket, we will be using stompjs library and sockJs library.You can easily extend this example application to create a chat application.

Websocket Definition

Like http, websocket is also a communication protocol which provides bi-directional, full duplex communication channel between a server and client.Once, a websocket connection is established between a client and a server, both the parties can exchange information endlessly untill the connection is closed by any one of the parties and this is the main reason why websocket is preferred over HTTP where the client and server need to exchange informations at high frequency and with low latency because HTTP connection is closed once a requet is served by server and there is a time constraint to open a HTTP connection again.

Also, the websocket protocol is bi-directional i.e. a client can subscribe for some event and server can publish the event to the client based on the availability of the event in the server.

Spring Boot Websocket Configuration

The spring boot websocket configuration is very much similar to my last article about spring boot websocket. We will have WebSocketConfig.java that has all the websocket and sockJS related configuration.

WebSocketConfig.java
package com.devglan;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

	@Override
	public void configureMessageBroker(MessageBrokerRegistry config) {
		config.enableSimpleBroker("/topic/", "/queue/");
		config.setApplicationDestinationPrefixes("/app");
	}

	@Override
	public void registerStompEndpoints(StompEndpointRegistry registry) {
		registry.addEndpoint("/greeting")
				.setAllowedOrigins("*");
				//.withSockJS();
	}

}

@EnableWebSocketMessageBroker enables message broker and by default spring uses STOMP as a message broker.Hence, this application will be using STOMP as a message broker for websocket communication but you are free to use other messaging protocol such as RabbitMQ or ActiveMQ.

Simlarly, the method configureMessageBroker() enables a simple memory-based message broker to carry the messages back to the client on destinations prefixed with "/topic" and "/queue". Hence, from our server side the websocket response will be send to endpoint prefixed with these endpoints and angular client will subscribe to url starting with these prefixes such as "/topic/reply"

Similarly,registerStompEndpoints() enables STOMP support and registers stomp endoints at "/greeting".Doing so, all the websocket messages will be channelised through STOMP and this also adds an extra layer of security to the websocket endpoint. Remember that, while creating websocket connection from javascipt, we will be using this particular stomp endpoint i.e. let socket = new WebSocket("ws://localhost:8080/greeting");only.

Now let us define our controller for mapping the messages to be received over websocket protocol.

package com.devglan.controller;

import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageExceptionHandler;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.stereotype.Controller;

import com.google.gson.Gson;

@Controller
public class WebSocketController {

	@Autowired
	private SimpMessageSendingOperations messagingTemplate;

	@MessageMapping("/message")
    @SendTo("/topic/reply")
	public String processMessageFromClient(@Payload String message) throws Exception {
		String name = new Gson().fromJson(message, Map.class).get("name").toString();
		return name;
	}
	
	@MessageExceptionHandler
    public String handleException(Throwable exception) {
        messagingTemplate.convertAndSend("/errors", exception.getMessage());
	    return exception.getMessage();
    }

}

@MessageMapping: This isto map the message headed for the url /message. So, the client should send the message at /app/message as per our WebSocketCOnfig.java.

Similarly, @SendTo is used to broadcast the message. Hence, the returned object of processMessageFromClient() will be broadcasted to this topic.To send this message to a particular user, spring provides @SendToUser

Angular JS Project Generation

Let us first generate our angular 5 project using angular cli. Make sure you have Node JS installed on your machine.A step by step configuration and tutorial on Angular is available here.

ng new angular-websocket
cd angular-websocket
ng serve

Now you can import the project in any IDE.The project strcture should look like below:

angular-websocket-project-strct

Now let us install stompjs and socksjs library first using NPM.

npm install stompjs --save
npm install sockjs-client --save

This will add dependencies in the package.json. Now, let us define our html code.The html we have has two buttons for connect and disconnect websocket connection. Similarly, the send button will send the name to server over websocket protocol in a JSON format and the server will extract the name out of it and sends back to topic which is subscribed by the client.

<div id="main-content" class="container">
  <div class="row">
    <div class="col-md-6">
      <form class="form-inline">
        <div class="form-group">
          <label for="connect">WebSocket connection:</label>
          <button id="connect" class="btn btn-default" type="button" [disabled]="disabled" (click)="connect()">Connect</button>
          <button id="disconnect" class="btn btn-default" type="button" [disabled]="!disabled" (click)="disconnect()">Disconnect
          </button>
        </div>
      </form>
    </div>
    <div class="col-md-6">
      <form class="form-inline" name="test-form">
        <div class="form-group">
          <label for="name">What is your name?</label>
          <input type="text" id="name" name="name" class="form-control" placeholder="Your name here..." [(ngModel)]="name">
        </div>
        <button id="send" class="btn btn-default" type="button" (click)="sendName()">Send</button>
      </form>
    </div>
  </div>
  <div class="row">
    <div class="col-md-12" *ngIf="showConversation">
      <table id="conversation" class="table table-striped">
        <thead>
        <tr>
          <th>Greetings</th>
        </tr>
        </thead>
        <tbody *ngFor="let greeting of greetings" >
          <tr><td> {{greeting}}</td></tr>
        </tbody>
      </table>
    </div>
  </div>

</div>

Similarly, we have following typescript code.

The connect() will create a web socket connection. Remember the mapping we did in WebSocketConfig.java class for /greeting.

showGreeting() will be simply showing the message received by the server broadcast.

send() function will construct a JSON message and sends message to the server.

app.component.ts
import { Component } from '@angular/core';
import * as Stomp from 'stompjs';
import * as SockJS from 'sockjs-client';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  greetings: string[] = [];
  showConversation: boolean = false;
  ws: any;
  name: string;
  disabled: boolean;

  constructor(){}

  connect() {
    //connect to stomp where stomp endpoint is exposed
    //let ws = new SockJS(http://localhost:8080/greeting);
    let socket = new WebSocket("ws://localhost:8080/greeting");
    this.ws = Stomp.over(socket);
    let that = this;
    this.ws.connect({}, function(frame) {
      that.ws.subscribe("/errors", function(message) {
        alert("Error " + message.body);
      });
      that.ws.subscribe("/topic/reply", function(message) {
        console.log(message)
        that.showGreeting(message.body);
      });
      that.disabled = true;
    }, function(error) {
      alert("STOMP error " + error);
    });
  }

  disconnect() {
    if (this.ws != null) {
      this.ws.ws.close();
    }
    this.setConnected(false);
    console.log("Disconnected");
  }

  sendName() {
    let data = JSON.stringify({
      'name' : this.name
    })
    this.ws.send("/app/message", {}, data);
  }

  showGreeting(message) {
    this.showConversation = true;
    this.greetings.push(message)
  }

  setConnected(connected) {
    this.disabled = connected;
    this.showConversation = connected;
    this.greetings = [];
  }
}

Websocket SockJS Config

To make use of SockJS in the client code you require to include sockjs.js in html.SockJS provides best available fallback options whenever websocket connection fails or unavailable.Following is the sample code to make use of it while establishing websocket connection from client.In the server side uncomment .withSockJS()

var socket = new SockJS('ws://localhost:8080/greeting');
ws = Stomp.over(socket);
//rest of the code as usual as above

Test Websocket Application

Run Application.java as a java application and in the console enter command ng serve and hit http://localhost:4200

spring-boot-angular-websocket-output

Conclusion

In this article, we discussed about integrating spring boot websocket with angular js.We used STOMP as a messaging protocol and sockJS to provide a fallback option.You can download the source from github

Share

If You Appreciate This, You Can Consider:

We are thankful for your never ending support.

About The Author

author-image
A technology savvy professional with an exceptional capacity to analyze, solve problems and multi-task. Technical expertise in highly scalable distributed systems, self-healing systems, and service-oriented architecture. Technical Skills: Java/J2EE, Spring, Hibernate, Reactive Programming, Microservices, Hystrix, Rest APIs, Java 8, Kafka, Kibana, Elasticsearch, etc.

Further Reading on Spring Boot