Spring Session реализует совместное использование сеансов кластера Tomcat.

задняя часть

1. Предпосылки

Автор увидел проблему совместного использования сеанса, упомянутую пользователями сети в группе обсуждения, поэтому я проверил документ в частном порядке и, наконец, заблокировал использование Spring Session для решения проблемы и записал его здесь.

2. Введение

Spring Session предоставляет набор API для управления информацией о сеансе пользователя.

Использование Spring Session может заменить реализацию HttpSession в контейнере проекта. Кроме того, Spring Session также предоставляет следующие функции:

1) Кластеризация сеансов: Spring Session упрощает поддержку кластеризованных сеансов. С Spring Session нам не нужно привязывать проекты к конкретным приложениям для сеансов кластеризации.

2) Мультибраузерные сеансы: Spring Session предоставляет решение для управления несколькими сеансами в одном браузере.

3) RESTful API: Spring Session позволяет добавить идентификатор сеанса в заголовок запроса для реализации RESTful API.

В этой статье представлена ​​функция первой точки.

Схематическая диаграмма выглядит следующим образом:

image

После того, как браузер инициирует запрос, tomcat (указанный распределением балансировки нагрузки на конкретный tomcat) получает идентификатор сеанса в запросе и находит соответствующий объект Session в контейнере хранилища сеансов.

Для контейнера хранилища сеансов Spring Session предоставляет множество решений:

1) HttpSession with Redis

2) HttpSession with Pivotal GemFire

3) HttpSession with JDBC

4) HttpSession with Mongo

5) HttpSession with Hazelcast

3. Реализация

JDK: 1.8
Контейнер: Томкэт 8
Контейнер хранилища сеансов: Redis 3.2.0

В этом тесте используется решение HttpSession with Redis.Для удобства тестирования автор развертывает проект на двух котах на одной виртуальной машине и использует для запуска порты 8080 и 8081.

3.1 Добавить зависимости

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>1.8.9.RELEASE</version>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session</artifactId>
    <version>1.3.1.RELEASE</version>
</dependency>

Связанные банки, такие как Spring, здесь опущены.

3.2 файл applicationContext-session.xml

<context:annotation-config/>
    
<!-- redis 连接池 -->
  <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxTotal" value="20"></property>
    <property name="maxIdle" value="1"></property>
  </bean>
  
  <!-- redis 连接工厂 -->
  <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
  destroy-method="destroy">
    <property name="hostName" 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 配置 -->
  <bean id="redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
    <property name="maxInactiveIntervalInSeconds" value="600"/>
  </bean>

Конфигурация в applicationContext-session.xml заставляет Spring создавать bean-компонент (фильтр) с именем springSessionRepositoryFilter при запуске проекта, и bean-компонент отвечает за замену реализации HttpSession на Spring Session . Spring Session использует Redis для хранения информации о сеансе на стороне клиента.

3.3 файл web.xml

<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>

После того, как каждый клиентский запрос проходит через DelegatingFilterProxy, DelegatingFilterProxy будет искать bean-компонент с именем springSessionRepositoryFilter в контейнере Spring и преобразовывать его в фильтр для фильтрации данных запроса.

3.4 Внутренний код

@Controller
public class LoginController {
    @RequestMapping("login")
    public String login(String userName, String password,HttpServletRequest request) {
        // 首次登录
        if ("admin".equals(userName) && "admin".equals(password)) {
            
            HttpSession session = request.getSession();
            session.setAttribute("userName", userName);
            
            return "manageUI";
        }
        
        // 如果已经登录过,从另一个 tomcat 访问该方法,跳转到 manageUI 页面可以查看 session 信息
        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";
    }
    
}

3.5 Интерфейсный код

страница index.jsp

<%@ 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="">
    <title>登陆界面</title>
    <link 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">用户名</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" name="userName" placeholder="用户名">
                </div>
            </div>
            <div class="form-group">
                <label for="inputPassword3" class="col-sm-2 control-label">密码</label>
                <div class="col-sm-10">
                    <input type="password" class="form-control" name="password" placeholder="密码">
                </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%">登陆</button>
                </div>
            </div>
        </form>
    </div>
</body>
</html>

страница manageUI.jsp

<%@ 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="">
    <title>管理界面</title>
    <link href="/resources/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
      <div class="jumbotron">
        <h3>端口为 8080 的页面</h3>
        <h3>用户名:${sessionScope.userName}(session 域数据)</h3>
        <p><a class="btn btn-lg btn-success" href="/logout" role="button">注销</a></p>
      </div>
    </div>
</body>
</html>

Примечание. Страницу проекта 8081 необходимо изменить на «страницу с портом 8081».

4. Демонстрация

ожидаемый результат:

1) Сначала войдите в проект через порт 8080 и войдите в систему, перейдите к интерфейсу управления и отобразите сохраненную информацию.

2) Посетите страницу проекта порта 8081 в том же браузере, нажмите кнопку входа в систему, не вводя пароль учетной записи, и он перейдет непосредственно к интерфейсу управления. Если сеанс является общим, вы можете просмотреть информацию, сохраненную в сеансе проектом порта 8080, в интерфейсе управления. Иначе наоборот.

Демонстрационная схема выглядит следующим образом:

image

Использование Spring Session действительно удобно и просто, нам не нужно дополнительно изучать API, нам нужно только настроить функцию.

5. Справочные документы

6. Загрузка исходного кода

session-share