Spring Boot + WebSocket example without STOMP and SockJs

By Dhiraj Ray, 05 November,2016   | Last updated on: 20 February,2017

You can find many examples available on the web for spring websocket integration but most of them are using some messaging protocol like STOMP. Though Spring provides STOMP support out of the box but use of any messaging protocol to connect to websocket is not mandatory. You can use raw websocket by defining your own messaging protocol to connect to spring websocket using TextWebSocketHandler. In this post we will be creating a websocket connection using Spring but without STOMP and SockJs.

If you are looking for spring websocket example with STOMP and Spring Security, then visit here spring websocket example with STOMP.

What is STOMP

STOMP stands for Streaming Text Oriented Messaging Protocol. As per wiki, STOMP is a simple text-based protocol, designed for working with message-oriented middleware (MOM). It provides an interoperable wire format that allows STOMP clients to talk with any message broker supporting the protocol.

This means when we do not have STOMP as a client, the message sent lacks of information to make Spring route it to a specific message handler method. So, if we could create a mechanism that can make Spring to route to a specific message handler then probably we can make websocket connection without STOMP.

Custom WebSocketHandler

We concluded that if we do not want to use STOMP, then we have to define our custom message protocol handler that should handle all the messages coming from any websocket client. Before defining any custom message handler class, we need to identify what format of message our handler class expect from the client. It can be either XML or Json or of any other format.

In this example we assume that the websocket client will be communicating with the server in JSON. Hence our handler will be a JSON message handler and we can define this in Spring by extending TextWebSocketHandler.java

TextWebSocketHandler

TextWebSocketHandler is a class in Spring library that extends AbstractWebSockethandler class and primarily meant for handling only text messages. So, if you are expecting any binary messages from your websocket client then defining your custom handler class by extending TextWebSocketHandler is of no use as binary messages will be rejected with CloseStatus.NOT_ACCEPTABLE.

Implementation of Spring Websocket without STOMP

While coming to the code implementation, we will be creating a simple web app using Spring websocket where message transfer between the client and server will happen via websocket without STOMP. Let us start by defining our project structure.

Project Structure

spring-boot-websocket-without-stomp-project-structure

Maven Dependency

pom.xml
<properties> <tomcat.version>8.0.3</tomcat.version> </properties> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.3.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> </dependency> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </dependencies>

Server Side Implementation

Let us start by defining Applicaton.java.

@SpringBootApplication: This is a convenience annotation that is equivalent to declaring @Configuration,@EnableAutoConfiguration and @ComponentScan.

Application.java
package com.devglan.config; import org.springframework.boot.SpringApplication; import org.springframework.boot.context.web.SpringBootServletInitializer; @SpringBootApplication public class Application extends SpringBootServletInitializer { private static Class applicationClass = Application.class; public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

Overriding TextWebSocketHandler

Now let us define our custom handler class by extending TextWebSocketHandler.java that will override the protocol to handle the text message. Our handler will be capable of handling Json message. This class records all the session once any websocket connection is established and broadcasts the message to all the sessions once any message is received.

Instead of broadcasting message to all the clients, you can also configure to send message to a particular session. This configuration is also explained in coming section.

SocketHandler.class
package com.devglan.config; import org.springframework.stereotype.Component; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; @Component public class SocketHandler extends TextWebSocketHandler { List sessions = new CopyOnWriteArrayList<>(); @Override public void handleTextMessage(WebSocketSession session, TextMessage message) throws InterruptedException, IOException { for(WebSocketSession webSocketSession : sessions) { Map value = new Gson().fromJson(message.getPayload(), Map.class); webSocketSession.sendMessage(new TextMessage("Hello " + value.get("name") + " !")); } } @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { //the messages will be broadcasted to all users. sessions.add(session); } }

Spring Web Socket Configurations

Now let us define our websocket configurations. The below configuration will register websocket handler at /name and define our custom handler class that will handle all the messages from the websocket client.

WebSocketConfig.class
package com.devglan.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new SocketHandler(), "/name"); } }

This is it for server side. Now let's jump to client side code.

app.js

Here we have defined 3 methods each for creating websocket connection when user clicks on connect button, sending message to the server once send button is clicked and another for listening the server response that will come from the server.

function connect() { ws = new WebSocket('ws://localhost:8080/name'); ws.onmessage = function(data){ showGreeting(data.data); } setConnected(true); } function disconnect() { if (ws != null) { ws.close(); } setConnected(false); console.log("Disconnected"); } function sendName() { ws.send($("#name").val()); } function showGreeting(message) { $("#greetings").append(" " + message + ""); }

Run Application

1. Run Application.java as a java application and the main method will execute.

2. In the browser make request at http:localhost:8080.

3. Create websocket connection by clicking connect button and enter the name and click on send.

4. The handler class at server side will handle the message and return the greeting message as a response which will be shown in the browser as below:

web-socket-example

Sending Message to Single Session

Above implementation will broadcast message to all the sessions and hence all the client will receive the messaage at a time. To send message to a single client we need to tweak our Sockethandler.java as below. SocketHandler.java

package com.devglan.config; import org.springframework.stereotype.Component; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; @Component public class SocketHandler extends TextWebSocketHandler { List sessions = new CopyOnWriteArrayList<>(); @Override public void handleTextMessage(WebSocketSession session, TextMessage message) throws InterruptedException, IOException { Map value = new Gson().fromJson(message.getPayload(), Map.class); /*for(WebSocketSession webSocketSession : sessions) { Map value = new Gson().fromJson(message.getPayload(), Map.class); webSocketSession.sendMessage(new TextMessage("Hello " + value.get("name") + " !")); }*/ session.sendMessage(new TextMessage("Hello " + value.get("name") + " !")); } @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { //the messages will be broadcasted to all users. sessions.add(session); } }

This change in SocketHandler.java will ensure that the message is sent to a single session.

Conclusion

I hope this article served you that you were looking for. If you have anything that you want to add or share then please share it below in the comment section.

Download the source

References

Spring Websocket Reference

Getting started with STOMP

Spring Boot References

Suggest more topics in suggestion section or write your own article and share with your colleagues.

Is this page helpful to you? Please give us your feedback below. We would love to hear your thoughts on these articles, it will help us improve further our learning process.

Further Reading: