The background,

The author saw the Session sharing problem mentioned by the netizens in the discussion group, so I consulted the documents privately and finally locked Spring Session to solve the problem and recorded it here.

Second, the introduction

Spring Session provides a set of apis to manage user Session information.

Use Spring Session instead of the HttpSession implementation in the project container. In addition, Spring Session provides the following features:

1) Session clustering: Spring Session makes it very easy to support clustered sessions. With Spring Session we don’t have to bind the project to a specific application for a cluster of sessions.

2) Multi-browser sessions: Spring Session provides a solution for managing multiple sessions in a single browser.

3) RESTful APIs: Spring Session allows Session ids to be added to request headers to implement RESTful APIs.

This article introduces the function of the first point.

The schematic diagram is as follows:

After the browser initiates the request, Tomcat (the load balancing assignment points to the specific Tomcat) obtains the session ID in the request and finds the corresponding Session object in the Session storage container.

For the container of Session storage, Spring Session provides a number of scenarios:

1) HttpSession with Redis

2) HttpSession with Pivotal GemFire

3) HttpSession with JDBC

4) HttpSession with Mongo

5) HttpSession with Hazelcast

Three, implementation,

JDK: 1.8 Container: Tomcat 8 Session Storage container: Redis 3.2.0

This test uses the HttpSession with Redis scheme. For the convenience of the test, the author deployed the project into two Tomcat servers on the same VIRTUAL machine and started the project using ports 8080 and 8081.

3.1 Adding a Dependency

<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> < version > 1.8.9. RELEASE < / version > < / dependency > < the dependency > < groupId > redis. Clients < / groupId > < artifactId > jedis < / artifactId > < version > 2.9.0 < / version > < / dependency > < the dependency > < the groupId > org. Springframework. Session < / groupId > < artifactId > spring - the session < / artifactId > < version > 1.3.1. The RELEASE < / version > </dependency>Copy the code

The Related Jars such as Spring are omitted here.

3.2 applicationContext – session. The XML file

<context:annotation-config/> <! - redis connection pool - > < bean id = "jedisPoolConfig" class = "redis. Clients. Jedis. JedisPoolConfig" > < property name = "maxTotal" value="20"></property> <property name="maxIdle" value="1"></property> </bean> <! <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy"> <property Value ="192.168.2.11"/> <property name="port" value="6379"/> <property name="timeout" value="5000"/> <property name="password" value=""/> <property name="usePool" value="true"/> <property name="poolConfig" ref="jedisPoolConfig"/> </bean> <! - spring session configuration - > < bean id = "redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"> <property name="maxInactiveIntervalInSeconds" value="600"/> </bean>Copy the code

ApplicationContext – session. In XML configuration makes the project started, Spring will create a Bean named springSessionRepositoryFilter (filter), The Bean is responsible for replacing the implementation of HttpSession with Spring Session. Spring Session relies on Redis to store Session information on the client.

3.3 web. The XML file

<filter>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSessionRepositoryFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>Copy the code

Each client request after DelegatingFilterProxy DelegatingFilterProxy will find in the Spring container called springSessionRepositoryFilter Bean, It is converted to a Filter to Filter the requested data.

3.4 Back-end code

@Controller public class LoginController { @RequestMapping("login") public String login(String userName, String password, it request) {/ / login for the first time the if (" admin ". The equals (userName) && "admin" equals (password)) { HttpSession session = request.getSession(); session.setAttribute("userName", userName); return "manageUI"; } // If already logged in, access the method from another Tomcat, If ("".equals(userName) && "".equals(password)) {return "manageUI"; } return "redirect:/index.jsp"; } @RequestMapping("logout") public String logout(HttpSession session) { session.removeAttribute("userName"); session.removeAttribute("url"); return "redirect:/index.jsp"; }}Copy the code

3.5 Front-end Code

The index. The JSP page

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <! DOCTYPE html> <html lang="zh"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta  name="viewport" content="width=device-width, Initial =1"> <meta name="description" content=""> <meta name="author" content=""> <title href="/resources/css/bootstrap.min.css" rel="stylesheet"> <style> html { background: url("/resources/images/bg.png") no-repeat center center; } label { color: #fff; } .container { position:absolute; top:50%; left:50%; margin-top: -115px; margin-left: -250px; width: 500px; height:230px; padding:50px; border: 2px solid #eee; border-radius: 5px; box-shadow:5px 5px 16px #000; } </style> </head> <body> <div class="container"> <form class="form-horizontal" role="form" action="/login" Method ="post"> <div class="form-group"> <label for="inputEmail3" class=" col-SM-2 control-label"> User name </label> <div Class ="col-sm-10"> <input type="text" class="form-control" name="userName" placeholder=" userName" > </div> </div> <div Class ="form-group"> <label for="inputPassword3" class=" col-SM-2 control-label"> password </label> <div class=" col-SM-10 "> <input Type ="password" class="form-control" name="password" placeholder=" password" > </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-primary" style="width: 100% "> log in < / button > < / div > < / div > < / form > < / div > < / body > < / HTML >Copy the code

ManageUI. JSP page

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <! DOCTYPE html> <html lang="zh"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta  name="viewport" content="width=device-width, Initial-scale =1"> <meta name="description" content=""> <meta name="author" content="" href="/resources/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container"> <div class="jumbotron"> <h3> <h3> <h3> ${sessionscope. userName} (session domain data) </h3> <p><a class=" BTN btn-lg btn-success" href="/logout" role="button"> logout </a></p> </div> </div> </body> </html>Copy the code

Note: the page of the 8081 project needs to be changed to “page with port 8081”.

Four, presentations,

Expected effect:

1) First access the project of port 8080 and log in, jump to the management interface and display the saved information.

2) When accessing the page of port 8081 project in the same browser, you do not need to enter the account password and click the login button directly to jump to the management interface. If the session is shared, you can view the information stored in the session by port 8080 project in the admin interface. Otherwise, vice versa.

The demo diagram is as follows:

Using Spring Session is really convenient and simple, we don’t need additional learning apis, just configuration to implement the functionality.

5. Reference documents

Download the source code

session-share