SpringBootでモデルをセッションに格納する

SpringBootでモデルをセッションに格納する

SpringBootでモデルやエンティティをセッションに格納する方法を説明する。
実装には@SessionAttributesアノテーションを用いる。

@SessionAttributesアノテーションを使用してセッションに格納したオブジェクトは、Controller単位でライフサイクルが管理される。

しかし、複数のControllerで同じ属性名のオブジェクトを@SessionAttributesアノテーションを使用してセッションに格納した場合、Controllerをまたいでライフサイクルが管理される。


セッションに格納したいモデルクラスやエンティティクラスの作成

セッションに格納したいモデルクラスを作成する。特に特別な記述等は必要ない。

import lombok.Data;

@Data
public class SimpleModel {

    /** ID */
    private int id;

    /** メールアドレス */
    private String email;
}
import lombok.Data;

@Data
public class MyModel {

    /** 名前 */
    private String name;

    /** 年齢 */
    private int age;
}

コントローラークラスを作成する

コントローラークラスに@SessionAttributesアノテーションを付与する。アノテーションの属性値でセッションに格納するオブジェクトを指定する。

オブジェクトの指定には「型」を指定する方法と「属性名」を指定する方法がある。

セッションに格納するオブジェクトを指定する

型でセッションに格納するオブジェクトを指定する

型で指定する場合は、@SessionAttributesアノテーションtypes属性にセッションで格納したいオブジェクトの型を指定する。型は複数指定することも可能。

@ModelAttributeアノテーションもしくはModelのaddAttributeメソッドを使用してModelオブジェクトに追加されたオブジェクトのうち、types属性で指定した型に一致するオブジェクトがセッションに格納される。

以下の記述例では、SimpleModelクラスとMyModelクラスのオブジェクトがセッションに格納される。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.SessionAttributes;

@Controller
@SessionAttributes(types = { SimpleModel.class, MyModel.class })
public class MyController {
}

属性名でセッションに格納するオブジェクトを指定する

属性名で指定する場合は、@SessionAttributesアノテーションvalue属性にセッションで格納したいオブジェクトの属性名を指定する。属性名は複数指定することも可能。

@ModelAttributeアノテーションもしくはModelのaddAttributeメソッドを使用してModelオブジェクトに追加されたオブジェクトのうち、value属性で指定した属性名に一致するオブジェクトがセッションに格納される。

以下の記述例では、属性名が"myModel"と"simpleModel"のオブジェクトがセッションに格納される。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.SessionAttributes;

@Controller
@SessionAttributes(value = { "myModel", "simpleModel" })
public class MyController {
}

セッションにオブジェクトを格納する

セッションにオブジェクトを追加する場合、以下2つの方法を使用する。

  • @ModelAttributeアノテーションが付与されたメソッドでセッションに追加するオブジェクトを返却する
  • ModelオブジェクトのaddAttributeメソッドでセッションに格納するオブジェクトを追加する

@ModelAttributeアノテーションが付与されたメソッドでセッションに追加するオブジェクトを返却する

Modelオブジェクトに格納する属性名を@ModelAttributeアノテーションvalue属性に指定する。

以下の記述例では、returnしたオブジェクトが"myModel"という属性名でセッションに格納される。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.SessionAttributes;

@Controller
@SessionAttributes(value = { "myModel", "simpleModel" })
public class MyController {
    
    @ModelAttribute(value = "myModel")
    public MyModel myModel() {
        return new MyModel();
    }
}

ModelオブジェクトのaddAttributeメソッドでセッションに格納するオブジェクトを追加する

ModelオブジェクトのaddAttributeメソッドを使用して、セッションに格納するオブジェクトを追加する。

上記例では、"simpleModel"という属性名で、オブジェクトがセッションに格納される。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.SessionAttributes;

@Controller
@SessionAttributes(value = { "myModel", "simpleModel" })
public class MyController {
    
    @RequestMapping(value = "/sessionSample", method = RequestMethod.POST)
    public String sessionSample(Model model) {
        SimpleModel simpleModel = new SimpleModel();
        simpleModel.setId(111);
        simpleModel.setEmail("aaa@bb.cc");
        
        model.addAttribute(simpleModel);
        
        return "sessionSample";
    }
}

セッションに格納されているオブジェクトを取得する

セッションに格納されているオブジェクトは、Controllerの処理メソッドの引数として受け取ることができる。

以下の例では、セッションにオブジェクトを格納したコントローラーとは別のコントローラーでセッションに格納されているオブジェクトを取得する例を示す。

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;

@Controller
@SessionAttributes(value = { "myModel", "simpleModel" })
public class SampleController {

    @RequestMapping(value = "/sessionSample/result", method = RequestMethod.POST)
    public String sessionSampleResult(MyModel myModel, SimpleModel simpleModel, Model model) {
        return "redirect:/sessionSample/complete";
    }
}

Controllerのメソッドの引数に渡すオブジェクトがModelオブジェクトに存在しない場合、@ModelAttributeアノテーションの指定の有無で動作が変わる。

@ModelAttributeアノテーションを指定していない場合は、新しいオブジェクトが生成されて引数に渡される。
生成されたオブジェクトはModelオブジェクトに格納されるため、セッションにも格納される。

// @ModelAttributeアノテーションを指定していない例
@RequestMapping(value = "/sessionSample/result", method = RequestMethod.POST)
public String sessionSampleResult(MyModel myModel, SimpleModel simpleModel, Model model) {
    return "redirect:/sessionSample/complete";
}

@ModelAttributeアノテーションを指定している場合は、org.springframework.web.HttpSessionRequiredExceptionが発生する。

// @ModelAttributeアノテーションを指定している例
@RequestMapping(value = "/sessionSample/result", method = RequestMethod.POST)
public String sessionSampleResult(@ModelAttribute MyModel myModel, SimpleModel simpleModel, Model model) {
    return "redirect:/sessionSample/complete";
}

セッションに格納したオブジェクトを削除する

@SessionAttributesを用いてセッションに格納したオブジェクトを削除する場合、 org.springframework.web.bind.support.SessionStatusのsetCompleteメソッドをControllerのメソッドから呼び出す。

SessionStatusオブジェクトのsetCompleteメソッドを呼び出すと、@SessionAttributesアノテーションの属性値に指定されているオブジェクトがセッションから削除される。

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;

@Controller
@SessionAttributes(value = { "myModel", "simpleModel" })
public class SampleController {

    @RequestMapping(value = "/sessionSample/result", method = RequestMethod.POST)
    public String sessionSampleResult(MyModel myModel, SimpleModel simpleModel, Model model) {
        return "redirect:/sessionSample/complete";
    }

    @RequestMapping(value = "/sessionSample/complete", method = RequestMethod.GET)
    public String complete(SessionStatus sessionStatus) {
        sessionStatus.setComplete();
        return "sessionSampleResult";
    }
}

セッションに格納したオブジェクトをThymeleafで参照する

セッションに格納したオブジェクトをThymeleafで参照する場合は、通常のモデルオブジェクトを参照する際と同様に${モデルの属性名.フィールド名}と記述する。

以下は記述例である。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
  <head>
    <meta charset="UTF-8">
    <title>Session Sample Result</title>
  </head>
  <body>
    <p th:text="|MyModel:${myModel.name} + ${myModel.age}|">
    <p th:text="|SimpleModel:${simpleModel.id} と ${simpleModel.email}|"/>
  </body>
</html>