Bean Validation 이란?
어노테이션 형태로 Request Body DTO 객체를 쉽게 검증할 수 있게 해주는 표준 검증 사양
사용 방법
라이브러리
- implementation 'org.springframework.boot:spring-boot-starter-validation'
Dto 단위
- 필요한 검증 어노테이션 필드에 추가
public class UserNotNull {
@NotNull(message = "검증 실패 메세지")
private String name;
}
컨트롤러 단위
- @Validated 또는 @Valid 어노테이션 추가
@PostMapping("")
public ResponseEntity test(@RequestBody @Valid UserNotNull userDto) {
[log.info](<http://log.info/>)("userDto: " + userDto);
return ResponseEntity.ok().body("검증 성공");
}
Cf. 검증 실패하는 경우 핸들링
- Bean Validation 에 실패하면 MethodArgumentNotValidException 발생한다.
- 위 Exception 의 기본 에러 메세지는 정확히 어떤 필드가 어떤 조건을 충족 못 했는지 알기 어렵다.
- getBindingResult() 를 통해 세세히 확인할 수 있다.
- ex. {"min":"must be greater than or equal to 1","max":"must be less than or equal to 1"}
@RestControllerAdvice
public class ErrorHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex){
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors()
.forEach(c -> errors.put(((FieldError) c).getField(), c.getDefaultMessage()));
return ResponseEntity.badRequest().body(errors);
}
}
Cf. @Valid, @Validated 차이
- @Valid
- 요구 사항 케이스에 따라 검증할 수 없음
- 모든 필드를 검증할 때 이용
- @Validated
- groups 개념으로 위 @Valid의 단점을 보완
- 특정 group 에 포함된 일부 필드 만을 검증
- @Validated 를 쓰는 경우 group 을 지정하지 않으면 valid 로 간주
어노테이션 종류
1. 숫자 범위
@Min, @Max, @DecimalMin, @DecimalMax
- @Min(n): n 이상이어야 한다.
- @Max(n): n 이하여야 한다.
- @DecimalMin("n"): n 이상이어야 한다.
- @DecimalMax("n"): n 이하여야 한다.
- null 도 valid 로 간주함
- 사용처
- BigDecimal, BigInteger, CharSequence, byte, short, int, long
- Double, Float 타입은 rounding error 때문에 사용 불가
- Cf. @Min, @DecimalMin 차이는?
- @DecimalMin() 인자에는 int, Long 범위 이상의 값(BigInteger) 넣을 수 있음
Long value1 = 9999999999999999999L; : 컴파일 에러 O BigInteger value = new BigInteger("999999999999999999"); : 컴파일 에러 X
@Positive, @PositiveOrZero, @Negative, @NegativeOrZero
- null 도 valid 로 간주함
- @Positive: 양수여야 한다. (n > 0)
- @PositiveOrZero: 0 또는 양수여야 한다. (n >= 0)
- @Negative: 음수여야 한다. (n < 0)
- @NegativeOrZero: 0 또는 음수여야 한다. (n <= 0)
- 사용처
- BigDecimal, BigInteger, CharSequence, byte, short, int, long, double, float
@Digits
- @Digits(integer = n, fraction = m)
- null 도 valid 로 간주함
- 최대 정수 자리 수 n개, 최대 소수 자리 수 m개
- 사용처
- BigDecimal, BigInteger, CharSequence, byte, short, int, long
2. 시간
@Past, @PastOrPresent, @Future, @FutureOrPresent (이슈)
- null 도 valid 로 간주함
- @Past: Now 보다 과거
- @PastOrPresent: Now 또는 Now 보다 과거
- @Future: Now 보다 미래
- @FutureOrPresent: Now 또는 Now 보다 미래
- Now 기준: ClockProvider의 가상 머신에 따라 현재 시간을 정의
- 사용처
- java.util.Date java.util.Calendar
- java.time.Instant java.time.LocalDate
- java.time.LocalDateTime java.time.LocalTime
- java.time.MonthDay java.time.OffsetDateTime
- java.time.OffsetTime java.time.Year
- java.time.YearMonth
- java.time.ZonedDateTime
- java.time.chrono.HijrahDate
- java.time.chrono.JapaneseDate
- java.time.chrono.MinguoDate
- java.time.chrono.ThaiBuddhistDate
3. Not ~
@NotNull, @NotEmpty, @NotBlank
- @NotNull
- null 이 아니어야 한다.
- "", " " 가능
- @NotEmpty
- 길이가 0 이상이고, null 이 아니어야 한다.
- " " 가능
- 사용처
- CharSequence, Collection, Map, Array
- @NotBlank
- 공백 문자를 제외한 문자가 1개 이상 있고, null 이 아니어야 한다.
- " " 불가능
- 사용처
- CharSequence
4. 패턴
@Size(min = n, max = m)
- null 도 valid 로 간주함
- 해당 객체 내용의 길이, 개수를 검증
- n 이상 m 이하 (디폴트 0 <= x <= 2147483647)
- 사용처
- CharSequence: 문자열 길이 / Collection, Map, Array: 원소 길이
@Email (이슈)
- null 도 valid 로 간주함
- 문자열 사이(맨 앞, 맨 끝 X)에 @가 존재해야 한다.
- 사용처
- CharSequence
@Pattern
- null 도 valid 로 간주함
- 지정한 정규식과 대응되는 문자열이어야 한다.
- 사용처
- CharSequence
5. Boolean
@AssertTrue, @AssertFalse
- @AssertTrue: true 여야 한다.
- @AssertFalse: false 여야 한다.
- 사용처
- Boolean
Custom Validation 만들기
ConstraintValidator 이용
- Interceptor 단위에서 검증 진행
- AOP 에러 핸들링 가능
적용 방법
- 어노테이션 생성
@Constraint(validatedBy = UniqueEmailValidator.class)
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface UniqueEmail {
String message() default "이미 존재하는 이메일입니다";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
- ConstraintValidator 를 상속 받아 검증 로직 작성
public class UniqueEmailValidator implements ConstraintValidator<UniqueEmail, String> {
@Override
public void initialize(UniqueEmail constraintAnnotation) {}
@Override
public boolean isValid(String email, ConstraintValidatorContext context) {
return email.equals("중복이메일") ? false : true;
}
}
- Dto 객체 필드에 어노테이션 추가
@UniqueEmail
private String alreadyExistEmail;
소스 코드
- 검증 어노테이션 별 테스트 코드 작성
Ref.
- NotNull, NotBlank, NotEmpty
- Jakarta Bean Validation API 2.0.2
- Jakarta-bean-validation-spec-3.0
- Javax-validation
- 더 많은 Annotaition
- @Valid, @Validated
- Custom validation
'Dev > Spring Boot' 카테고리의 다른 글
[Validation] @Past, @FutureOrPresent LocalDateTime 타입 검증 이슈 (2) | 2022.07.17 |
---|---|
[Validation] 정규식 여부에 따른 @Email 동작 이슈 (0) | 2022.07.17 |
[Gradle] finalizedBy 개념 (0) | 2022.04.04 |
JUnit4 기반 Spring Rest Docs 작성 방법 (0) | 2022.03.22 |
application.yml 위치 변경하기 (0) | 2022.02.17 |