検証

Spring MVC には、Java Bean 検証を含む @RequestMapping メソッドの検証が組み込まれています。検証は、次の 2 つのレベルのいずれかで適用できます。

  1. @ModelAttribute@RequestBody@RequestPart 引数リゾルバーは、メソッドパラメーターに Jakarta @Valid または Spring の @Validated がアノテーション付けされており直後に Errors または BindingResult パラメーターがなくメソッド検証が不要 (次に説明) である場合に、メソッド引数を個別に検証します。この場合に発生する例外は MethodArgumentNotValidException です。

  2. @Min@NotBlank などの @Constraint アノテーションがメソッドパラメーターに直接宣言されている場合、またはメソッド (戻り値用) に宣言されている場合、メソッド検証を適用する必要があり、メソッド検証はメソッドパラメーター制約と @Valid を介したネストされた制約の両方をカバーするため、メソッド引数レベルでの検証よりも優先されます。この場合に発生する例外は HandlerMethodValidationException です。

アプリケーションは、コントローラーメソッドシグネチャーに応じて MethodArgumentNotValidException と HandlerMethodValidationException のいずれかが発生する可能性があるため、両方を処理する必要があります。ただし、この 2 つの例外は非常によく似た設計になっており、ほぼ同じコードで処理できます。主な違いは、前者は単一のオブジェクト用であり、後者はメソッドパラメーターのリスト用である点です。

@Valid は制約アノテーションではなく、オブジェクト内のネストされた制約用です。@Valid だけではメソッド検証は行われません。一方、@NotNull は制約であり、これを @Valid パラメーターに追加するとメソッド検証が行われます。特に null 値許容性については、@RequestBody または @ModelAttribute の required フラグを使用することもできます。

メソッド検証は、Errors または BindingResult メソッドパラメーターと組み合わせて使用できます。ただし、コントローラーメソッドは、すべての検証エラーが直後に Errors があるメソッドパラメーターにある場合にのみ呼び出されます。その他のメソッドパラメーターに検証エラーがある場合は、HandlerMethodValidationException が発生します。

Validator は、WebMvc 設定を通じてグローバルに構成することも、@Controller または @ControllerAdvice@InitBinder メソッドを通じてローカルに構成することもできます。複数のバリデーターを使用することもできます。

コントローラーのクラスレベルが @Validated である場合、メソッド検証は AOP プロキシを通じて適用されます。Spring Framework 6.1 で追加されたメソッド検証の Spring MVC 組み込みサポートを利用するには、コントローラーからクラスレベルの @Validated アノテーションを削除する必要があります。

エラーレスポンスセクションでは、MethodArgumentNotValidException と HandlerMethodValidationException がどのように処理されるか、また MessageSource とロケールおよび言語固有のリソースバンドルを通じてそれらのレンダリングをカスタマイズする方法について詳しく説明します。

メソッド検証エラーをさらにカスタム処理するには、ResponseEntityExceptionHandler を継承するか、コントローラーまたは @ControllerAdvice で @ExceptionHandler メソッドを使用して、HandlerMethodValidationException を直接処理できます。例外には、メソッドパラメーターごとに検証エラーをグループ化する ParameterValidationResult のリストが含まれています。これらを反復処理することも、コントローラーメソッドのパラメーター型ごとにコールバックメソッドを訪問者に提供することもできます。

  • Java

  • Kotlin

HandlerMethodValidationException ex = ... ;

ex.visitResults(new HandlerMethodValidationException.Visitor() {

	@Override
	public void requestHeader(RequestHeader requestHeader, ParameterValidationResult result) {
			// ...
	}

	@Override
	public void requestParam(@Nullable RequestParam requestParam, ParameterValidationResult result) {
			// ...
	}

	@Override
	public void modelAttribute(@Nullable ModelAttribute modelAttribute, ParameterErrors errors) {

	// ...

	@Override
	public void other(ParameterValidationResult result) {
			// ...
	}
});
// HandlerMethodValidationException
val ex

ex.visitResults(object : HandlerMethodValidationException.Visitor {

	override fun requestHeader(requestHeader: RequestHeader, result: ParameterValidationResult) {
			// ...
       }

	override fun requestParam(requestParam: RequestParam?, result: ParameterValidationResult) {
			// ...
       }

	override fun modelAttribute(modelAttribute: ModelAttribute?, errors: ParameterErrors) {
			// ...
       }

	// ...

	override fun other(result: ParameterValidationResult) {
			// ...
       }
})