In this article we’re going to see how to implement web socket using Spring with STOMP protocol.
First of all, what’s Web Socket and when should I use it?
Well, Web Socket is a technology that makes it possible to open a bidirectional communication between the browser and server. The connection is established by sending an HTTP request from browser to a server to upgrade a connection and change the protocol. This operation is called Handshake.
The image bellow illustrates what was explained above.
When should I use Web Socket?
Use Web Sockets when you want two-way communication between two systems. Web Sockets are very useful for data visualization dashboards or maps that need to reflect real-time data values.
Creating Spring Application
We can use Spring Initializr to create a simple application with the Web Socket dependency like bellow.
After that, let’s create the necessary configurations to application runs correctly.
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(final MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(final StompEndpointRegistry registry) {
registry.addEndpoint("/websocket")
.setAllowedOriginPatterns("*")
.withSockJS();
}
}
The annotation @EnableWebSocketMessageBroker tells to spring to enable the Web Socket message handling.
The class WebSocketConfig overrides some default configurations about Spring implementation that have two methods called configureMessageBroker and registerStompEndPoints.
The first one configures the message broker. Basically we enable a simple memory-based message broker. In this case, every client must subscribe to a topic prefixed with /topic to receive the messages and every message sent to server must be prefixed with /app.
The methodregisterStompEndPoints just register the Handshake end point and set all allowed origins.
Mapping received messages
In our example we will just receive a message by the client and return the same message to show in the browser. For that we will create a DTO to represent our message.
public class Message {
private String content;
public Message() {
}
public Message(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
After the DTO is created, we need to create a Controller to receive and send to back the message.
@Controller
public class DemoController {
@MessageMapping("/message")
@SendTo("/topic/callback")
public Message stompMessage(Message message) throws Exception {
Thread.sleep(1000); // simulated delay
return new Message("Returned by server, " + HtmlUtils.htmlEscape(message.getContent()) + " 💙");
}
}
The code above uses our well-known @Controller annotation to Spring router our end-points.
The @MessageMapping it’s similar to the @RequestMapping when we are talking about HTTP requests. Then, every message that is sent to /message will be routed to stompMessage method.
On the other hand the @SendTo annotation will send the method return to a /topic/callback where the client is subscribed.
Creating the browser client
Let’s create a simple html file with some imports like: bootstrap, jquery, sockjs, and stompjs libs.
<!DOCTYPE html>
<html>
<head>
<title>Hello WebSocket</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.6.4.min.js" integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.6.1/sockjs.min.js" integrity="sha512-1QvjE7BtotQjkq8PxLeF6P46gEpBRXuskzIVgjFpekzFVF4yjRgrQvTG1MTOJ3yQgvTteKAcO7DSZI92+u/yZw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js" integrity="sha512-iKDtgDyTHjAitUDdLljGhenhPwrbBfqTKWO1mkhSFH3A7blITC9MhYon6SjnMhp4o0rADGw9yAC6EW4t5a4K3g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="/app.js"></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 class="col-md-6">
<form class="form-inline">
<div class="form-group">
<label for="name">Type your message here 👋</label>
<input type="text" id="content" class="form-control" placeholder="Your message here...">
</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>Greetings</th>
</tr>
</thead>
<tbody id="messages">
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
After that we need to create a Javascript file to makes possible the connection with our server. The code is very simple and I will comment just two functions.
var stompClient = null;
function setConnected(connected) {
$("#connect").prop("disabled", connected);
$("#disconnect").prop("disabled", !connected);
if (connected) {
$("#conversation").show();
}
else {
$("#conversation").hide();
}
$("#messages").html("");
}
function connect() {
var socket = new SockJS('http://localhost:8080/websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function () {
setConnected(true);
stompClient.subscribe('/topic/callback', function (message) {
showCallback(JSON.parse(message.body).content);
});
});
}
function disconnect() {
if (stompClient !== null) {
stompClient.disconnect();
}
setConnected(false);
}
function sendContent() {
stompClient.send("/app/message", {}, JSON.stringify({'content': $("#content").val()}));
}
function showCallback(message) {
$("#messages").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() { sendContent(); });
});
The connect function creates a instance of SockJs passing the URL of the Handshake that is /websocket. Then we connect to the server and inside the success callback we subscribe in the topic /topic/callback.
The sendContent function sends the message to the server. It’s good to keep in mind the prefix /app that was configured previously.
Conclusion
In this post I have shared with you my experience using Web Sockets and Spring boot. I hope you have found the answers for your questions.
I will be happy to answer any questions you may have and the repo with all code you can find here: joseMarciano
Very nice!!! 🚀