Websocket Integration With Spring Boot.

Hey Guys, I have posted an article to explain  how to send notification to the web application in real time with spring boot application with websocket.
Few Steps We Need To Follows :

1) Create simple spring boot application with spring web dependency  only. You can use this link https://start.spring.io to create spring boot application.

2) Once project set up then  add one more dependency for websocket  in pom.xml file.

<!-- For web socket -->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

3) Now we are ready to configure web socket message broker. I have create  new package com.firststepitsolution.spring.ws.api.config  and created new class WsConfig under the above package and implemented WebSocketMessageBrokerConfigurer. As I have mentioned this is the web socket configuration class so we need to annotate this class as @Configuration and we need to add @EnableWebSocketMessageBroker annotation to enable web socket.

package com.firststepitsolution.spring.ws.api.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 WsConfig implements WebSocketMessageBrokerConfigurer {

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

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

In the above code snippet "config.enableSimpleBroker( "/user", "/secured/user/queue/specific-user")"  this line is important  to send message to specific users who have subscribed from the client applicaion. "registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();" this line is important to establish connection between server and client.

3) Create new package with name "com.firststepitsolution.spring.ws.api.socket" and create new class with the name of "SocketSender" and annotate with @Component. This class is responsible to send massage to specific user. I have injected SimpMessagingTemplate    and used convertAndSendToUser to send message to specific user. Below is the code snippet for this class.

package com.firststepitsolution.spring.ws.api.socket;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Component;

import com.firststepitsolution.spring.ws.api.DTO.OutputNotificationMessageDTO;

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class SocketSender {

	private final SimpMessagingTemplate simpMessagingTemplate;

	@Autowired
	public SocketSender(SimpMessagingTemplate simpMessagingTemplate) {
		this.simpMessagingTemplate = simpMessagingTemplate;

	}

	public void sendToWeb(OutputNotificationMessageDTO outputNotificationMessageDTO, Long id) {
		log.info("Sending data to user are {} and message going to id is {}", outputNotificationMessageDTO.toString(),
				id);
		simpMessagingTemplate.convertAndSendToUser(id.toString(), "/queue/notification", outputNotificationMessageDTO);
	}
}

4) I have created one Rest Controller for sending message to user using web socket. For this create one new package "com.firststepitsolution.spring.ws.api.controller" and create class "SendToUserController". This rest controller is only responsible to send message. Below is the code snippet for this class.

package com.firststepitsolution.spring.ws.api.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.firststepitsolution.spring.ws.api.DTO.MessageSendToUserDTO;
import com.firststepitsolution.spring.ws.api.DTO.OutputNotificationMessageDTO;
import com.firststepitsolution.spring.ws.api.socket.SocketSender;

import lombok.extern.slf4j.Slf4j;

@RestController
@Slf4j
public class SendToUserController {

	@Autowired
	private SocketSender socketSender;

	@PostMapping("/send/{id}")
	public ResponseEntity<Object> register(@PathVariable("id") Long id,
			@RequestBody MessageSendToUserDTO messageSendToUserDTO) {
		log.info("Request data are {}", messageSendToUserDTO.toString());
		OutputNotificationMessageDTO outputNotificationMessageDTO = new OutputNotificationMessageDTO();
		outputNotificationMessageDTO.setId(id);
		outputNotificationMessageDTO.setTitle(messageSendToUserDTO.getTitle());
		outputNotificationMessageDTO.setMessage(messageSendToUserDTO.getMessage());
		socketSender.sendToWeb(outputNotificationMessageDTO, id);
		return ResponseEntity.ok().build();
	}
}

5) Backend is ready. All the source code are not added in this article so if you want to download complete working source code then you can visit my git hub repository Repository Link.  I have added some additional library for logs and getter, setter , in this project so you need to add those library as well .

6)  Now we need to create one HTML file to act as a client . Create file name web-socket-client.html and save on Desktop.Make sure this file is not a part of sprint boot project so please keep this file outside the sprint boot project. I have added code snippet below.

<html>
<head>
<title>firststepitsolution web socket demo</title>

<script type="text/javascript">
	var stompClient = null;
	function setConnected(connected) {
		document.getElementById('connect').disabled = connected;
		document.getElementById('disconnect').disabled = !connected;
		document.getElementById('response').innerHTML = '';
	}
	function connect() {
		var socket = new SockJS('http://192.168.1.8:8080/ws'); // domainname/ws
		stompClient = Stomp.over(socket);
		stompClient.connect({}, function(frame) {
			setConnected(true);
			console.log('Connected: ' + frame);
			var from = document.getElementById('from').value;
			stompClient.subscribe('/user/' + from + '/queue/notification',
					function(messageOutput) {
						console.log('log something here')
						showMessageOutput(JSON.parse(messageOutput.body));
					});
		});
	}
	function disconnect() {
		if (stompClient != null) {
			stompClient.disconnect();
		}
		setConnected(false);
		console.log("Disconnected");
	}
	
	function showMessageOutput(messageOutput) {
		var response = document.getElementById('response');
		var p = document.createElement('p');
		p.style.wordWrap = 'break-word';
		p.appendChild(document.createTextNode(messageOutput.title + ": "
				+ messageOutput.id + " (" + messageOutput.message + ")"));
		response.appendChild(p);
	}
</script>
</head>
<body onload="disconnect()">
	<div>
		<div>
			<input type="text" size=200 id="from" placeholder="pass user unique id to receive message to specific user" />
		</div>
		<br />
		<div>
			<button id="connect" onclick="connect();">Connect</button>
			<button id="disconnect" disabled="disabled" onclick="disconnect();">
				Disconnect</button>
				<p id="response"></p>
		</div>
		<br />
		
		<script
			src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.1.4/sockjs.min.js"></script>
		<script
			src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
	</div>
</body>
</html>

These two libraries are required for client application.

<script
			src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.1.4/sockjs.min.js"></script>
		<script
			src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>

 

6)  Some reference screen shot attached here:
  For source code please visit my git hub repository Repository Link. .