Spring Boot + Websocket + Example

By Dhiraj Ray, 28 January,2017   | Last updated on: 05 January,2018 21K

Hello friends, let us again walk through creating websocket connection in spring but this time with spring and STOMP protocol.We will also make use of Spring security to restrict websocket server reply to a single client(queue) instead of broadcasting to all clients(topic).Here, We will be using spring boot configurations to configure websocket connection with STOMP, sockJS and spring security.Here is my previous post that describes spring websocket connection without STOMP and Spring boot websocket angular example

Table of Contents
1. What is WebSocket 
2. What is STOMP 
3. Spring Boot Setup 
4. Maven Dependencies
5. Spring Boot Websocket Configuration
6. Websocket Listeners and Interceptors
7. Websocket Endpoint
8. Websocket Client
9. Websocket SockJS Config
10. Run Websocket Application

What is WebSocket

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.

What is STOMP

STOMP stands for Streaming Text Oriented Messaging Protocol. As per wiki, STOMP is a simple text-based protocol, designed for working with message-oriented middleware (MOM). It provides an interoperable wire format that allows STOMP clients to talk with any message broker supporting the protocol.Spring provides default support for it but you are open to choose any other messaging protocol such as RabbitMQ or ActiveMQ.

Spring Boot Setup

1. JDK 8 2. Spring Boot 3. Intellij Idea/ eclipse 4. Tomcat(embedded with Spring) 5. Maven

Maven Dependencies

spring-boot-starter-websocket - Provides useful defaults for websocket.

pom.xml
<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>1.3.3.RELEASE</version>
</parent>
<properties>
	<tomcat.version>8.0.3</tomcat.version>
</properties>

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-websocket</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-security</artifactId>
	</dependency>
	<dependency>
		<groupId>com.google.code.gson</groupId>
		<artifactId>gson</artifactId>
	</dependency>
<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
	
</dependencies>
 Other Interesting Posts
Maintaining Spring Session during Websocket Connection
Websocket spring Boot Integration without STOMP
Password Encoding using Bcrypt Encoder
Spring Boot Security Redirect after Login with complete JavaConfig
Spring Security Hibernate Example with complete JavaConfig
Securing REST API with Spring Security Basic Authentication
Spring JMS Activemq Integration with Spring Boot
Spring MVC Angularjs Integration with complete JavaConfig
Spring Hibernate Integration with complete JavaConfig
Spring Junit Integration with complete JavaConfig
Spring Ehcache Cacheable Example with complete javaConfig
Spring Boot Spring MVC Example
Spring Boot Thymeleaf Example

Spring Boot Websocket Configuration

First of all let us configure our STOMP message broker.In WebSocketConfig.java we have defined our message broker STOMP endpoint and websocket application endpoint.

@Configuration : It indicates that it is a Spring configuration class.

@EnableWebSocketMessageBroker : It enables WebSocket message handling, backed by a message broker. Here we are using STOMP as a mesage broker.

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". It also designates the "/app" prefix for messages that are bound for @MessageMapping-annotated methods in controller class. This prefix will be used to define all the message mappings; for example, "/app/message" is the endpoint that the WebSocketController.processMessageFromClient() method is mapped to handle.

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 only.

In the configuration below to enable SockJs support to provide deafult falback option, we need to make following changes.

registry.addEndpoint("/greeting").withSockJS();

The advantage of using sockJS here is whenever the websocket connection is disconnected or the websocket connection can not be established,then the connection will be downgraded to HTTP and the communication between client and server can still continue.

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");;
	 }
	
}

Websocket Listeners and Interceptors

Apart from above configuration, spring boot also provides mechanism to register different listeners or interceptors and this configuration can be added in registerStompEndpoints() methods defined above.

SessionConnectEvent - Whenever a WebSocket client using a Simple Messaging Protocolas raises a connect request.

SessionConnectEvent -Whenever a websocket client is connected.

SessionConnectEvent -A connected event represents the server response to a client's connect request.

SessionSubscribeEvent -Whenever a connected client sends a subscription request to server.

