Spring Boot バリデーション実践入門

このスライドについて

対象者

  • 基本的な Spring Boot アプリを作ったことはあるが、バリデーションを体系的に学んでいない人
  • Spring Boot プロジェクトの基礎設計をする人

目標

Spring Boot のバリデーションで、「こんなことができるんだ」という事を知る

なぜバリデーションが必要か?

  • バリデーションは「クライアントが『契約』を守っているかを確認する」行為
  • バリデーションを行い、不正な状態を Service に渡さないようにすることで、Controller 以降がビジネスロジックに集中できる

「Spring Boot には、このバリデーションを簡単かつ統一的に実装する仕組みが存在しているため、積極的に使っていきましょう」という話をしていきます。

基本のバリデーション

基本は単項目チェック。 アノテーションをつけることにより、どんなバリデーションを行うか定義する。

  • @RequestParam に直接定義
  • @RequestBody のバリデーション定義(Bean のフィールドにバリデーション定義)
  • デフォルトアノテーションの一例

@RequestParam に直接定義

次のように、引数にアノテーションをつけることでバリデーションを定義する。

package dev.mikoto2000.springboot.validation.workshop.firststep.controller;

import org.hibernate.validator.constraints.Length;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import jakarta.validation.constraints.Pattern;

/**
 * EchoController
 */
@RestController
public class EchoController {

  /**
   * 引数を直接バリデーション。
   *
   * @param message 文字列
   *              - 必須ではない
   *              - デフォルト値は "0"
   *              - 1文字以上10文字以下
   *              - 数字のみ
   * @return 引数に改行文字を付与して返す
   */
  @GetMapping("/number-echo")
  public String numberEcho(
      @RequestParam(required = false, defaultValue = "0")
      // 文字列の長さは 1 から 10 とする
      @Length(min = 1, max = 10)
      // 文字は、正規表現 `[0-9]*` にマッチする
      @Pattern(regexp = "[0-9]*")
      String message) {
    return message + "\n";
  }
}

動作確認

バリデーション成功

次のように、「正規表現 [0-9]* に適合」したリクエストを送った場合、 200 レスポンスが返ってきて、message に改行を加えたレスポンスが返ってくる。

vscode /workspaces/spring-boot-validation-workshop (main) $ curl -v localhost:8080/number-echo?message=123 # 正規表現 `[0-9]*` に適合
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /number-echo?message=123 HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.88.1
> Accept: */*
> 
< HTTP/1.1 200 
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 4
< Date: Fri, 02 Jan 2026 02:10:05 GMT
< 
123
* Connection #0 to host localhost left intact
バリデーション失敗

次のように、「正規表現 [0-9]* に適合」していないリクエストを送った場合、 400 レスポンスが返ってきて、ずらずらとエラーメッセージが表示される。

vscode /workspaces/spring-boot-validation-workshop (main) $ curl -v localhost:8080/number-echo?message=123
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /number-echo?message=123 HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.88.1
> Accept: */*
> 
< HTTP/1.1 200 
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 4
< Date: Fri, 02 Jan 2026 02:10:05 GMT
< 
123
* Connection #0 to host localhost left intact
vscode /workspaces/spring-boot-validation-workshop (main) $ curl -v localhost:8080/number-echo?message=123a
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /number-echo?message=123a HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.88.1
> Accept: */*
> 
< HTTP/1.1 400 
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Fri, 02 Jan 2026 02:12:18 GMT
< Connection: close
< 
{"timestamp":"2026-01-02T02:12:18.157+00:00","status":400,"error":"Bad Request","trace":"org.springframework.web.method.annotation.HandlerMethodValidationException: 400 BAD_REQUEST \"Valida
tion failure\"\n\tat org.springframework.web.method.annotation.HandlerMethodValidator.applyArgumentValidation(HandlerMethodValidator.java:106)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:187)\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:991)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:896)\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)\n\tat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)\n\tat jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)\n\tat jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)\n\tat org. apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)\n\tat org.apache. catalina.core.StandardHostValve.invoke(StandardHostValve.java:116)\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:398)\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:903)\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1769)\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1189)\n\tat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:658)\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)\n\tat java.base/java.lang.Thread.run(Thread.java:1583)\n","message":"Validation failed for method='public java.lang.String dev.mikoto2000.springboot.validation.workshop.firststep.controller.EchoController.numberEcho(java.lang.String)'. Error count: 1","errors":[{"codes":["Pattern.echoController#numberEcho.message","Pattern.message","Pattern.java.lang.String","Pattern"],"defaultMessage":"must match \"[0-9]*\"","arguments":[{"codes":["echoController#numberEcho.message","message"],"arguments":null,"defaultMessage":"message","code":"message"},[],{"codes":["[0-9]*"],"defaultMessage":"[0-9]*","arguments":null}]}],"path":"/number-echo"}vscode ➜ /workspaces/spring-boot-validation
* Closing connection 0

@RequestBody のバリデーション定義

次のように、 @RequestBody@Valid を付与することで、その Bean のバリデーション定義を検証する。

そして、Bean のフィールドに、バリデーション定義を付与する。

BeanEchoController.java:

package dev.mikoto2000.springboot.validation.workshop.firststep.controller;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import dev.mikoto2000.springboot.validation.workshop.firststep.bean.ValidationExampleBean;
import jakarta.validation.Valid;

/**
 * BeanEchoController
 */
