Spring Boot Session + STOMP + Websocket + Javaconfig

author-imageBy Dhiraj, 21 December,2016   12K

In this post, we will be discussing about how to maintain spring session during websocket connection through HandshakeInterceptor.Doing so we can track user session during every websocket request and can utilize this session to track client activities from the server even after the server is connected through websocket protocol.Now let us look into the code how can we maintain spring session during websocket connection using Spring boot.

Background

As we know, before making a websocket connection to a server, client makes a handshake request as an upgrade request and this request is a HTTP request.Hence, to maintain a websocket session, we require to intercept this HTTP request and keep the session id somewhere from where it can be accessed everytime whenever a websocket request is made.Here we will be using STOMP header attributes to track the session.

Environment Setup

1. JDK 8 2. Spring Boot 3. Intellij Idea/ eclipse 4. Maven

Maven Dependencies

There is no any extra maven dependency is required for this case that we used in our previous post of Spring Websocket Integration Example without STOMP.Hence let us ignore it for time being.

Server Side

First of all let us configure our message broker.In WebSocketConfig.java we have defined our STOMP endpoint and message broker. The important thing to notice here is the configuration for handshakeInterceptor.So, whenever any websocket handshake request is received by the server,this class will come into picture.

WebSocketConfig.java
package com.developertack;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
	
	 @Override
	 public void configureMessageBroker(MessageBrokerRegistry config) {
	  config.enableSimpleBroker("/topic/", "/queue/");
	  config.setApplicationDestinationPrefixes("/app");
	 }
	 
	 @Override
	 public void registerStompEndpoints(StompEndpointRegistry registry) {
	  registry.addEndpoint("/greeting").addInterceptors(new HttpHandshakeInterceptor());
	 }
	
}
 Other Interesting Posts
Websocket spring Boot Integration Example
Spring 5 Features and Enhancements
Spring Security Password Encoding using Bcrypt Encoder
Spring Boot Security Redirect after Login with complete JavaConfig
Spring Security Hibernate Example with complete JavaConfig
Securing REST API with Spring Security Basic Authentication
Spring Security with Spring MVC Example Using Spring Boot
Spring JMS Activemq Integration with Spring Boot
Spring MVC Angularjs Integration with complete JavaConfig
Spring Hibernate Integration with complete JavaConfig
Spring Junit Integration with complete JavaConfig
Spring Ehcache Cacheable Example with complete javaConfig
Spring Boot Spring MVC Example
Spring Boot Thymeleaf Example

Now let us define the httpInterceptor.We have overriden beforeHandshake() to intercept the handshake request and set our custom attributes.We are setting our custom attribute sessionId with actual sessionId and this is the same key which we will be using later to track the session from our controller class.

HttpHandshakeInterceptor.java
package com.developertack;

import java.util.Map;

import javax.servlet.http.HttpSession;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

public class HttpHandshakeInterceptor implements HandshakeInterceptor {

	@Override
	public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
			Map attributes) throws Exception {
		if (request instanceof ServletServerHttpRequest) {
			ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
			HttpSession session = servletRequest.getServletRequest().getSession();
			attributes.put("sessionId", session.getId());
		}
		return true;
	}

	public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
			Exception ex) {
	}
}

Following is the listener class which will be executed whenever a STOMP client subscribes for a queue or topic. We are also validating the sessionId which we created during handshake.

SubscribeEventListener.java
package com.developertack;

import org.springframework.context.ApplicationListener;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.messaging.SessionSubscribeEvent;

@Component
public class SubscribeEventListener implements ApplicationListener {

	@Override
	public void onApplicationEvent(SessionSubscribeEvent sessionSubscribeEvent) {
		StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(sessionSubscribeEvent.getMessage());
		System.out.println(headerAccessor.getSessionAttributes().get("sessionId").toString());
	}
}

Now let us define the controller which will intercept the message coming from the stomp client and validate the session using custom attribute sessionId which we set during handshake.This attribute can be accessed from the headerAccessor.

package com.developertack.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.stereotype.Controller;

@Controller
public class WebSocketController {
	
	@Autowired
	private SimpMessageSendingOperations messagingTemplate;
	
	@MessageMapping("/message")
    public void processMessageFromClient(@Payload String message, SimpMessageHeaderAccessor  headerAccessor) throws Exception {
		String sessionId = headerAccessor.getSessionAttributes().get("sessionId").toString();
		System.out.println(sessionId);
		headerAccessor.setSessionId(sessionId);
		messagingTemplate.convertAndSend("/topic/reply", new Gson().fromJson(message, Map.class).get("name"));
      
    }

}

Run Application

1. Run Application.java as a java application.

2. Open the browser and hit the URL - http:localhost:8080.

3. Click on connect button to make the socket connection.

4. Enter your name and click send.Following is the result.

web-socket-example

On the server side you can check the console and find the sessionIds are same.

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

Further Reading on Spring Boot

1. Spring Boot Angular Websocket

2. Spring Boot Websocket Integration Example

3. Spring Websocket Integration Example Without Stomp

4. Spring Ehcache Cacheable Example Javaconfig

5. Spring Jms Activemq Integration Example

If You Appreciate What We Do Here On Devglan, You Should Consider: