Spring 5 : Spring Boot WebFlux WebSocket | Code Factory


Donate : Link

Medium Blog : Link

Applications : Link

Spring webflux which support websocket connection between a client and server.

A websocket is a bi-directional, full-duplex, persistent connection between a web browser and a server. Once the connection is established, it stays open until the client or server decides to close this connection. Websockets have practical use in applications where multiple users connects with each other and send and receive messages e.g. chat applications.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.7.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.codeFactory</groupId>
	<artifactId>spring-5-webflux-websocket</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-5-webflux-websocket</name>
	<description>Spring Boot WebFlux WebSocket Example</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</artifactId>
		</dependency>

		<dependency>
			<groupId>javax.websocket</groupId>
			<artifactId>javax.websocket-api</artifactId>
			<version>1.1</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>io.projectreactor</groupId>
			<artifactId>reactor-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

Spring5WebfluxWebsocketApplication.java

package com.codeFactory;

import java.util.HashMap;
import java.util.Map;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.server.WebSocketService;
import org.springframework.web.reactive.socket.server.support.HandshakeWebSocketService;
import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter;
import org.springframework.web.reactive.socket.server.upgrade.ReactorNettyRequestUpgradeStrategy;

import com.codeFactory.handler.EchoHandler;

/**
 * @author code.factory
 *
 */
@SpringBootApplication
public class Spring5WebfluxWebsocketApplication {

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

	@Bean
	public EchoHandler echoHandler() {
		return new EchoHandler();
	}

	@Bean
	public HandlerMapping handlerMapping() {
		Map<String, WebSocketHandler> map = new HashMap<>();
		map.put("/echo", echoHandler());

		SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
		mapping.setUrlMap(map);
		mapping.setOrder(Ordered.HIGHEST_PRECEDENCE);
		return mapping;
	}

	@Bean
	public WebSocketHandlerAdapter handlerAdapter() {
		return new WebSocketHandlerAdapter(webSocketService());
	}

	@Bean
	public WebSocketService webSocketService() {
		return new HandshakeWebSocketService(new ReactorNettyRequestUpgradeStrategy());
	}
}

EchoHandler.java

package com.codeFactory.handler;

import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketSession;

import reactor.core.publisher.Mono;

/**
 * @author code.factory
 *
 */
public class EchoHandler implements WebSocketHandler {

	@Override
	public Mono<Void> handle(WebSocketSession session) {
		return session.send(session.receive()
				.map(msg -> "RECEIVED ON SERVER : " + msg.getPayloadAsText())
				.map(session::textMessage));
	}

}

app.js

var ws = null;
var url = "ws://localhost:8080/echo";

function setConnected(connected) {
	document.getElementById('connect').disabled = connected;
	document.getElementById('disconnect').disabled = !connected;
	document.getElementById('echo').disabled = !connected;
}

function connect() {
	ws = new WebSocket(url);
	ws.onopen = function() {
		setConnected(true);
		log('Info: Connection Established.');
	};

	ws.onmessage = function(event) {
		log(event.data);
	};

	ws.onclose = function(event) {
		setConnected(false);
		log('Info: Closing Connection.');
	};
}

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

function echo() {
	if (ws != null) {
		var message = document.getElementById('message').value;
		log('Sent to server :: ' + message);
		ws.send(message);
	} else {
		alert('Connection not established, please connect.');
	}
}

function log(message) {
	var console = document.getElementById('logging');
	var p = document.createElement('p');
	p.appendChild(document.createTextNode(message));
	console.appendChild(p);
}

index.html

<!DOCTYPE html>
<html>
<head>
<link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.10/semantic.min.css" />
<script type="text/javascript" src="app.js"></script>
</head>
<body>
	<div>
		<div id="connect-container" class="ui centered grid">
			<div class="row">
				<button id="connect" onclick="connect();" class="ui green button ">Connect</button>
				<button id="disconnect" disabled="disabled" onclick="disconnect();" class="ui red button">Disconnect</button>
			</div>
			<div class="row">
				<textarea id="message" style="width: 350px" class="ui input" placeholder="Message to Echo"></textarea>
			</div>
			<div class="row">
				<button id="echo" onclick="echo();" disabled="disabled" class="ui button">Echo message</button>
			</div>
		</div>
		<div id="console-container">
			<h3>Logging</h3>
			<div id="logging"></div>
		</div>
	</div>
</body>
</html>

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s