bong-u/til

Spring - Bean Validation : Annotation으로 Validation하기

수정일 : 2024-11-15

Bean Validation

  • Annotation을 달아서 Validation을 수행할 수 있다.
  • 주로 jakarta.validation과 hibernate.validator 두 패키지를 사용한다.
  • Dependency Diagram 구조

    spring-boot-starter-validation -> hibernate-validator -> jakarta.validation-api

jakarta.validation에서 지원하는 annotation

Annotation Description
@NotNull null이 아닌가 ("", " " => 통과)
@NotEmpty null이 아니고, size가 0인가 (" " => 통과)
@NotBlank null이 아니고, trim한 결과가 empty인가
@Size 문자열, 배열의 길이가 해당 범위에 있는가
@Min 숫자가 해당 범위에 있는가
@Max 숫자가 해당 범위에 있는가
@Email 이메일 형식에 맞는가
@Pattern Regex(정규식)에 맞는가
@Past 과거의 날짜인가
@Future 미래의 날짜인가
@Digits 정수, 소수 자릿수가 해당 범위에 있는가
@DecimalMin, @DecimalMax 자릿수가 해당 범위에 있는가 (소수 이하 자릿수 포함)
@Positive, @PositiveOrZero, @Negative, @NegativeOrZero

hibernate.validator에서 지원하는 annotation

Annotation Description
@Range 숫자가 해당 범위에 있는가 (소수 이하 자릿수 포함)
@Length 문자열, 배열의 길이가 해당 범위에 있는가
@URL URL 형식에 맞는가
  • 언급한 Annotation말고 다른 Annotation도 있다.

Rest Controller에서 사용

  • Controller

    1public ResponseEntity<Customer> postCustomer(@RequestBody @Valid CustomerDTO customerDTO) {...}
    
    • @Valid Annotation을 붙여서 CustomerDTO 객체에 대한 Validation을 수행한다
    • @Valid Annotation을 붙이는 것을 깜빡하지 말자
  • 예외 처리

    • 위 코드의 Validation에서 실패하면, MethodArgumentNotValidException이 발생한다
    • 해당 예외는 필드별 모든 에러를 담고 있다
    • 그대로 반환하면 엄청 길기 때문에, 보통 아래 코드와 같이 필요한 정보만 추출해서 반환한다
      1processValidationErrors(MethodArgumentNotValidException e) {
      2    List<String> errors = e.getBindingResult().getFieldErrors().stream()
      3                            .map(error -> error.getField() + ": " + error.getDefaultMessage())
      4                            .collect(Collectors.toList());
      5    return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
      6}
      

수동 Validation

  • Controller에서 Validation을 수행하지 못하는 경우, 수동으로 Validation을 수행할 수 있다
  • 이때, Validator 객체를 주입받아서 사용한다
    1import jakarta.validation.Validator;
    2...
    3@Autowired
    4private Validator validator;
    5...
    6var violations = validator.validate(voucher);
    7if (!violations.isEmpty())
    8    throw new IllegalArgumentException(violations.stream().findFirst().get().getMessage());
    
  • 코드에서는 voucher 객체에 대한 Validation을 수행하고, 발생한 에러가 있다면 IllegalArgumentException을 발생시킨다