こんにちは、くまごろーです。
ポートフォリオアプリをいじっていて、ちょっと苦戦したところがあるのでまとめていきます。
1 何をしたいのか?
(1)SpringBootのバリデーションチェックとは
SpringBootでは、アノテーションを活用すれば、簡単にフォームの入力チェックができる。modelクラスに、下記の様にBeanValidationのアノテーションを付加し、コントローラークラスで所定の措置を取れば、SpringBootが自動的にバリデーションを実施してくれる。
(詳しくはこちら。↓)
【SpringBoot】SpringBootでバリデーションチェックを実装してみた。 - くまごろーのプログラミングメモ
<MemberInfo.java>
public class MemberInfo { //入力必須・文字列が2文字以上、20文字まで @NotBlank(message = "名前を入力してください") @Size(min = 2, max = 20, message = "名前は2文字以上、20文字以下で入力してください") private String name; //入力必須・メール形式 @NotBlank(message = "メールアドレスを入力してください") @Email private String email; //入力必須・文字列4文字以上、255文字以下 @NotBlank @Size(min = 4, max = 255) private String password; }
コントローラークラスではこのような処理をする。
@Controller public class HomeController { @GetMapping("/") public String index(Model, model) { return "input"; } @PostMapping("/") public String confirm(@Validated @ModelAttribute MemberInfo memberInfo, BindingResult result, Model model) { if(result.hasErrors()) { return "input"; }return "output"; } }
※ @Validatedを付加すると、バリデーションを行うことができる。
※ バリデーションの結果はBindingResultに入り、result.hasErrors()でエラーがあるか確認できる。
(2)バリデーションエラー発生時にリダイレクトすると・・・?
1つのページに色々なコンテンツを詰め込んでいると、バリデーションエラー時にフォワードではなくリダイレクトさせなければならない時がある。(リダイレクトしないと、正常な動作に必要なmodelを取得できない)
でも、このようにコードを修正しても、リダイレクト後にエラー文は表示されない。
@Controller public class HomeController { /*省略*/ @PostMapping("/") public String confirm(@Validated @ModelAttribute MemberInfo memberInfo, BindingResult result) { if(result.hasErrors()) { return "redirect:/"; //フォワードからリダイレクトに変更 }return "output"; } }
理由は簡単で、上記コードだと、バリデーションの結果を保持しているBindingResultのインスタンスをリダイレクト先に渡せていないから。
BindingResultをリダイレクト先でも取得できるようにする必要がある。
2 解決方法
RedirectAttributesを使用して、BindingResultをリダイレクト先に渡す
BindingResultは"org.springframework.validation.BindingResult.[対象となっているModelAttributeの名前]"という名称でModelに追加されているらしい。
というわけで、BindingResultを上記の名称でRedirectAttributeで追加すれば、リダイレクト先でもBindingResultを使用することができるようになる。
それを踏まえると、コードは以下の通りになる。
@Controller public class HomeController { /*省略*/ @PostMapping("/") public String confirm(@Validated @ModelAttribute MemberInfo memberInfo, BindingResult result, Model model, RedirectAttributes ra) { if(result.hasErrors()) { //RedirectAttributeでBindingResult, 対象のModelAttributeをリダイレクト先に渡す ra.addFlashAttribute("org.springframework.validation.BindingResult.memberInfo", result); ra.addFlashAttribute("memberInfo", memberInfo); return "redirect:/"; //フォワードからリダイレクトに変更 }return "output"; } }
※ 注意点
リダイレクト先で新たにMemberInfoインスタンスをModelに追加すると、RedirectAttributeで追加したBindingResult, memberInfoインスタンスは失われてしまう。
よって、リダイレクト先のメソッドに下記のコードを追加する。
@Controller public class HomeController { @GetMapping("/") public String index(Model model) { //Modelに"memberInfo"が存在しない時だけ、下記の処理を実行 if (!model.containsAttribute("memberInfo")) { model.addAttribute("memberInfo", new MemberInfo()); } return "input"; } /*省略*/ }
これで、リダイレクト時もバリデーションのエラーメッセージを表示することが可能になる。