☝️

【Spring Boot】リダイレクト先へのデータの受け渡し

2023/09/20に公開

初めに

Springでビューに値を渡すためには値をModelに格納するというのは初学者でもなんとなくわかります。しかし、「Modelに値を格納したらなんとなくデータを保持してくれる」みたいな考えだった私は、リダイレクト処理を行う際のデータの受け渡しでよくわからなくなりました。この記事ではSpring初学者が、Modelのスコープ等について学びつつ、リダイレクト処理のデータ受け渡し時のイメージを掴むことを目的にしていきます。

完成コード

結論、リダイレクト先にデータを渡す方法が知りたい人は以下のコードを見ればOKです。submitメソッドで受け取ったwordの値をredirectAttributes.addFlashAttributeを用いればリダイレクト先に渡せます。それをリダイレクト先のcheckメソッドの@ModelAttribute("word") String wordで受け取っているというだけです。

コントローラ
@Controller
@RequestMapping("/redirect_check")
public class RedirectCheckController {

    public RedirectCheckController() {
    }

    @GetMapping("/")
    public ModelAndView check(@ModelAttribute("word") String word, ModelAndView mav) {
        mav.addObject("word", word);
        mav.setViewName("redirect_check/index");
        return mav;
    }

    @PostMapping("/submit")
    public String submit(@RequestParam String word, RedirectAttributes redirectAttributes) {
        redirectAttributes.addFlashAttribute("word", word);
        return "redirect:/redirect_check/";
    }

}

しかし、なぜリダイレクト先にデータを渡す場合はRedirectAttributesを用いなければいけないのでしょうか?
例えば以下コードのようにModelを用いて、リダイレクト先にデータを渡すことができないのはなぜでしょうか?

model.addAttribute("word", word);

この記事ではもう少しだけ詳しく調べて、Spring Bootにおけるリダイレクト処理のイメージを掴んでいこう思います。

リダイレクトとは?

そもそもリダイレクトがどういうものかを軽く触れておきます。
https://k-sasaking.net/programing/redirect-forwad/
上の記事を読めばわかりますが、クライアントがリクエストを送った結果、サーバーではリダイレクトのレスポンスを返します。そうするとクライアント(ブラウザ)はそのレスポンスを基に、勝手に新しいリクエストを投げ、ページの情報を取得します。上の記事から画像もわかりやすかったので、拝借すると下図のような感じです。

Springにおけるリダイレクト

Springでは、コントローラの例で記載したように、本来View名を指定する部分で以下のように「redirect:+リダイレクト先のリクエストパス」を指定することでリダイレクトさせることができます。本来View名入れるところにリクエストパスを入れるというところは少しややこしいので間違えないように気をつけましょう。

return "redirect:/redirect_check/";

Viewとのデータ連携(Modelとスコープ)

Viewに連携するデータはModelに格納して連携します。このときModelへ格納されるオブジェクトは、以下の3つのスコープのいずれかで管理されます。

  • リクエストスコープ
    →リクエスト内でオブジェクトを共有するためのスコープ。リクエストに対するレスポンスを返すとデータは破棄されます。単にModelにオブジェクトを格納すればリクエストスコープになります。
  • フラッシュスコープ
    →リダイレクト時にオブジェクトを共有するためのスコープ。オブジェクトは一時的にHttpSessionに格納され、リダイレクト処理終了後に自動で破棄される。
  • セッションスコープ
    →同一セッション内の複数リクエストでオブジェクトを共有するためのスコープ。オブジェクトはHttpSessionに格納され、明示的に破棄するまでHttpSessionに残り続けます。

ここまでくれば、以下コードが単にModelにオブジェクトを格納している→つまり、リクエストスコープなので、リダイレクト後はModelにwordの情報が残らない!ということがわかります。

model.addAttribute("word", word);

フラッシュスコープにオブジェクトを格納

フラッシュスコープにオブジェクトを格納するためには、初めのコードに記載したRedirectAttributesを使用します。RedirectAttributesをハンドラメソッドの引数に記載し、以下のようにaddFlashAttributeメソッドを使うことで、フラッシュスコープにオブジェクトを格納することができます。

redirectAttributes.addFlashAttribute("word", word);

→これは"word"というキーで、値はwordというオブジェクトを、フラッシュスコープで格納しますということですね。

RedirectAttributesにはaddAttributeというメソッドも存在します(RedirectAttrubutes公式javadoc)。

addFlashAttributeとaddAttributeの違いは以下記事が参考になりました。
https://grandbig.github.io/blog/2016/05/28/redirect-parameter-spring-boot/
addAttributeでもフラッシュスコープに格納することはできるけど、文字列としてしかパラメータを送れないようです。なので基本的にはaddFlashAttributeを使うのが良さそうですが、リダイレクト時のGETリクエストにクエリパラメータをつけたい場合などにはaddAttributeを使う必要があるという感じになりそうですね。

ちなみに私が書いたwordという変数はString型だったので、以下のように書いてもaddFlashAttributeの場合と全く同じ挙動になっていました。

redirectAttributes.addAttribute("word", word);

ちなみに以下のようにキーとなる文字列を指定せずオブジェクトだけを引数に取ることもできます。この場合はオブジェクトのクラスの頭文字を小文字にした名前がキーとなるようです。今回のwordはString型なので、キー名は"string"となっていました。

redirectAttributes.addAttribute(word)

Modelからデータの受け取り

以下のようにフラッシュスコープに格納した値は、

redirectAttributes.addFlashAttribute("word", word);

↓このように@ModelAttributeを用いてリダイレクト先でデータを受け取ることができます。

@GetMapping("/")
public ModelAndView check(@ModelAttribute("word") String word, ModelAndView mav) {

このとき、格納時に"word"というキーで格納しているので、@ModelAttributeの引数にも同じ名前を記載する必要があります。
以下のように変数名がwordなら引数の"word"を省略してもいけないかなと思って試してみましたが、こちらは値を受け取ることができませんでした。

@ModelAttribute String word

@ModelAttribute以外のデータの受け取り方も1つ紹介します。
以下のようにオブジェクトをフラッシュスコープに格納した場合、

RedirectCheckForm form = new RedirectCheckForm();
form.setWord(word);
redirectAttributes.addFlashAttribute(form);

↓リダイレクト先でこのように受け取ることも可能です。

@GetMapping("/")
public ModelAndView check(RedirectCheckForm form, ModelAndView mav) {
	mav.addObject("word", form.getWord());

まとめ

この記事で伝えたかったことは、Modelへ格納するオブジェクトにはスコープの種類があり、リダイレクト先にデータを受け渡すためにはフラッシュスコープを使う必要がある!ということです。
では、実際フラッシュスコープの仕組みがどうなっているかというところまで詳しく調べきれていませんが、リダイレクトを使用する上での最低限の知識は身につけられたかと思います。
この記事がSpring初学者の参考になれば幸いです。

その他の参考リンク

https://www.amazon.co.jp/Spring徹底入門-Spring-FrameworkによるJavaアプリケーション開発-株式会社NTTデータ/dp/4798142476

Discussion