MENU

【SpringBoot】バリデーションのエラーメッセージをリダイレクト先にも表示させる


こんにちは、くまごろーです。
ポートフォリオアプリをいじっていて、ちょっと苦戦したところがあるのでまとめていきます。
 

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";
  }
	
 /*省略*/

}

 
これで、リダイレクト時もバリデーションのエラーメッセージを表示することが可能になる。