@RestController
public class BeanEchoController {

  /**
   * Bean 定義でバリデーション。
   *
   * @param bean リクエストボディの JSON をマッピングした Bean
   *            - 各フィールドは null 不可(ValidationExampleBean の定義を参照)
   * @return 引数を Lombok の toString() で文字列化して改行文字を付与して返す
   */
  @PostMapping("/bean-echo")
  public String beanEcho(
      @Valid @RequestBody ValidationExampleBean bean) {
    return bean.toString() + "\n";
  }
}

ValidationExampleBean.java:

package dev.mikoto2000.springboot.validation.workshop.firststep.bean;

import jakarta.validation.constraints.NotNull;
import lombok.Data;

/**
 * ValidationExampleBean
 */
@Data
public class ValidationExampleBean {
  @NotNull
  private String stringValue;
  @NotNull
  private Integer integerValue;
  @NotNull
  private Double doubleValue;
}

カスタムバリデーション

基本のバリデーションで足りない場合、ロジックを自分で書くことになる。 相関チェックや、単項目チェックでもデフォルトで足りないものなど。

  • 相関チェック(クラスレベル制約)
  • カスタムバリデーターの作成

相関チェック(クラスレベル制約)

AssertTrue アノテーションを使用することで、相関チェックも可能。

isXxx メソッドに、 @AssertTrue を付与し、バリデーション結果を true/false で返却する。

package dev.mikoto2000.springboot.validation.workshop.firststep.bean;

import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * CalcInfo
 */
@AllArgsConstructor
@Data
public class CalcInfo {

  @NotNull
  private Double left;
  @NotNull
  private Double right;
  @NotNull
  private Operation operation;

  public enum Operation {
    ADD,
    SUBTRACT,
    MULTIPLY,
    DIVIDE
  }

  /**
   * 割り算はゼロ除算してはいけない。
   */
  @AssertTrue(message = "Division by zero is not allowed.")
  public boolean isValid() {
    // 割り算、かつ、右辺がゼロの場合は不正とする
    if (operation == Operation.DIVIDE && right == 0) {
      return false;
    }
    return true;
  }
}

カスタムバリデーター

デフォルトで提供されているアノテーションでは不十分な場合、自分でアノテーションを作ることもできる。

次の例では Range を拡張し、範囲プラスαの数値を Valid とするアノテーションを使っている。

package dev.mikoto2000.springboot.validation.workshop.firststep.bean;

import dev.mikoto2000.springboot.validation.workshop.firststep.validation.constraints.RangeEx;
import jakarta.validation.constraints.NotNull;
import lombok.Data;

/**
 * BatteryStatus
 */
@Data
public class BatteryStatus {
  // バッテリー残量(0〜100の範囲, ただし、255 は不明とする)
  // 無理矢理感あるが、 IoT 機器とかの API でたまにこういうのがある
  @NotNull
  @RangeEx(min = 0, max = 100, others = {255})
  private Integer batteryLevel;
  // 充電中かどうか
  @NotNull
  private Boolean charging;
  // バッテリーの健康状態
  @NotNull
  private Health health;

  public static enum Health {
    GOOD,
    FAIR,
    POOR
  }
}

カスタムバリデーターの作成

「Bean に付ける制約を表すクラス」と「実際にバリデーションの処理を行うクラス」を作成することで、先ほどのような独自バリデーションを行える。

Bean に付ける制約を表すクラスを作成

RangeEx.java:

package dev.mikoto2000.springboot.validation.workshop.firststep.validation.constraints;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import jakarta.validation.Constraint;
import jakarta.validation.OverridesAttribute;
import jakarta.validation.Payload;
import jakarta.validation.ReportAsSingleViolation;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import org.hibernate.validator.constraints.Range;

