1. 概要

このクイックチュートリアルでは、SpringセッションJDBCを使用してセッション情報をデータベースに永続化する方法を学習します。

デモンストレーションの目的で、インメモリH2データベースを使用します。

2. 構成オプション

サンプルプロジェクトを作成する最も簡単で最速の方法は、 SpringBootを使用することです。 ただし、起動しない方法で設定する方法も示します。

したがって、セクション3と4の両方を完了する必要はありません。 SpringBootを使用してSpringSession を構成しているかどうかに応じて、1つ選択してください。

3. スプリングブート構成

まず、SpringSessionJDBCに必要な構成を見てみましょう。

3.1. Mavenの依存関係

まず、これらの依存関係をプロジェクトに追加する必要があります。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency> 
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.197</version>
    <scope>runtime</scope>
</dependency>

このアプリケーションはSpringBoot で実行され、親pom.xmlは各エントリのバージョンを提供します。 各依存関係の最新バージョンは、 spring-boot-starter-web spring-boot-starter-test、 spring-session-jdbcにあります。 、およびh2。

驚いたことに、リレーショナルデータベースに基づくSpring Sessionを有効にするために必要な唯一の構成プロパティは、 application.properties:にあります。

spring.session.store-type=jdbc

4. 標準のSpringConfig(Spring Bootなし)

また、SpringBootを使用せずにSpringセッションを統合および構成する方法も見てみましょう。

4.1. Mavenの依存関係

まず、 spring-session-jdbc を標準のSpringプロジェクトに追加する場合は、spring-session-jdbch2をに追加する必要があります。 pom.xml (前のセクションのスニペットの最後の2つの依存関係)。

4.2. Springセッション構成

次に、 Spring SessionJDBCの構成クラスを追加しましょう。

@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 Beanを明示的に定義する必要があります。以前の構成では、SpringBootがそれを行います。

上記により、 springSessionRepositoryFilterという名前のSpringBeanが、すべてのリクエストに対してサーブレットコンテナに登録されます。

5. シンプルなアプリ

次に、セッションの永続性を示す保存を行う単純なRESTAPIを見てみましょう。 。 

5.1. コントローラ

まず、 Controller クラスを追加して、HttpSessionに情報を格納および表示します。

@Controller
public class SpringSessionJdbcController {

    @GetMapping("/")
    public String index(Model model, HttpSession session) {
        List<String> 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<String> favoriteColors 
          = getFavColors(request.getSession());
        if (!StringUtils.isEmpty(color)) {
            favoriteColors.add(color);
            request.getSession().
              setAttribute("favoriteColors", favoriteColors);
        }
        return "redirect:/";
    }

    private List<String> getFavColors(HttpSession session) {
        List<String> favoriteColors = (List<String>) session
          .getAttribute("favoriteColors");
        
        if (favoriteColors == null) {
            favoriteColors = new ArrayList<>();
        }
        return favoriteColors;
    }
}

6. 実装のテスト

GETメソッドとPOSTメソッドを備えたAPIができたので、両方のメソッドを呼び出すテストを作成しましょう。

いずれの場合も、セッション情報がデータベースに保持されていることを表明できるはずです。 これを確認するために、セッションデータベースに直接クエリを実行します。

まず、設定を行いましょう。

@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<String> getSessionIdsFromDatabase() 
      throws SQLException {
 
        List<String> result = new ArrayList<>();
        ResultSet rs = getResultSet(
          "SELECT * FROM SPRING_SESSION");
        
        while (rs.next()) {
            result.add(rs.getString("SESSION_ID"));
        }
        return result;
    }

    private List<byte[]> getSessionAttributeBytesFromDb() 
      throws SQLException {
 
        List<byte[]> 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テーブルには1行しかありません。

最後に、お気に入りの色を指定してPOSTエンドポイントをテストします。

@Test
public void whenH2DbIsQueried_thenSessionAttributeIsRetrieved()
  throws Exception {
 
    MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
    map.add("color", "red");
    this.testRestTemplate.postForObject(
      "http://localhost:" + port + "/saveColor", map, String.class);
    List<byte[]> queryResponse = getSessionAttributeBytesFromDatabase();
    
    assertEquals(1, queryResponse.size());
    ObjectInput in = new ObjectInputStream(
      new ByteArrayInputStream(queryResponse.get(0)));
    List<String> obj = (List<String>) in.readObject();
    assertEquals("red", obj.get(0));
}

予想どおり、SPRING_SESSION_ATTRIBUTESテーブルはお気に入りの色を保持します。 Springはデータベースでセッション属性を永続化するときにオブジェクトのシリアル化を行うため、ATTRIBUTE_BYTESの内容をStringオブジェクトのリストに逆シリアル化する必要があることに注意してください。

7. それはどのように機能しますか?

コントローラを見ると、データベースがセッション情報を保持していることを示すものはありません。 すべての魔法は、application.propertiesに追加した1行で発生しています。

つまり、 spring.session.store-type = jdbcを指定すると、Spring Bootは、@EnableJdbcHttpSessionアノテーションを手動で追加するのと同等の構成をバックグラウンドで適用します。

これにより、 aSessionRepositoryFilterを実装するspringSessionRepositoryFilterという名前のSpringBeanが作成されます。

もう1つの重要なポイントは、フィルターがすべての HttpServletRequest をインターセプトし、それをSessionRepositoryRequestWrapperにラップすることです。

また、 commitSession メソッドを呼び出して、セッション情報を永続化します。

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を使用して認証情報を管理するには、この記事– SpringSessionのガイドを参照してください。

いつものように、ソースコードはGithubにあります。