Spring Bootのリクエストのバリデーションとアノテーションについて
はじめに
こんにちは、クラウドエースの許です。
Spring Boot には、リクエストパラメータが正しいかを検証し、パラメータ不正時にリクエストを弾くことができる機能が備わっています。
そして、この機能はリクエストパラメータにアノテーションを付与することで実現されます。
例えば、以下のように @NotNull
を付与することで、リクエストパラメータが null でないことを検証することができます。
@NotNull
private String string_value;
そして、これらのアノテーションは、jakarta.validation.constraints
にて定義されています。
今回はそれら全てのアノテーション(xxx.List
については省略)とその指定方法について解説していきます。
アノテーション一覧早見表
アノテーション名 | ドキュメント説明 | 意訳 |
---|---|---|
@AssertFalse |
The annotated element must be false. | 値が false であることを検証 |
@AssertTrue |
The annotated element must be true. | 値が true であることを検証 |
@DecimalMax |
The annotated element must be a number whose value must be less than or equal to the specified maximum. | 値が指定された最大値以下であることを検証 |
@DecimalMin |
The annotated element must be a number whose value must be greater than or equal to the specified minimum. | 値が指定された最小値以上であることを検証 |
@Digits |
The annotated element must be a number within the specified range. | 値(小数)が指定した桁数内であることを検証 |
@Email |
The annotated element must be a valid email address. | 値が有効なメールアドレスであることを検証 |
@Future |
The annotated element must be a date in the future. | 値が未来の日付であることを検証 |
@FutureOrPresent |
The annotated element must be a date in the future or present. | 値が未来または現在の日付であることを検証 |
@Max |
The annotated element must be a number whose value must be less than or equal to the specified maximum. | 値が指定された最大値以下であることを検証 |
@Min |
The annotated element must be a number whose value must be greater than or equal to the specified minimum. | 値が指定された最小値以上であることを検証 |
@Negative |
The annotated element must be a negative number. | 値が負の数であることを検証 |
@NegativeOrZero |
The annotated element must be a negative number or zero. | 値が負の数またはゼロであることを検証 |
@NotBlank |
The annotated element must not be null and must contain at least one non-whitespace character. | 値が null でなく、かつ非空白文字を含むことを検証 |
@NotEmpty |
The annotated element must not be null and must not be empty. | 値が null でなく、かつ空でないことを検証 |
@NotNull |
The annotated element must not be null. | 値が null でないことを検証 |
@Null |
The annotated element must be null. | 値が null であることを検証 |
@Past |
The annotated element must be a date in the past. | 値が過去の日付であることを検証 |
@PastOrPresent |
The annotated element must be a date in the past or present. | 値が過去または現在の日付であることを検証 |
@Pattern |
The annotated element must match the specified regular expression. | 値が指定された正規表現に一致することを検証 |
@Positive |
The annotated element must be a positive number. | 値が正の数であることを検証 |
@PositiveOrZero |
The annotated element must be a positive number or zero. | 値が正の数またはゼロであることを検証 |
@Size |
The annotated element must be a string whose size must be within the specified boundaries. | 文字列の長さが指定された範囲内であることを検証 |
参考:jakarta.validation.constraints
動作検証方法
それぞれの指定方法について解説する前に、動作検証を行うための環境構築方法について説明します。
- Spring Initializr にアクセスします。
- 以下のように設定します。
- Project: Maven
- Language: Java
- Spring Boot: 3.4.5
- Project Metadata
- Group: com.example
- Artifact: demo
- Name: demo
- Package name: com.example.demo
- Packaging: Jar
- Java: 21
- Dependencies
- Spring Web
- Lombok
- Validation
※ Validation を追加しないと、それぞれのアノテーションは利用できません。
- [Generate] をクリックし、ダウンロードした zip ファイルを解凍します。
- 解凍した内容を IDE 等で開きます。
-
src/main/java/com/example/demo
にdto
パッケージを作成し、以下のようにDemoDTO.java
を作成します。
DTO クラスはリクエストパラメータやレスポンスパラメータを定義するクラスです。
これを作成することで、リクエストパラメータの管理が容易になります。package com.example.demo.dto; import lombok.Data; import java.time.LocalDateTime; @Data public class DemoDTO { private String string_value; private Integer integer_value; private Float float_value; private LocalDateTime date_time_value; private Boolean boolean_value; private String email; }
-
src/main/java/com/example/demo
にcontroller
パッケージを作成し、以下のようにDemoController.java
を作成します。
Controller クラスはリクエストを受け取り、レスポンスを返すクラスです。
ここでは、単純にリクエストを受け取り、リクエストパラメータをそのままレスポンスとして返す API を作成します。package com.example.demo.controller; import com.example.demo.dto.DemoDTO; import jakarta.validation.Valid; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController public class DemoController { @PostMapping("/demo") public DemoDTO demo( @RequestBody @Valid DemoDTO demoDTO ) { return demoDTO; } }
これで以下のような形式でリクエストボディをPOSTで送信する準備が完了しました。(送信先エンドポイントは http://127.0.0.1:8080/demo
)
アノテーションは付与していない状態なので、バリデーションは行われません。
{
"string_value": "string",
"integer_value": 1,
"float_value": 1.0,
"date_time_value": "2023-10-01T00:00:00",
"boolean_value": true,
"email": "test@email.com"
}
DemoDTO を利用してアノテーションを付与する方法
実際にバリデーションを行うために、DemoDTO
クラスにアノテーションを付与していきます。
基本的には、以下のように、リクエストパラメータのフィールドにアノテーションを付与するだけでバリデーションが行われます。
public class DemoDTO {
@NotNull
private String string_value;
@Max(value = 100)
private Integer integer_value;
private Float float_value;
private LocalDateTime date_time_value;
private Boolean boolean_value;
@Email
private String email;
}
ここのアノテーションの指定方法は、後述するアノテーションの機能解説を参考にしてください。
バリデーションエラー時のレスポンスをカスタマイズする
作成した API がバリデーションエラーになると、以下のようなレスポンスになります。
{
"timestamp": "2025-05-08T00:31:29.102+00:00",
"status": 400,
"error": "Bad Request",
"path": "/demo"
}
ただし、この状態だと何がバリデーションに引っかかったのかレスポンスでは判別できないため、APIを公開する場合など、API利用側で何のパラメータが間違っているのか判別できません。
そのため、レスポンスをカスタマイズして、どのリクエストが、どのように間違っているかを確認できるようにしていきます。
やり方はとても簡単で、メソッドを一つ追加するだけです。
src/main/java/com/example/demo/exception/GlobalExceptionHandler.java
を作成し、以下のように記載します。
GlobalExceptionHandler
クラスは、Exception をキャッチしてレスポンスをカスタマイズしてくれるクラスです。
Spring Boot では、@RestControllerAdvice
アノテーションを付与することで、Controller クラスで発生した例外をキャッチしてくれます。
package com.example.demo.exception;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getFieldErrors().forEach(error -> {
errors.put(error.getField(), error.getDefaultMessage());
});
return ResponseEntity.badRequest().body(errors);
}
}
この状態で、APIにリクエストを送ると以下のようなレスポンスが取得できます。
{
"string_value": "空白は許可されていません"
}
これで、どのリクエストが、どのように間違っているかを確認できるようになったかと思います。
アノテーションの機能解説
前段が長くなってしまいましたが、ここからはそれぞれのアノテーションの機能について解説していきます。
@AssertFalse
リクエストパラメータが false であることを検証します。
@AssertFalse
private Boolean boolean_value;
@AssertTrue
リクエストパラメータが true であることを検証します。
@AssertTrue
private Boolean boolean_value;
@DecimalMax
リクエストパラメータが指定された最大値以下であることを検証します。
※value は string 型で指定する必要があります。
@DecimalMax(value = "100.0")
private Float float_value;
@DecimalMin
リクエストパラメータが指定された最小値以上であることを検証します。
※value は string 型で指定する必要があります。
@DecimalMin(value = "0.0")
private Float float_value;
@Digits
リクエストパラメータが指定された桁数の範囲内であることを検証します。
integer
は整数部の桁数、fraction
は小数部の桁数を指定します。
例は、整数部が3桁、小数部が2桁の範囲内であることを検証します。
@Digits(integer = 3, fraction = 2)
private Float float_value;
リクエストパラメータが有効なメールアドレスであることを検証します。
メールアドレスの形式は xxxxx@domain.name
のような形式です。
検証した結果、 @
の前後に一字以上の文字があれば、チェックは通過する仕様になります。(x@x
のような形式)
@Email
private String email;
@Future
リクエストパラメータが未来の日付であることを検証します。
ただし、現在の日時データの場合はチェックに引っかかるので、現在も対象にしたい場合は @FutureOrPresent
を使用してください。
@Future
private LocalDateTime date_time_value;
@FutureOrPresent
リクエストパラメータが未来または現在の日付であることを検証します。
@FutureOrPresent
private LocalDateTime date_time_value;
@Max
リクエストパラメータが指定された最大値以下であることを検証します。
※整数型のみが対象のため、小数点型を対象にしたい場合は @DecimalMax
を使用してください。
@Max(value = 100)
private Integer integer_value;
@Min
リクエストパラメータが指定された最小値以上であることを検証します。
※整数型のみが対象のため、小数点型を対象にしたい場合は @DecimalMin
を使用してください。
@Min(value = 0)
private Integer integer_value;
@Negative
リクエストパラメータが負の数であることを検証します。
ただし、0 の場合はバリデーションに引っかかります。
@Negative
private Integer integer_value;
@NegativeOrZero
リクエストパラメータが負の数またはゼロであることを検証します。
@NegativeOrZero
private Integer integer_value;
@NotBlank
リクエストパラメータが null でなく、かつ空白文字(タブ文字や改行コードなどを含む)の文字を含むことを検証します。
@NotBlank
private String string_value;
@NotEmpty
リクエストパラメータが null でなく、かつ空でないことを検証します。
@NotBlank
と異なり、こちらは空白文字が含まれている場合は通過します。
@NotEmpty
private String string_value;
@NotNull
リクエストパラメータが null でないことを検証します。
"string_value": ""
のようなリクエストは通過しますが、"string_value": null
のようなリクエストは通過しません。
@NotNull
private String string_value;
@Null
リクエストパラメータが null であることを検証します。
@Null
private String string_value;
@Past
リクエストパラメータが過去の日付であることを検証します。
ただし、現在の日時データの場合はチェックに引っかかるので、現在も対象にしたい場合は @PastOrPresent
を使用してください。
@Past
private LocalDateTime date_time_value;
@PastOrPresent
リクエストパラメータが過去または現在の日付であることを検証します。
@PastOrPresent
private LocalDateTime date_time_value;
@Pattern
リクエストパラメータが指定された正規表現に一致することを検証します。
@Pattern(regexp = "^[a-zA-Z0-9]+$")
private String string_value;
@Positive
リクエストパラメータが正の数であることを検証します。
ただし、0 の場合はバリデーションに引っかかります。
@Positive
private Integer integer_value;
@PositiveOrZero
リクエストパラメータが正の数またはゼロであることを検証します。
@PositiveOrZero
private Integer integer_value;
@Size
リクエストパラメータの文字数が指定された範囲内であることを検証します。
受け取る文字数を指定したい場合に有効です。
@Size(min = 1, max = 3)
private String string_value;
まとめ
以上、Spring Boot のバリデーションアノテーションについて解説しました。
バリデーションの実装の際に、こちらの記事を参考に記載いただければと思います。
Discussion