import dev.mikoto2000.springboot.validation.workshop.firststep.validation.validator.RangeExValidator;


/**
 * RangeEx。
 */
@Target({
    ElementType.FIELD,
    ElementType.METHOD,
    ElementType.PARAMETER,
    ElementType.ANNOTATION_TYPE,
    ElementType.TYPE_USE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = RangeExValidator.class)
@Documented
@Repeatable(RangeEx.List.class)
@Range
@ReportAsSingleViolation
public @interface RangeEx {

  /**
   * 最小値。
   */
  @OverridesAttribute(constraint = Min.class, name = "value")
  long min() default 0;

  /**
   * 最大値。
   */
  @OverridesAttribute(constraint = Max.class, name = "value")
  long max() default Integer.MAX_VALUE;

  String message() default "{dev.mikoto2000.springboot.validation.workshop.firststep.validation.constraints.RangeEx.message}";

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};

  /**
   * 最大値と最小値範囲以外で許可する値のリスト。
   */
  long[] others();

  @Target({
      ElementType.FIELD,
      ElementType.METHOD,
      ElementType.PARAMETER,
      ElementType.ANNOTATION_TYPE })
  @Retention(RetentionPolicy.RUNTIME)
  @Documented
  @interface List {
    RangeEx[] value();
  }
}
実際にバリデーションの処理を行うクラス作成

RangeExValidator.java:

package dev.mikoto2000.springboot.validation.workshop.firststep.validation.validator;


import java.util.Arrays;

import dev.mikoto2000.springboot.validation.workshop.firststep.validation.constraints.RangeEx;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;

/**
 * RangeExValidator
 */
public class RangeExValidator implements ConstraintValidator<RangeEx, Number> {

  private long min;
  private long max;
  private long[] others;

  @Override
  public void initialize(RangeEx rangeEx) {
    this.min = rangeEx.min();
    this.max = rangeEx.max();
    this.others = rangeEx.others();
  }

  @Override
  public boolean isValid(Number value, ConstraintValidatorContext context) {

    // others に存在しているか確認
    if (Arrays.stream(others).anyMatch(e -> e == value.longValue())) {
      // others に存在しているものは OK
      return true;
    } else {
      // others に存在していない場合、 min, max の範囲チェックを行う
      if (min <= value.longValue() && value.longValue() <= max) {
        // 範囲内であれば OK
        return true;
      } else {
        // 範囲外であれば NG
        return false;
      }
    }
  }
}

エラーメッセージと i18n

エラーメッセージの設定方法は、大きく分けて以下 2 つ。

  • 個別指定(アノテーションで指定)
  • 言語別デフォルト指定

個別指定(アノテーションで指定)

次のように、バリデーション定義のアノテーションに message プロパティを追加することで、個別にエラーメッセージを指定できる。

package dev.mikoto2000.springboot.validation.workshop.firststep.controller;

import org.hibernate.validator.constraints.Length;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import jakarta.validation.constraints.Pattern;

/**
 * EchoController
 */
@RestController
public class EchoController {

  /**
   * 引数を直接バリデーション。
   *
   * @param message 文字列
   *              - 必須ではない
   *              - デフォルト値は "0"
   *              - 1文字以上10文字以下
   *              - 数字のみ
   * @return 引数に改行文字を付与して返す
   */
  @GetMapping("/number-echo")
  public String numberEcho(
      @RequestParam(required = false, defaultValue = "0")
      // 文字列の長さは 1 から 10 とする
      @Length(min = 1, max = 10, message = "1文字以上10文字以下で指定してください")
      // 文字は、正規表現 `[0-9]*` にマッチする
      @Pattern(regexp = "[0-9]*", message = "数字のみで指定してください")
      String message) {
    return message + "\n";
  }
}

デフォルト指定

src/main/resources/ValidationMessages.properties にデフォルトメッセージ定義を記述できる。

jakarta.validation.constraints.AssertFalse.message=不正な値が入力されました。
jakarta.validation.constraints.AssertTrue.message=s不正な値が入力されました。
jakarta.validation.constraints.DecimalMax.message={value}より同じか小さい値を入力してください。
jakarta.validation.constraints.DecimalMin.message={value}より同じか大きい値を入力してください。
jakarta.validation.constraints.Digits.message=整数{integer}桁以内、小数{fraction}桁以内で入力してください。
jakarta.validation.constraints.Future.message=未来の日付を入力してください。
jakarta.validation.constraints.Max.message={value}以下の値を入力してください。
jakarta.validation.constraints.Min.message={value}以上の値を入力してください。
jakarta.validation.constraints.NotNull.message=値を入力してください。
jakarta.validation.constraints.Null.message=未入力でなければいけません。
jakarta.validation.constraints.Past.message=過去の日付を入力してください。
jakarta.validation.constraints.Pattern.message="{regexp}"にマッチしていません。
jakarta.validation.constraints.Size.message={min}から{max}の間の値を入力してください。

