1. Обзор
В этом кратком руководстве мы рассмотрим, как использовать сеанс Spring с поддержкой MongoDB как с Spring Boot, так и без него.
Spring Session также может поддерживаться другими хранилищами, такими как Redis и JDBC .
2. Конфигурация весенней загрузки
Во-первых, давайте рассмотрим зависимости и конфигурацию, необходимые для Spring Boot. Для начала добавим в наш проект последние версии spring-session-data-mongodb
и spring-boot-starter-data-mongodb
:
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-mongodb</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
После этого, чтобы включить автоматическую настройку Spring Boot, нам нужно добавить тип хранилища Spring Session как mongodb
в application.properties
:
spring.session.store-type=mongodb
3. Конфигурация Spring без Spring Boot
Теперь давайте посмотрим на зависимости и конфигурацию, необходимые для хранения сеанса Spring в MongoDB без Spring Boot.
Как и в конфигурации Spring Boot, нам понадобится зависимость spring-session-data-mongodb
. Однако здесь мы будем использовать зависимость spring-data-mongodb
для доступа к нашей базе данных MongoDB:
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-mongodb</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
Наконец, давайте посмотрим, как настроить приложение:
@EnableMongoHttpSession
public class HttpSessionConfig {
@Bean
public JdkMongoSessionConverter jdkMongoSessionConverter() {
return new JdkMongoSessionConverter(Duration.ofMinutes(30));
}
}
Аннотация @EnableMongoHttpSession
включает конфигурацию, необходимую для хранения данных сеанса в MongoDB .
Также обратите внимание, что JdkMongoSessionConverter
отвечает за сериализацию и десериализацию данных сеанса.
4. Пример приложения
Давайте создадим приложение для тестирования конфигураций. Мы будем использовать Spring Boot, так как он быстрее и требует меньше настроек.
Мы начнем с создания контроллера для обработки запросов:
@RestController
public class SpringSessionMongoDBController {
@GetMapping("/")
public ResponseEntity<Integer> count(HttpSession session) {
Integer counter = (Integer) session.getAttribute("count");
if (counter == null) {
counter = 1;
} else {
counter++;
}
session.setAttribute("count", counter);
return ResponseEntity.ok(counter);
}
}
Как видно из этого примера, мы увеличиваем счетчик
при каждом обращении к конечной точке и сохраняем его значение в атрибуте сеанса с именем count
.
5. Тестирование приложения
Давайте протестируем приложение, чтобы увидеть, действительно ли мы можем хранить данные сеанса в MongoDB.
Для этого мы получим доступ к конечной точке и проверим полученный файл cookie. Это будет содержать идентификатор сеанса.
После этого мы запросим коллекцию MongoDB, чтобы получить данные сеанса, используя идентификатор сеанса:
@Test
public void
givenEndpointIsCalledTwiceAndResponseIsReturned_whenMongoDBIsQueriedForCount_thenCountMustBeSame() {
HttpEntity<String> response = restTemplate
.exchange("http://localhost:" + 8080, HttpMethod.GET, null, String.class);
HttpHeaders headers = response.getHeaders();
String set_cookie = headers.getFirst(HttpHeaders.SET_COOKIE);
Assert.assertEquals(response.getBody(),
repository.findById(getSessionId(set_cookie)).getAttribute("count").toString());
}
private String getSessionId(String cookie) {
return new String(Base64.getDecoder().decode(cookie.split(";")[0].split("=")[1]));
}
6. Как это работает?
Давайте посмотрим, что происходит за кулисами весенней сессии.
SessionRepositoryFilter отвечает
за большую часть работы:
- преобразует
HttpSession
вMongoSession
- проверяет наличие
файла cookie
и, если да, загружает данные сеанса из хранилища - сохраняет обновленные данные сеанса в хранилище
- проверяет валидность сеанса
Кроме того, SessionRepositoryFilter
создает файл cookie с именем SESSION
, который является HttpOnly и безопасным. Этот файл cookie содержит идентификатор сеанса, который представляет собой значение в кодировке Base64.
Чтобы настроить имя или свойства файла cookie, нам нужно создать bean-компонент Spring типа DefaultCookieSerializer.
Например, здесь мы отключаем свойство httponly
файла cookie:
@Bean
public DefaultCookieSerializer customCookieSerializer(){
DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
cookieSerializer.setUseHttpOnlyCookie(false);
return cookieSerializer;
}
7. Сведения о сеансе хранятся в MongoDB
Давайте запросим нашу коллекцию сеансов, используя следующую команду в нашей консоли MongoDB:
db.sessions.findOne()
В результате мы получим документ BSON , похожий на:
{
"_id" : "5d985be4-217c-472c-ae02-d6fca454662b",
"created" : ISODate("2019-05-14T16:45:41.021Z"),
"accessed" : ISODate("2019-05-14T17:18:59.118Z"),
"interval" : "PT30M",
"principal" : null,
"expireAt" : ISODate("2019-05-14T17:48:59.118Z"),
"attr" : BinData(0,"rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAUH2sHDFmDRAwACRgAKbG9hZEZhY3RvckkACXRocmVzaG9sZHhwP0AAAAAAAAx3CAAAABAAAAABdAAFY291bnRzcgARamF2YS5sYW5nLkludGVnZXIS4qCk94GHOAIAAUkABXZhbHVleHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhwAAAAC3g=")
}
_id — это UUID , который будет закодирован в Base64 DefaultCookieSerializer
и установлен в качестве значения в файле
cookie SESSION .
Также обратите внимание, что атрибут attr
содержит фактическое значение нашего счетчика.
``
8. Заключение
В этом руководстве мы рассмотрели Spring Session с поддержкой MongoDB — мощного инструмента для управления HTTP-сессиями в распределенной системе. Имея в виду эту цель, он может быть очень полезен при решении проблемы репликации сеансов между несколькими экземплярами приложения.
Как обычно, исходный код доступен на GitHub .