This article shows you how to setup a very basic
WebSocket application powered by
Spring Boot. It uses the
Java API for WebSocket (
JSR-356) to define a WebSocket server endpoint and includes a very simple JavaScript WebSocket client.
As usual for a Spring Boot application, it all starts with the Maven POM:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ervacon.sb</groupId>
<artifactId>websocket</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<!-- Add typical dependencies for a websocket application -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies>
<!-- Package as an executable jar -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Notice how we pull in the
spring-boot-starter-websocket dependency.
This will make sure the Java API for WebSocket (
javax.websocket) is on
the classpath, together with
Spring's support for WebSocket. When Spring Boot starts it will detect these dependencies and auto-configure the embedded Servlet engine
(Tomcat by default) to handle the WebSocket protocol.
Next, we define our
@SpringBootApplication class:
package com.ervacon.sb.websocket;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
The only special thing here is the fact that we register the
ServerEndpointExporter,
which will make sure our
@ServerEndpoint annotated classes get registered
with the WebSocket runtime.
We can now define our server side WebSocket endpoint:
package com.ervacon.sb.websocket;
import org.springframework.stereotype.Component;
import javax.websocket.OnMessage;
import javax.websocket.server.ServerEndpoint;
@Component
@ServerEndpoint("/socket")
public class WebSocketEndpoint {
@OnMessage
public String echo(String message) {
return "Echo: " + message;
}
}
Nothing to surprising here: we're just using the Java API for WebSocket (JSR-356)
to define a method that will handle incoming text messages by simply echoing
them back to the client. That client is implemented using some basic JavaScript
code in a simple HTML page (add this as
index.html to
src/main/resources/static in your Spring Boot application):
<html>
<head>
<title>WebSocket Client</title>
<!-- based on https://www.nexmo.com/blog/2018/10/08/create-websocket-server-spring-boot-dr/ -->
</head>
<body>
<div class="container">
<div id="messages" style="border: 1px solid gray; padding: 1em;"></div>
<div class="input-fields">
<p>Type your message:</p>
<input id="message"/>
<button id="send">Send</button>
</div>
</div>
</body>
<script>
const messageWindow = document.getElementById("messages");
const sendButton = document.getElementById("send");
const messageInput = document.getElementById("message");
const socket = new WebSocket("ws://localhost:8080/socket");
socket.onopen = function (event) {
addMessageToWindow("Connected");
};
socket.onmessage = function (event) {
addMessageToWindow(`Got Message: ${event.data}`);
};
sendButton.onclick = function (event) {
sendMessage(messageInput.value);
messageInput.value = "";
};
function sendMessage(message) {
socket.send(message);
addMessageToWindow("Sent Message: " + message);
}
function addMessageToWindow(message) {
messageWindow.innerHTML += `<div>${message}</div>`
}
</script>
</html>
We can now launch our Spring Boot application using a simple
mvn spring-boot:run
and test it by accessing
http://localhost:8080/.