Build Chat Room with WebSocket in Spring MVC Framework

On the Eclipse, create a Spring MVC project

Enter Project Information:

  • Name: LearnSpringMVCWithRealApps
  • Group: com.demo
  • Artifact: LearnSpringMVCWithRealApps
  • Description: Learn Spring MVC with Real Apps
  • Package: com.demo

Select the technologies and libraries to be used:

  • Web

Click Next button to show Site Information for project

Click Finish button to finish create Spring MVC project




<?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.10.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.demo</groupId>
	<artifactId>LearnSpringMVCWithRealApps</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>LearnSpringMVCWithRealApps</name>
	<description>Learn Spring MVC with Real Apps</description>

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

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

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>javax.servlet.jsp.jstl</groupId>
			<artifactId>javax.servlet.jsp.jstl-api</artifactId>
			<version>1.2.1</version>
		</dependency>

		<dependency>
			<groupId>taglibs</groupId>
			<artifactId>standard</artifactId>
			<version>1.1.2</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-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>




spring.mvc.view.prefix = /WEB-INF/views/
spring.mvc.view.suffix = .jsp
spring.mvc.static-path-pattern=/resources/**

server.port=9596

Create new package, named com.demo.entities. In this package, create entities class as below:

Create new java class, named Greeting.java

package com.demo.entities;

public class Greeting {

	private String name;

	public Greeting() {
		super();
	}

	public Greeting(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}

Create new java class, named HelloMessage.java

package com.demo.entities;

public class HelloMessage {

	private String name;

	public HelloMessage(String name) {
		super();
		this.name = name;
	}

	public HelloMessage() {
		super();
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}




Create new package named com.demo.controllers. In this package, create controllers as below:

Create new java class, named DemoController.java

package com.demo.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping(value = { "", "demo" })
public class DemoController {

	@RequestMapping(method = RequestMethod.GET)
	public String index() {
		return "demo/index";
	}

}

Create new java class, named ChatController.java

package com.demo.controllers;

import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.web.util.HtmlUtils;

import com.demo.entities.Greeting;
import com.demo.entities.HelloMessage;

@Controller
public class ChatController {

	@MessageMapping("/say")
	@SendTo("/topic/chat")
	public Greeting say(HelloMessage helloMessage) throws Exception {
		return new Greeting(HtmlUtils.htmlEscape(helloMessage.getName()));
	}

}




Create new folders with path webapp\WEB-INF\views in src\main. In views folder, create views as below:

Create new folder named demo. Create new jsp file named index.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1" isELIgnored="false"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Index</title>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.3.0/sockjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>

<script type="text/javascript">
	var stompClient = null;

	function setConnected(connected) {
		$("#connect").prop("disabled", connected);

		$("#disconnect").prop("disabled", !connected);

		if (connected) {
			$("#conversation").show();
		} else {
			$("#conversation").hide();
		}
		$("#greetings").html("");
	}

	function connect() {
		var socket = new SockJS('/ws');
		stompClient = Stomp.over(socket);
		stompClient.connect({}, function(frame) {
			setConnected(true);
			console.log('Connected: ' + frame);
			stompClient.subscribe('/topic/chat', function(greeting) {
				showGreeting(JSON.parse(greeting.body).name);
			});
		});
	}

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

	function sendName() {
		stompClient.send("/app/say", {}, JSON.stringify({
			'name' : $("#name").val()
		}));
	}

	function showGreeting(message) {
		$("#greetings").append("<tr><td>" + message + "</td></tr>");
	}

	$(function() {

		$("form").on('submit', function(e) {
			e.preventDefault();
		});

		$("#connect").click(function() {
			connect();
		});

		$("#disconnect").click(function() {
			disconnect();
		});

		$("#send").click(function() {
			sendName();
		});

	});
</script>
</head>
<body>

	<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="submit">Connect</button>
						<button id="disconnect" class="btn btn-default" type="submit"
							disabled="disabled">Disconnect</button>
					</div>
				</form>
			</div>

		</div>
		<div class="row">
			<div class="col-md-6">
				<form class="form-inline">
					<div class="form-group">
						<input type="text" id="name" class="form-control"
							placeholder="Input...">
					</div>
					<button id="send" class="btn btn-default" type="submit">Send</button>
				</form>
			</div>
		</div>
		<div class="row">
			<div class="col-md-12">
				<table id="conversation" class="table table-striped">
					<thead>
						<tr>
							<th>Messages</th>
						</tr>
					</thead>
					<tbody id="greetings">
					</tbody>
				</table>
			</div>
		</div>
	</div>

</body>
</html>




Create new package named com.demo.configurations. In this package, create new java class named WebSocketConfiguration.java as below:

package com.demo.configurations;

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 WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {

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

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

}




Select LearnSpringMVCWithRealAppsApplication.java file in com.demo package, right click and select Run As/Spring Boot App menu

Open index method in demo controller with following url: http://localhost:9596/demo from multiple your browsers. Click Connect button connect to WebSocket and start chat

Output