SessionUnsubscribeEvent -Whenever a connected client sends a request to to remove a subscription.

There are lot of such event provided by spring websocket API.Also, there are many interceptors provided by spring which can be configured in above config class.Following is an example to register HandshakeInterceptor from my one of the post.

public class HttpHandshakeInterceptor implements HandshakeInterceptor {

	@Override
	public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
			Map attributes) throws Exception {
		if (request instanceof ServletServerHttpRequest) {
			ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
			HttpSession session = servletRequest.getServletRequest().getSession();
			attributes.put("sessionId", session.getId());
		}
		return true;
	}

	public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
			Exception ex) {
	}
}

Above interceptor can be registered as below:

registry.addEndpoint("/greeting").addInterceptors(new HttpHandshakeInterceptor());

Websocket Endpoint

Now let us define our controller and map the websocket connection endpoint.

@MessageMapping: This isto map the message headed for the url /message

@SendToUser: indicates that the return value of a message-handling method should be sent as a org.springframework.messaging.Message to the specified destination(s) prepended with "/user/{username}" where the user name is extracted from the headers of the input message being handled.

@MessageExceptionHandler: throw any exceptions caused by STOMP to the end user on the /queue/errors destination.

@Payload: to extract the payload of a message and optionally convert it using spring MessageConverter.

WebSocketController.java
package com.devglan.controller;

import java.security.Principal;
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.simp.SimpMessageSendingOperations;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.stereotype.Controller;

import com.google.gson.Gson;

@Controller
public class WebSocketController {

	@Autowired
	private SimpMessageSendingOperations messagingTemplate;

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

}

convertAndSendToUser() facilitates same operation as of @SendToUser.This is used when you want to send message to a particular user and this message will be sent to a queue. There is also convertAndSend() which will broadcast message to a topic.

We wll be using spring boot feature to run our application. The spring boot maven plugin will collect all the jars on the classpath and builds a single, runnable jar file, which makes it more convenient to execute and transport our service. It searches for the public static void main() method to flag as a runnable class and provides built-in dependency resolver that sets the version number to match spring boot dependencies.

SpringBootServletInitializer enables process used in Servlet 3.0 using web.xml

@SpringBootApplication: This is a convenience annotation that is equivalent to declaring @Configuration,@EnableAutoConfiguration and @ComponentScan.

Application.java
package com.devglan.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.web.SpringBootServletInitializer;

@SpringBootApplication
public class Application extends SpringBootServletInitializer {
	
	 private static Class applicationClass = Application.class;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

Websocket Client

app.js

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

The function onmessage() will execute itself once any message is broadcasted by server

function 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.

function connect() {
	var socket = new WebSocket('ws://localhost:8080/greeting');
	ws = Stomp.over(socket);

	ws.connect({}, function(frame) {
		ws.subscribe("/user/queue/errors", function(message) {
			alert("Error " + message.body);
		});

		ws.subscribe("/user/queue/reply", function(message) {
			showGreeting(message.body);
		});
	}, function(error) {
		alert("STOMP error " + error);
	});
}

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

function sendName() {
    ws.send($("#name").val());
}

function showGreeting(message) {
    $("#greetings").append(" " + message + "");
}

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.

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

Run Websocket Application

1. Run the Application.java as a java application. 2. Open the browser and hit the URL - http:localhost:8080. It will prompt for username and password as below.By default the username is user and password you can check in the console. spring-boot-websocket-security-login 3. Now, you can see the index.html after successful authentication. 4. Click on connect button to make the socket connection. 5. Enter the name and post the message and you can see the greeting message as below from websocket server.

web-socket-example

Conclusion

In this article we learned about spring boot websocket configuration and implemenation.I hope this article served you that you were looking for. If you have anything that you want to add or share then please share it below in the comment section.

Download the source

1. Spring Boot Angular Websocket

2. Spring 5 Features And Enhancements

3. Spring Websocket Integration Example Without Stomp

4. Spring Session Stomp Websocket

5. Spring Jms Activemq Integration Example

If You Appreciate What We Do Here On Devglan, You Should Consider: