Spring BootでBindingResultをリダイレクト先へ渡す際の注意点
By Donna Thomason | 2021/12/09 02:23:04
要約
SpringBootアプリケーションでフォームのバリデーションを行う際、BindingResult
を用いてエラーメッセージを管理することがあります。これをリダイレクト後の画面で表示するために、RedirectAttributes
のaddFlashAttribute
メソッドを使ってBindingResult
をリダイレクト先へ渡す場合、リダイレクト先のコントローラーメソッドの引数にForm
クラスとBindingResult
クラスを直接定義してはいけません。正しく扱わないと、予期せぬ動作やエラーメッセージが表示されないといった問題が発生する可能性があります。
SpringBootのバージョン情報
- Spring Boot バージョン: 2.7.0 以降
- Java バージョン: 8 以降
BindingResultをRedirectAttributesのaddFlashAttributeで渡す際の注意点
なぜリダイレクト先でFormクラスとBindingResultクラスを渡すと機能しないのか
-
Spring MVCのリクエストライフサイクル:
- Spring MVCでは、HTTPリクエストがコントローラーメソッドにマッピングされる際、
BindingResult
はフォームのバインディング処理時に新たに生成されます。このバインディング処理では、リクエストパラメータをForm
オブジェクトにバインドし、その結果としてのBindingResult
が自動的に生成されます。 - リダイレクト時には、新しいHTTPリクエストが発行されるため、
BindingResult
も新たに生成されます。この時点で、元のリクエストで使用されたBindingResult
は、リクエストスコープを超えて存在しないため、リダイレクト先では無視されます。
- Spring MVCでは、HTTPリクエストがコントローラーメソッドにマッピングされる際、
-
Flash Attributesの扱い:
RedirectAttributes.addFlashAttribute
は、一時的にデータをセッションに保存し、リダイレクト先でそのデータを取り出して利用できるようにするための機能です。しかし、リダイレクト先でForm
クラスとBindingResult
クラスを引数として宣言すると、Spring MVCはこれを新たなバインディングプロセスとして扱い、FlashAttributes
に格納されたBindingResult
を適切に利用しません。- 特に、
BindingResult
のフラッシュ属性は、"org.springframework.validation.BindingResult.フォーム名"
という特定のキーで格納されますが、リダイレクト先での新しいバインディング処理が優先されてしまうため、addFlashAttribute
で渡されたBindingResult
は上書きされてしまい、利用されません。
誤った実装例
以下は、リダイレクト先でForm
クラスとBindingResult
を引数に定義してしまう誤った例です。この場合、BindingResult
が適切に処理されず、リダイレクト後の画面でエラーメッセージが表示されない可能性があります。
@Controller
public class SampleController {
@PostMapping("/submit")
public String submitForm(@ModelAttribute("form") Form form, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
if (bindingResult.hasErrors()) {
redirectAttributes.addFlashAttribute("form", form);
redirectAttributes.addFlashAttribute("bindingResult", bindingResult);
return "redirect:/form";
}
// 正常処理
return "success";
}
// リダイレクト先での処理
@GetMapping("/form")
public String showForm(@ModelAttribute("form") Form form, BindingResult bindingResult) {
// ここではBindingResultが適切に機能しない
return "form";
}
}
正しい実装例
正しい実装では、リダイレクト先でBindingResultを直接引数に取らず、@ModelAttributeを用いてFormオブジェクトを取得し、それに関連付けられたエラーメッセージを取り出して表示します。
@Controller
public class SampleController {
@PostMapping("/submit")
public String submitForm(@ModelAttribute("form") Form form, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
if (bindingResult.hasErrors()) {
redirectAttributes.addFlashAttribute("form", form);
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.form", bindingResult);
return "redirect:/form";
}
// 正常処理
return "success";
}
// リダイレクト先での処理
@GetMapping("/form")
public String showForm() {
return "form";
}
}
注意点
- BindingResultの名前に注意:
- RedirectAttributesにBindingResultを追加する際、キー名を"org.springframework.validation.BindingResult.フォーム名"として渡す必要があります。この例では"org.springframework.validation.BindingResult.form"です。
- BindingResultを直接渡さない:
- リダイレクト先のメソッドにBindingResultを直接渡しても機能しないため、BindingResultのオブジェクトはRedirectAttributesを通じて渡します。
- エラーメッセージの表示:
- BindingResultがリダイレクト先で正しく機能すれば、formに関連するエラーメッセージが正しく表示されます。
Note
Highlights information that users should take into account, even when skimming.Tip
Optional information to help a user be more successful.Important
Crucial information necessary for users to succeed.Warning
Critical content demanding immediate user attention due to potential risks.Caution
Negative potential consequences of an action.この実装により、フォームバリデーションのエラーメッセージがリダイレクト先の画面でも適切に表示されるようになります。