org.hibernate.validator.constraints.Email.message=E-mail形式で入力してください。
org.hibernate.validator.constraints.Length.message={min}文字から{max}文字の間で入力してください。
org.hibernate.validator.constraints.NotEmpty.message=値を入力してください。
org.hibernate.validator.constraints.Range.message={min}から{max}の間の値を入力してください。
org.hibernate.validator.constraints.URL.message=不正なURLです。

dev.mikoto2000.springboot.validation.workshop.firststep.validation.constraints.RangeEx.message={min}から{max}の間の値、または{othre}を入力してください。

言語別デフォルト指定

src/main/resources/ValidationMessages_en.propertiessrc/main/resources/ValidationMessages_ja.properties 等を作成することで、言語別のデフォルトメッセージ定義が可能。

出力するメッセージは、リクエストヘッダーの Locale ヘッダーを見て判断される。

バリデーションエラーの返却

バリデーションエラーは、一元管理するのが楽なので、その方法を紹介する。

  • advice によるバリデーションエラー返却の一元化

advice による バリデーションエラー返却の一元化

  • デフォルトではスタックトレースが含まれており、これをよしとしない場合が多い
  • また、バリデーションエラーの構造は全エンドポイントで統一されていることがほとんど
  • @RestControllerAdvice を用いてバリデーションエラー返却の一元化が可能

@RestControllerAdvice の定義

@RestControllerAdvice 内に次の 3 種類のメソッドを追加することで、バリデーション関連エラーの一元化が可能。

package dev.mikoto2000.springboot.validation.workshop.firststep.controller.advice;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.HandlerMethodValidationException;

import dev.mikoto2000.springboot.validation.workshop.firststep.bean.ValidationError;
import dev.mikoto2000.springboot.validation.workshop.firststep.bean.ValidationErrors;
import lombok.extern.slf4j.Slf4j;

/**
 * ValidationExceptionHandler
 */
@Slf4j
@RestControllerAdvice
public class ValidationExceptionHandler {

  /**
   * メソッド引数の単純値のバリデーションエラーを処理するハンドラ。
   * @return ValidationErrors
   */
  @ExceptionHandler(HandlerMethodValidationException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public ValidationErrors handleMethodValidationException(HandlerMethodValidationException e) {

    log.info("handleMethodValidationException: {}", e);

    List<ValidationError> errors = new ArrayList<>();

    for (var error : e.getParameterValidationResults()) {
      String field = error.getMethodParameter().getParameterName();

      List<ValidationError> fieldErrors = error.getResolvableErrors().stream()
          .map(ve -> new ValidationError(field, ve.getDefaultMessage()))
          .toList();

      errors.addAll(fieldErrors);
    }

    return new ValidationErrors(errors);
  }

  /**
   * メソッド引数の bean のバリデーションエラーを処理するハンドラ。
   * @return ValidationErrors
   */
  @ExceptionHandler(MethodArgumentNotValidException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public ValidationErrors handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {

    log.info("handleMethodArgumentNotValidException: {}", e);

    List<ValidationError> errors = e.getFieldErrors().stream()
        .map((error) -> new ValidationError(error.getField(), error.getDefaultMessage()))
        .toList();

    return new ValidationErrors(errors);
  }

  /**
   * シンタックスエラーなど、そもそも正しくないリクエストだった場合に処理するハンドラ。
   * @return ValidationErrors
   */
  @ExceptionHandler(HttpMessageNotReadableException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public ValidationErrors handleMethodArgumentNotValidException(HttpMessageNotReadableException e) {
    log.info("handleMethodArgumentNotValidException: {}", e);

    List<ValidationError> errors = List.of(new ValidationError(null, e.getLocalizedMessage()));

    return new ValidationErrors(errors);
  }
}

まとめ

今回は、以下の項目が行えることを説明してきました。

  • 単項目バリデーション
  • 相関チェックのバリデーション
  • デフォルトメッセージの設定方法
  • 言語別のデフォルトメッセージの設定方法
  • バリデーションエラーの効率の良いハンドリング方法

Spring Boot は、効率よく望んだとおりのバリデーションを行うための仕組みを用意してくれています。 これら機能を活用してどんどん楽をしていきましょう。