Рубрики
Без рубрики

Весенняя сессия с JDBC

Узнайте, как легко сохранить информацию о сеансе в базе данных с помощью Spring Session JDBC

Автор оригинала: baeldung.

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) {
        List favoriteColors = 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 List getSessionIdsFromDatabase() 
      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 {
 
    MultiValueMap map = 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
весенняя сессия jdbc
весенняя сессия jdbc

9. Заключение

Spring Session-это мощный инструмент для управления HTTP-сеансами в архитектуре распределенной системы. Spring заботится о тяжелом подъеме для простых случаев использования, предоставляя предопределенную схему с минимальной конфигурацией. В то же время он обеспечивает гибкость при разработке нашего дизайна того, как мы хотим хранить информацию о сеансе.

Наконец, для управления информацией аутентификации с помощью Spring Session вы можете обратиться к этой статье – Руководство по Spring Session .

Как всегда, вы можете найти исходный код на Github .