1. Обзор
В этом кратком руководстве мы узнаем, как использовать JDBC весенней сессии для сохранения информации о сеансе в базе данных.
Для демонстрационных целей мы будем использовать базу данных H2 в памяти.
2. Параметры Конфигурации
Самый простой и быстрый способ создать наш пример проекта-это использовать Spring Boot . Тем не менее, мы также покажем способ настройки без загрузки.
Следовательно, вам не нужно заполнять оба раздела 3 и 4. Просто выберите один из них в зависимости от того, используем ли мы Spring Boot для настройки Spring Session .
3. Конфигурация Пружинной загрузки
Во-первых, давайте рассмотрим необходимую конфигурацию для весенней сессии JDBC.
3.1. Зависимости Maven
Во-первых, нам нужно добавить эти зависимости в наш проект:
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.session spring-session-jdbc com.h2database h2 1.4.197 runtime
Наше приложение работает с Spring Boot и родительским pom.xml предоставляет версии для каждой записи. Последнюю версию каждой зависимости можно найти здесь: spring-boot-starter-web , spring-boot-starter-test, spring-session-jdbc и h2.
Удивительно, но единственное свойство конфигурации, которое нам нужно для включения весенней сессии, поддерживаемой реляционной базой данных , находится в application.properties :
spring.session.store-type=jdbc
4. Стандартная конфигурация пружины (без пружинной загрузки)
Давайте также рассмотрим интеграцию и настройку spring-сессии без загрузки Spring – только с помощью обычной Spring.
4.1. Зависимости Maven
Во-первых, если мы добавляем spring-session-jdbc в стандартный проект Spring, нам нужно будет добавить spring-session-jdbc и h2 в наш pom.xml (последние две зависимости из фрагмента в предыдущем разделе).
4.2. Конфигурация Весенней сессии
Теперь давайте добавим класс конфигурации для Весенней сессии JDBC :
@Configuration @EnableJdbcHttpSession public class Config extends AbstractHttpSessionApplicationInitializer { @Bean public EmbeddedDatabase dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("org/springframework/session/jdbc/schema-h2.sql").build(); } @Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }
Как мы видим, различия минимальны. Теперь мы должны явно определить нашу EmbeddedDatabase и PlatformTransactionManager beans – Spring Boot делает это за нас в предыдущей конфигурации.
Вышеизложенное гарантирует, что Spring bean по имени springSessionRepositoryFilter регистрируется в нашем контейнере сервлета для каждого запроса.
5. Простое Приложение
Двигаясь дальше, давайте рассмотрим простой REST API, который сохраняет сохраняемость сеанса .
5.1. Контроллер
Во-первых, давайте добавим класс Controller для хранения и отображения информации в HttpSession :
@Controller public class SpringSessionJdbcController { @GetMapping("/") public String index(Model model, HttpSession session) { ListfavoriteColors = getFavColors(session); model.addAttribute("favoriteColors", favoriteColors); model.addAttribute("sessionId", session.getId()); return "index"; } @PostMapping("/saveColor") public String saveMessage (@RequestParam("color") String color, HttpServletRequest request) { List favoriteColors = getFavColors(request.getSession()); if (!StringUtils.isEmpty(color)) { favoriteColors.add(color); request.getSession(). setAttribute("favoriteColors", favoriteColors); } return "redirect:/"; } private List getFavColors(HttpSession session) { List favoriteColors = (List ) session .getAttribute("favoriteColors"); if (favoriteColors == null) { favoriteColors = new ArrayList<>(); } return favoriteColors; } }
6. Тестирование Нашей Реализации
Теперь, когда у нас есть API с методом GET и POST, давайте напишем тесты для вызова обоих методов.
В каждом случае мы должны иметь возможность утверждать, что информация о сеансе сохраняется в базе данных. Чтобы убедиться в этом, мы запросим базу данных сеансов напрямую.
Давайте сначала все устроим:
@RunWith(SpringRunner.class) @SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class SpringSessionJdbcApplicationTests { @LocalServerPort private int port; @Autowired private TestRestTemplate testRestTemplate; private ListgetSessionIdsFromDatabase() throws SQLException { List result = new ArrayList<>(); ResultSet rs = getResultSet( "SELECT * FROM SPRING_SESSION"); while (rs.next()) { result.add(rs.getString("SESSION_ID")); } return result; } private List getSessionAttributeBytesFromDb() throws SQLException { List result = new ArrayList<>(); ResultSet rs = getResultSet( "SELECT * FROM SPRING_SESSION_ATTRIBUTES"); while (rs.next()) { result.add(rs.getBytes("ATTRIBUTE_BYTES")); } return result; } private ResultSet getResultSet(String sql) throws SQLException { Connection conn = DriverManager .getConnection("jdbc:h2:mem:testdb", "sa", ""); Statement stat = conn.createStatement(); return stat.executeQuery(sql); } }
Обратите внимание на использование @FixMethodOrder(MethodSorters.NAME_ASCENDING) для управления порядком выполнения тестового набора . Подробнее об этом читайте здесь .
Давайте начнем с утверждения, что таблицы сеансов в базе данных пусты:
@Test public void whenH2DbIsQueried_thenSessionInfoIsEmpty() throws SQLException { assertEquals( 0, getSessionIdsFromDatabase().size()); assertEquals( 0, getSessionAttributeBytesFromDatabase().size()); }
Далее мы тестируем конечную точку GET:
@Test public void whenH2DbIsQueried_thenOneSessionIsCreated() throws SQLException { assertThat(this.testRestTemplate.getForObject( "http://localhost:" + port + "/", String.class)) .isNotEmpty(); assertEquals(1, getSessionIdsFromDatabase().size()); }
При первом вызове API создается сеанс, который сохраняется в базе данных. Как мы видим, на данный момент в таблице SPRING_SESSION есть только одна строка.
Наконец, мы тестируем конечную точку POST, предоставляя любимый цвет:
@Test public void whenH2DbIsQueried_thenSessionAttributeIsRetrieved() throws Exception { MultiValueMapmap = new LinkedMultiValueMap<>(); map.add("color", "red"); this.testRestTemplate.postForObject( "http://localhost:" + port + "/saveColor", map, String.class); List queryResponse = getSessionAttributeBytesFromDatabase(); assertEquals(1, queryResponse.size()); ObjectInput in = new ObjectInputStream( new ByteArrayInputStream(queryResponse.get(0))); List obj = (List ) in.readObject(); assertEquals("red", obj.get(0)); }
Как и ожидалось, SPRING_SESSION_ATTRIBUTES таблица сохраняет любимый цвет. Обратите внимание, что мы должны десериализовать содержимое ATTRIBUTE_BYTES в список String объектов, так как Spring выполняет сериализацию объектов при сохранении атрибутов сеанса в базе данных.
7. Как Это Работает?
Глядя на контроллер, нет никаких признаков того, что база данных сохраняет информацию о сеансе. Все волшебство происходит в одной строке, которую мы добавили в application.properties .
То есть, когда мы указываем spring.session.store-type=jdbc, за кулисами Spring Boot применит конфигурацию, эквивалентную ручному добавлению @EnableJdbcHttpSession аннотации .
Это создает компонент Spring с именем s springsessionrepositoryfilter , который реализует SessionRepositoryFilter .
Еще одним ключевым моментом является то, что фильтр перехватывает каждый HttpServletRequest и обертывает его в SessionRepositoryRequestWrapper .
Он также вызывает метод commit Session для сохранения информации о сеансе.
8. Информация о сеансе, хранящаяся в базе данных H2
Добавив следующие свойства, мы могли бы взглянуть на таблицы, в которых информация о сеансе хранится из URL – адреса – http://localhost:8080/h2-console/ :
spring.h2.console.enabled=true spring.h2.console.path=/h2-console
9. Заключение
Spring Session-это мощный инструмент для управления HTTP-сеансами в архитектуре распределенной системы. Spring заботится о тяжелом подъеме для простых случаев использования, предоставляя предопределенную схему с минимальной конфигурацией. В то же время он обеспечивает гибкость при разработке нашего дизайна того, как мы хотим хранить информацию о сеансе.
Наконец, для управления информацией аутентификации с помощью Spring Session вы можете обратиться к этой статье – Руководство по Spring Session .
Как всегда, вы можете найти исходный код на Github .