Part 3 – WebSocket Example with Spring Boot + Angular 6 + STOMP

What have we learned so far,

 
Part 1 – How server sends notification to client? Polling and Server Sent Events
 
Part 2- What is WebSocket? Polling vs Server Sent Events vs WebSocket
Scenario

We will implement a Angular client where the user will connect to the server and send the text to server and then server will append “Message from server: Hello ” and send to the user.

Spring Boot + STOMP + WebSocket Backend
Step 1 : Add maven dependency
<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-messaging</artifactId>
            <version>5.0.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>5.0.9.RELEASE</version>
        </dependency>

Step 2 : Enable WebSocket in Spring Boot
We need to add the @EnableWebSocketMessageBroker to enable the WebSocket capabilities. It enables WebSocket message handling, backed by a message broker.

package com.onlyfullstack.springbootwebsocketbackend.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 {

 /**
  * Configure message broker options.
  */
 @Override
 public void configureMessageBroker(MessageBrokerRegistry config) {
  config.enableSimpleBroker("/topic");
  config.setApplicationDestinationPrefixes("/onlyfullstack"); // prefix for every @MessageController path
 }

 /**
  * Register STOMP endpoints mapping each to a specific URL and (optionally)
  * enabling and configuring SockJS fallback options.
  */
 @Override
 public void registerStompEndpoints(StompEndpointRegistry registry) {
  registry
  .addEndpoint("/onlyfullstack-stomp-endpoint") // Where the client will connect to the STOMP server
  .setAllowedOrigins("http://localhost:4200")
  .withSockJS();
 }
}

Here, we can see that the method configureMessageBroker is used to configure the message broker. First, we enable an in-memory message broker to carry the messages back to the client on destinations prefixed with “/topic”.

We complete our simple configuration by designating the “/onlyfullstack” prefix to filter destinations targeting application annotated methods (via @MessageMapping).

The registerStompEndpoints method registers the “/onlyfullstack-stomp-endpoint” endpoint, enabling Spring’s STOMP support.
It also enables the SockJS fallback options, so that alternative messaging options may be used if WebSockets are not available. This is useful since WebSocket is not supported in all browsers yet and may be precluded by restrictive network proxies.

Step 3 : Lets create DTOs to transfer the data over the network.
package com.onlyfullstack.springbootwebsocketbackend.model;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Hello {

    private String greeting;
}
package com.onlyfullstack.springbootwebsocketbackend.model;


import lombok.Data;

@Data
public class User {

 private String name;
}

Step 4 : Create a Message-Handling Controller with @MessageMapping method

package com.onlyfullstack.springbootwebsocketbackend.controller;


import com.onlyfullstack.springbootwebsocketbackend.model.Hello;
import com.onlyfullstack.springbootwebsocketbackend.model.User;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;

@Controller
public class WebSocketController {

 @MessageMapping("/hello") // endpoint where the client will send messages or events
 @SendTo("/topic/hi")      // messaging queue endpoint where client will be listening
 public Hello greeting(User user) {
  return new Hello("Message from server: Hello " + user.getName());
 }
}

Spring’s approach to working with STOMP messaging is to associate a controller method to the configured endpoint. This is made possible through the @MessageMapping annotation.

Okay so we have successfully created the WebSocket at backend and now we will start the frontend development of Angular 6 + StompJs.

Angular 6 + StompJs + WebSocket Frontend

Step 1 : Create new project using Angular CLI

ng new WebsocketAangular6Frontend

Step 2 : Install @stomp/stompjs and socksjs-client

npm install @stomp/stompjs --save

npm install sockjs-client --save

Step 3 : Add this code in the first line of polyfills.ts file:

(window as any).global = window;

Step 4 : Add required module of Angular Material and form

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import {MatButtonModule, MatFormFieldModule, MatInputModule, MatDividerModule, MatCardModule} from '@angular/material';
import { FlexLayoutModule } from '@angular/flex-layout';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    MatButtonModule,
    MatFormFieldModule,
    MatInputModule,
    BrowserAnimationsModule,
    FlexLayoutModule,
    ReactiveFormsModule,
    MatDividerModule,
    MatCardModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Step 4 : Design the HTML form
