アソビュー Advent Calendar 2019 の11日目の記事です。
こんにちは、@seitです。
Spring Bootでバリデーションチェック実装を試したので備忘録です。
アノテーションを使ったバリデーションチェックの方法
今回はSpring Frameworkで用意されている@Validatedアノテーション(org.springframework.validation.annotation)を使って、画面に入力された値のチェックを行います。
まずは簡単なFormとController、HTMLを用意し、text1フィールドを入力必須にしてみます。
テンプレートエンジンはThymeleafを使っています。
InputForm.java
public class InputForm { @NotBlank(message = "text1を入力してください")・・・① String text1; public String getText1() { return text1; } public void setText1(String text1) { this.text1 = text1; } }
SampleController.java
@Controller public class SampleController { @GetMapping("/index") public String index( InputForm inputForm){ return "sample/index"; } @PostMapping("/input") public String input(@Validated InputForm inputForm, BindingResult error, Model model){・・・② if(error.hasErrors()){・・・③ return "sample/index"; } return "sample/result"; } }
index.html
<!DOCTYPE html> <html lang="ja" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head></head> <body th:object="${inputForm}"> <ul>・・・④ <li th:each="error : ${#fields.detailedErrors()}"> <span th:text="${error.message}">Error message</span> </li> </ul> <form method="post" th:action="@{/input}" > <p>text1</p> <input path="text1" type="text" th:field="*{text1}"/> <input type="submit" value="送る"/> </form> </body>
今回はtext1を必須入力にしたいので、そのフィールドに@NotBlankアノテーションを付与します(①)。
@NotBlankアノテーションは、指定したフィールドに空白が入力されることを許容しません。
独自のエラーメッセージを定義する場合は、message属性を使用します(message属性を定義しない場合はデフォルトのメッセージが返されます)。
Controllerが受け取るFormに@Validatedアノテーションを付与します(②)。
@Validatedを付与したFormに対して、SpringはController#inputハンドラが呼び出される前にバリデーションチェックを行います。
これだけで、text1に何も入力しない場合に、Controller#inputハンドラの引数BindingResultにエラーが渡されます。
Controllerでは、バリデーションエラーの発生有無を③でチェックしています。
Thymeleafでエラーを表示するには、#fieldsからエラー情報を取得することで表示できます(④)。
groupでチェック対象を絞る
バリデーションチェックは、@Validアノテーション(javax.validation)でも行うことができますが、@Validated(org.springframework.validation.annotation)を使うことでgroups属性を利用できます。
groups属性によって、状況に応じてチェック対象としたり、チェック対象から外したりといった制御が可能です。
SampleController.java
@PostMapping("/input") public String input(@Validated(AlphaGroup.class) InputForm inputForm, BindingResult error, Model model){・・・① if(error.hasErrors()){ return "sample/index"; } return "sample/result"; }
InputForm.java
@NotBlank(groups = {AlphaGroup.class}, message = "text1を入力してください")・・・② String text1; @NotBlank(groups = {BetaGroup.class}, message = "text2を入力してください")・・・③ String text2;
AlphaGroup.java
public interface AlphaGroup {・・・④ }
BetaGroup.java
public interface BetaGroup {・・・⑤ }
index.html
<form method="post" th:action="@{/input}" > <p>text1</p> <input path="text1" type="text" th:field="*{text1}"/> <p>text2</p> <input path="text2" type="text" th:field="*{text2}"/> <input type="submit" value="送る"/> </form>
今回は2つのGroup(AlphaGroup④、BetaGroup⑤)を用意しました。
InputFormのtext1をAlphaGroupに指定しています(②)。
InputFormにtext2を追加し、BetaGroupを指定しています(③)。
これで、@ValidatedにAlphaGroupを指定(①)することで、同じAlphaGroupに属するフィールド(text1)のみバリデーションチェックが入ります。
AssertTrueを用いた相関チェック
AssertTrueを用いることで、相関チェックを行うことができます。
例えば、Aが入力されている場合は、Bも必須入力とする、といったようなことができます。
今回の例では、text1が入力されている場合、text2の入力チェックを行います。
InputForm.java
@NotBlank(groups = {AlphaGroup.class}, message = "text1を入力してください") String text1; String text2; // 相関チェック @AssertTrue(groups= {AlphaGroup.class},message = "text2を入力してください") public boolean isValid(){ if(text1.isEmpty()) { // text1のバリデーションチェックはNotBlankに任せる return true; } // text1が入力されている時はtext2もチェックする if(text2.isEmpty()){ // 未入力の場合はエラーとする return false; } return true; }
今回は以上です。