第11章 Spring MVC + Thymeleaf
セッションスコープは、アクセスしているブラウザごとの固有のデータを、リクエストをまたがってサーバ側で保持するためのJava標準の仕組みです。本章では、Spring MVCを使ってセッションスコープを扱う方法を説明します。
19.1 セッションスコープとは?
AさんとBさんのブラウザがアクセスしている場合は、アプリケーションの中で、AさんとBさんそれぞれでセッションスコープが用意されます。
また、セッションスコープは、複数のリクエストをまたがってデータが保持されます。
なお、それぞれのリクエストごとにデータを保持するリクエストスコープというJava標準の仕組みもあります。
また、第11章で学習したModelもデータを保持する役割を持ちますが、Modelオブジェクトはリクエストごとに新しく生成され、レスポンスを返すと破棄されるため、リクエストをまたがってデータを共有することはできません。
yagibrary.hatenablog.com
yagibrary.hatenablog.com
yagibrary.hatenablog.com
19.2 セッションスコープの利用シーン
セッションスコープは、ショッピングカートを使って注文するときのように、複数の画面をまたがって完結させるような機能で使用されることが多いです。
図19.3は、オンラインショッピングのWebアプリケーションを想定した図になっています。左下の商品詳細画面から、商品をカートに入れるリクエストを送信すると、次の画面でカートの中身が表示されます。このときサーバ側では、カートの中の商品の情報をセッションスコープで保持します。ここでは、CartInputというInputオブジェクトが、カートの中の商品の情報を保持している想定です。
19.3 Spring MVCとセッションスコープ
Spring MVCでセッションスコープを扱う方法は、大きく以下の3種類あります。
- セッションスコープのBeanを使用する
セッションスコープごとに個別のオブジェクトを管理してくれるBeanを使用する。
- @SessionAttributesを使用する
Modelオブジェクトに格納したデータを、自動的にセッションスコープにも格納してもらうことができる。
- Java標準のHttpSessionインタフェースを使用する
Javaが標準で提供するHttpSessionインタフェースを使用してセッションスコープを操作する(前述の2つの方法でも、裏ではHttpSessionインタフェースが使用されています)。
本書では、1つ目のセッションスコープのBeanを使用する方法について説明します。
19.4 セッションスコープのBean
▼ソース19.1 セッションスコープのBean定義
@Component @SessionScope public class ReservationSession { private ReservationInput reservationInput; ...Getter・Setterメソッド
Bean定義する方法は問いませんが、ソース19.1ではステレオタイプアノテーションの@Componentを使用してBean定義しています。@SessionScopeを付けることにより、ReservationSessionオブジェクトが、セッションスコープごとに生成されます。
ソース19.1の定義をすると、DIコンテナを生成した際に、裏ではSpringが自動生成したProxyと呼ばれるクラスのオブジェクトがBeanとして登録されます。Proxyオブジェクトの働きについては次節で説明します。
19.5 セッションスコープのBeanとProxy
自動生成されたProxyクラスは、開発者がBean定義したクラス(ソース19.1のReservationSessionクラス)を継承しています。
図19.4の真ん中にあるのが、ReservationSessionクラスを継承したProxyクラスのオブジェクトです。DIコンテナにはProxyオブジェクトがBeanとして登録されるため、ReservationSessionオブジェクトをインジェクションする側(図19.4ではReservationControllerオブジェクト)には、Proxyオブジェクトがインジェクションされます。このProxyオブジェクトの働きにより、セッションスコープごとに別のReservationSessionオブジェクトを使用することができるのです。
19.6 セッションスコープのBeanの実装サンプル
▼ソース19.2 セッションスコープのBeanのサンプル
@Component @SessionScope ❶ @SuppressWarnings("serial") ❷ public class ReservationSession implements Serializable { ❸ private ReservationInput reservationInput; ❹ public ReservationInput getReservationInput() { return reservationInput; } public void setReservationInput(ReservationInput reservationInput) { this.reservationInput = reservationInput; } public void clearData() { reservationInput = null; } }
❷と❸の行は、セッションスコープのBeanとは別の話になってしまいますが、Javaが標準で提供するシリアライゼーションを使用するための記述です。セッションスコープに格納されるオブジェクトは、シリアライゼーションを使用するための記述が必要になります。
❺の行のclearDataメソッドは、フィールドにnullを代入するだけのメソッドです。セッションスコープのデータは、サーバのメモリを消費するため、不要になったら破棄する必要があります。本来は、セッションスコープの中のReservationSessionオブジェクトを破棄したいですが、セッションスコープのBeanを使用する場合、セッションスコープの中のReservationSessionオブジェクトは削除することができません。ですので、ReservationSessionオブジェクトがフィールドで保持するReservationInputオブジェクトを破棄することで対応します。