app.component.html

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>{{title}}</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>

<body>
  <div style="color: #280861; text-align: center">
    <h1 class="mat-title">WebSocket with Spring Boot + STOMP + Angular 6</h1>
    <a class="mat-subheading-2" href="#">Websocket with Spring Boot and Agngular 6 guide</a>
    <h4 class="mat-h4">Author - Saurabh Oza (Only Fullstack Developer Blog)</h4>
  </div>
  <mat-divider [inset]="true" style="margin: 2%"></mat-divider>

  <div fxLayout="column" fxLayoutAlign="space-evenly center" fxLayouyGap="1%">
    <label>Make Connection</label>
    <div fxLayout="row" fxLayoutAlign="space-evenly center" style="min-width: 40%">
      <button mat-raised-button color="primary" type="button" [disabled]="!disabled"
        (click)="connectToWebsocketWithStomp()">Connect</button>
      <button mat-raised-button type="submit" [disabled]="disabled"
        (click)="disconnect()">Disconnect</button>
    </div>
  </div>

  <mat-divider [inset]="true" style="margin: 2%"></mat-divider>

  <div fxLayout="column" fxLayoutAlign="space-evenly center" *ngIf="!disabled">
    <div>
      <p class="mat-subheading-2">You are connected to the server, now you can send user names.</p>
    </div>
    <form [formGroup]="userForm" fxLayout="column" (submit)="submit()">
      <mat-form-field class="example-full-width">
        <input matInput placeholder="User's Name" formControlName="userName">
      </mat-form-field>
      <button mat-raised-button color="primary" type="submit">Send</button>
    </form>
    <div fxLayout="column" fxLayoutGap="1%">
      <mat-card *ngFor="let greeting of greetings" style="min-width: 30%">
        {{greeting}}
      </mat-card>
    </div>
  </div>
</body>

</html>

Step 5 : Add some logic in our component file.
app.component.ts

import { Component, OnInit } from '@angular/core';
import * as Stomp from '@stomp/stompjs';
import * as SockJS from 'sockjs-client';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';

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

  greetings: string[] = [];

  disabled = true;

  private stompClient = null;

  userForm: FormGroup;

  constructor(private formBuilder: FormBuilder) { }

  ngOnInit(): void {
    this.userForm = this.formBuilder.group({
      userName: ['', Validators.required]
    });
  }

  /**
   * This method creates a WebSocket connection with server using a stomp js client
   */
  connectToWebsocketWithStomp() {
    const socket = new SockJS('http://localhost:8080/onlyfullstack-stomp-endpoint');
    this.stompClient = Stomp.over(socket);

    const _this = this;
    this.stompClient.connect({}, function(frame) {
      _this.showUserNameForm(true);
      console.log('Connected: ' + frame);

      _this.stompClient.subscribe('/topic/hi', function(hello) {
        _this.showGreeting(JSON.parse(hello.body).greeting);
      });
    });
  }

  /**
   * This method disconnects the WebSocket connection
   */
  disconnect() {
    if (this.stompClient != null) {
      this.stompClient.disconnect();
    }

    this.showUserNameForm(false);
    console.log('Disconnected!');
  }
/**
 * This method submits the username form aand sends the entered data to the server
 */
  submit() {
    this.stompClient.send(
      '/onlyfullstack/hello',
      {},
      JSON.stringify({ name: this.userForm.value.userName })
    );
  }

  showGreeting(message) {
    this.greetings.push(message);
  }

  showUserNameForm(connected: boolean) {
    this.disabled = !connected;

    if (connected) {
      this.greetings = [];
    }
  }
}

Run and check the result
– Spring Boot backend project with command-lines: mvn clean install and mvn spring-boot:run.
– Angular project: npm install and npm start.

Now Open browser with url http://localhost:4200/.
Click on Connect button and send User’s Name.

WebSocket2Bwith2BSpring2BBoot2B252B2BSTOMP2B252B2BAngular2B6
Source Code
Download the source code of WebSocket tutorial from below git repository :
websocket-with-spring-boot-and-angular-6
 
WebSocket Tutorial

1 Comment

Comments are closed.