Spring 5でできることは?4からの変更点や互換性について解説
Spring Sessionは、セッション情報をRedisやRDBMS、Hazelcastに保存できるので、クラスター環境でも簡単にセッション情報を管理できます。
「Spring Sessionの使い所は?」
「Spring Sessionの実装方法は?」
といった疑問に対して、本記事ではSpring Sessionの解説から使い方までを初級者エンジニア向けに詳しく解説していきます。
※本記事で紹介するサンプルコードは、Java18で動作確認しています。
1.Spring Sessionとは?
Spring Sessionは、Springプロジェクトのひとつで、セッションを管理するAPIと実装を提供します。セッションとは、Webシステムにおいて「サーバー内に情報を保存し、異なるページ間で共有」する仕組みのことです。Spring Sessionを利用すると簡単にセッション管理ができます。
①Spring Sessionの特徴
Spring Sessionの特徴は、以下の通りです。
・複数コンピューターで構築されたWebシステムでもセッション管理が可能
・ひとつのブラウザで複数のセッション管理が可能
・RESTful APIで動作するようにセッションIDをHTTPヘッダーで提供可能
・WebSocketメッセージの受信時にHttpSessionの維持が可能
②Spring Sessionの使い所
Spring Sessionは、インメモリデータストアやRDBMSなどでセッション情報を管理できます。
通常、セッション情報はアプリケーションサーバーで管理されますが、クラスター化されたシステム構成で運用する場合、複数サーバー間でセッション情報を同期する必要があり、設定が複雑になります。
そのようなときSpring Sessionを使用すると、アプリケーションサーバー以外でセッション情報を管理できるので、クラスター化システムでのセッション管理は、Spring Sessionを使うのがおすすめです。
2.Spring Sessionのモジュール
ここでは、Spring Sessionのモジュールを説明します。
①Spring Session Core
Spring Session Coreは、Spring Sessionのコア機能とAPIを提供します。
②Spring Session Data Redis
Spring Session Data Redisは、Redisにセッション情報を保存するために、SessionRepositoryの実装クラスと、関連する設定を提供します。
Redisとは、オープンソースのメモリ内key-valueデータストアのことです。
③Spring Session JDBC
Spring Session JDBCは、セッション情報をリレーショナルデータベースに保存するために、SessionRepository実装クラスと、関連する設定を提供します。
JDBCとは、Javaからリレーショナルデータベースに接続するための標準Java APIです。
④Spring Session Hazelcast
Spring Session Hazelcastは、Hazelcastをセッションの保存場所にするSessionRepository実装クラスと、関連する設定を提供します。
Hazelcastとは、オープンソースの分散型インメモリデータグリッドプラットフォームで、分散データ構造、分散クエリなど、さまざまな機能があります。
3.Spring Sessionの使い方
実際に、Spring Sessionを使ってみましょう。ここでは、セッション情報をPostgreSQLに保存する方法を紹介します。
①事前準備
まずは、PostgreSQLにデータベースを作成しましょう。今回は、”postgres”というデータベースを作成し、セッション情報保持用のテーブルをスクリプトから作成します。
下記サイトからスクリプトをダウンロード・実行し、テーブルを作成します。
下図のようになると、データベース作成は成功です。
②プロジェクトの作成
今回は、STSを使ってプロジェクトを作成していきます。
使用するライブラリ
今回使用するライブラリは、下図の通りです。
プロジェクト構成
プロジェクト構成は、下図のような構成にしています。
プロパティ設定
“Application.properties”に、データベース接続情報の設定を記述します。
spring.jpa.database=POSTGRESQL
spring.session.store-type=jdbc
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.datasource.driver-class-name=org.postgresql.Driver
spring.session.jdbc.initialize-schema=embedded
spring.session.jdbc.table-name=SPRING_SESSION
server.servlet.session.timeout=30m
今回は、PostgreSQLを使用するので、spring.jpa.databaseに”POSTGRESQL”と指定します。
Spring.datasource.urlには、JDBCでの接続URLを設定しましょう。今回のサンプルコードでは、PostgreSQLの標準的なポート番号である”5432”を指定し、DB名を先ほど作成した”postgres”を指定します。
Spring.datasource.usernameに、データベースへの接続ユーザー、Spring.datasource.passwordにはパスワードを設定します。
上記はサンプルなので、ご自身の環境に合わせて適宜変更してください。
pom.xmlの編集
Spring Sessionを使用する前に、依存関係を更新する必要があります。Mavenを使用する場合、次の依存関係を追加してください。
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-jdbc</artifactId>
</dependency>
③セッションを取得する
以下のように、Controllerクラス、エンティティクラス、htmlファイルを作成します。
Controllerクラス
package com.example.demo.controller;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import com.example.demo.model.User;
@Controller
//セッションに保存する情報は@SessionAttributesアノテーションで指定する
@SessionAttributes(types = User.class)
@RequestMapping("/")
public class SessionController {
//セッションに保存するオブジェクトの本体は、メソッドに@ModelAttributeアノテーションを付けて作成する
@ModelAttribute("user")
public User user() {
return new User();
}
@RequestMapping("login")
public String login(@ModelAttribute User user,HttpSession httpSession) {
Integer counter = user.getLoginCount();
user.setLoginCount(++counter);
user.setUserID(httpSession.getId());
user.setUserName("Suzuki Ichiro");
return "index";
}
}
このサンプルプログラムでは、Controllerクラスはひとつなので、@SessionAttributeを使用しました。
Userクラスをセッションで保存するように指定しています。登録したオブジェクトは、@ModelAttributeを付与した引数から参照できます。
エンティティクラス
エンティティクラスを以下のように記述します。
package com.example.demo.model;
import java.io.Serializable;
import org.springframework.stereotype.Component;
import lombok.Data;
@Data
@Component
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private String UserID;
private String UserName;
private int LoginCount;
}
index.html
画面表示するhtmlファイルを以下のように記述しています。
user.getUserID、user.getUserName、user.getLoginCountで、セッション情報から値を取得しています。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<form >
<h3>Session Id</h3>
<p th:text="${user.getUserID}"/>
<h3>ユーザー名</h3>
<p th:text="${user.getUserName}"/>
<h3>ログイン回数</h3>
<p th:text="${user.getLoginCount}" />
<p>
<input type="submit" name="login" formaction="/login" value="ログイン" />
</p>
</form>
</body>
</html>
このサンプルコードは、”ログイン”ボタンをクリックするごとに、セッション情報からログイン回数を取得し、カウントアップするようになっています。
Spring Bootアプリケーションの実行
コーディング完成後、Spring Bootアプリケーションを実行し、ブラウザで以下のURLを開きます。
Web画面が正しく表示されると、セッション情報がPostgreSQLに保存されます。
④セッションを破棄する
セッション情報を破棄する場合は、SessionStatusインターフェースを引数で受け取り、setCompleteメソッドを呼び出します。
先ほどのControllerクラスに、下記メソッドを追記します。
@RequestMapping("reset")
public String reset(@ModelAttribute User user, HttpServletRequest request,HttpSession httpSession,SessionStatus sessionStatus) {
//セッション情報を破棄
httpSession.removeAttribute("user");
httpSession.invalidate();
sessionStatus.setComplete();
user.setUserID(httpSession.getId());
user.setLoginCount(0);
return "index";
}
また、index.htmlにも、下記コードを追記し、アプリケーションを実行してみましょう。
<input type="submit" name="reset" formaction="/reset" value="リセット" />
“リセット”ボタンクリック前のPostgreSQLのspring_sessionテーブルは以下のようになっています。
”リセット”ボタンをクリック後、PostgreSQLのspring_sessionテーブルは、以下のようにレコードが削除されるので、セッションが破棄されたことがわかりますね。
⑤有効期限を設定する
セッション情報の有効期限は、デフォルトでは30分となっています。この時間を変更するには、application.propertiesに以下のように記述します。
server.servlet.session.timeout=15m
セッションタイムアウトの最小値は1分なので、それ以上の時間を設定するようにしましょう。
4.その他のセッション取扱方法
ここでは、先ほど説明した@SessionAttribute以外で、セッション情報を扱う方法を解説します。
①HttpSession
HttpSessionを使用する場合、Controllerクラスで、DIコンテナから参照します。セッションオブジェクトから値を取り出すには、”getAttribute”メソッドを使い、セッションオブジェクトに値を登録するには、”setAttribute”を使います。サンプルコードで確認しましょう。
package com.example.demo.controller;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/")
public class SessionController {
@Autowired
private HttpSession session;
@RequestMapping("login")
public String login() {
Integer counter = (Integer) session.getAttribute("counter");
if (counter == null) {
counter = 0;
}
session.setAttribute("counter", ++counter);
return "index";
}
}
サンプルコードでは、セッションオブジェクトの名前を”counter”とし、値の登録、取得を行なっています。
②@SessionScope
@SessionScopeを使用すると、複数のControllerでセッション情報を共有できます。
package com.example.demo.model;
import java.io.Serializable;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.SessionScope;
import lombok.Data;
@Data
@Component
@SessionScope
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private String UserID;
private int LoginCount;
}
このように、エンティティクラスに@SessionScopeを付与すると、複数のControllerクラスでセッション情報を共有できます。