Spring Frameworkにおけるvalidation
詳しくは上記リンクも参照したほうが良いですが、 カジュアルに使うように残します。
Hibernate Validator
実装はHibernate Validatorなので、javax.validation.constraints
のアノテーションを使います。
主なアノテーション
@NotNull // nullでないことをチェック /** * Stringに対して使えるアノテーション */ @NotEmpty // 空文字列でないことをチェック @Size(min = 1, max = 10) // 文字列の長さが1以上10以下であることをチェック @Pattern(regexp = "[0-9A-Z]*") // "[0-9A-Z]*"の正規表現にマッチしているかチェック @Email // Emailアドレスとしてvalidなものかチェック /** * Integerなど整数型に対して使えるアノテーション */ @Min(3) // 3以上であることをチェック @Max(100) // 以下であることをチェック
Formに対するvalidation
制約を記したFormクラスを用意して、コントローラで受け取るのが基本です。
Formクラス
ビューの入力フォームに対応するFormクラスを書きます。
@Data public final class SearchForm { @NotNull @Size(min = 1, max = 100) @Pattern(regexp = "[0-9a-zA-z]*") private String message; }
Controllerクラス
Formのバリデーションに失敗するとBindingResultにエラーが入ります。
@Controller @RequestMapping("") public class SearchController { @PostMapping("serach") public ModelAndView search( @Validated @ModelAttribute final SearchForm searchForm, final BindingResult bindingResult ) { final ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("hoge"); // Formのバリデーションに失敗するとBindingResultにエラーが入る if (bindingResult.hasErrors()) { // エラー時の処理 } // ... return modelAndView; } }
エラー時の実際の処理は、エラーページに飛ばしたり、 modelに何かを付け加えたりといったものになります。
エラーメッセージは、デフォルトで親切なものが出ます。
Constraintごとにmessage
属性を付与して、カスタムすることができますが、
セキュリティ上の懸念がある場合は、modelに付与して、一括で同じメッセージを出しても良いと思います。
Form以外に対するvalidation
Form以外の普通の引数に対するvalidationでも、不正なリクエストを弾く場合などで、Hibernate Validatorは有用です。
@Controller @RequestMapping("") public class HogeController { @PostMapping("add") public ModelAndView add( @RequestParam("quantity") @NotNull @Min(1) @Max(100) @Valid final Integer quantity) { // ... } }
(ここの場合Springの@Validated
ではなく、Hibernateの方の@Valid
でもOKです)
ここでinvalidだった場合、中に入る前に、javax.validation.ConstraintViolationException
が投げられます。
Springの場合はControllerで投げられた例外は@ExceptionHandler
で拾うことができるので、
@ControllerAdvice
の中に書いておけば、全ての@Controller
から投げられたConstraintViolationException
を拾うことができます。
@ControllerAdvice public class MyExceptionHandler { // 400 Bad Requestを返してエラーページに飛ばす @ExceptionHandler(ConstraintViolationException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) public String handleConstraintViolationException() { // ログ落としたり... return "error"; } }
書いてないこと
自前のconstraint annotationを作ることもできます。
長くなったので、また今度ということで… (忘れる😩)