시작하기에 앞서, 아래의 사진을 보자.. 정말 끔찍하다. 부끄럽지만 직전 프로젝트에서 실제로 작성했던 코드다.
위 코드는 @RequestBody
요청 객체를 검증하기 위함이었는데, 이런식으로 요청 객체를 처리하다보니 반복되는 코드가 너무 많았고 가독성도 심히 좋지 않았다. 그에 따라 다음과 같은 고민을 하게 되었다.
조금 더 멋지게(?), 깔끔하게 요청을 검증하는 코드를 작성할 수 있는 방법이 없을까?`
코드를 좀 더 섹시하게 작성하고 싶다!
그래서 찾은 것이 @Valid
어노테이션이다. 먼저 아래의 사진을 보면 그 차이를 확연히 볼 수 있다. 반복되는 if
에서 탈출하고, 훨씬 깔끔해졌다!
@Valid?
위 사진은 @Valid
어노테이션을 캡쳐한 화면이다. 주석을 해석해보자면 대충 다음과 같은 내용이며 메서드, 필드, 생성자, 파라미터 등에 사용할 수 있다.
개체와 해당 속성에 정의된 제약 조건을 통해 속성, 메서드 매개 변수 또는 메서드 반환 유형을 검증한다.
사용 방법
먼저 build.gradle
에 다음과 같은 의존성을 추가해준다.
implementation 'org.springframework.boot:spring-boot-starter-validation'
참고!
SpringBoot가 버전업을 하면서 기존에는 springboot-web
의존성안에 있던 constraints package
(앞서 언급했던)가 아예 모듈로 빠졌다고 한다.
그 다음, @RequestBody가 선언된 파라미터에 @Valid를 선언해주면, @RequestBody로 들어오는 객체에 대한 검증을 수행하게 된다.
이때, 검증을 수행할 제약 조건은 앞서 언급한 어노테이션들을 이용해서 아래 사진과 같이 지정해주면 된다. message
속성을 통해 검증을 통과하지 못했을 때 출력할 메시지를 지정해줄 수도 있다.
참고!
@Valid의 유효성 검증을 통과하지 못하면 MethodArgumentValidException
이 발생한다. 그러니까, @RestControllerAdvice
와 함께 @ExceptionHandler
등을 적절하게 사용하면 펀쿨섹하게(?) 예외 처리를 할 수 있다!
참고자료 - @RestControllerAdvice를 사용해보자
제약 조건
위 사진은 앞의 @Valid
가 포함되어 있는 javax.validation
패키지의 일부이다. constraints
내부에 제약조건을 지정할 수 있는 다양한 어노테이션들이 있다. 이름만 봐도 의미를 알기 쉽게 잘 구성되어 있지만 간단하게 짚고 넘어가도록 하겠다(자세한 내용은 직접 뜯어보면서 확인해보시라!).
@AssertFalse
- 지원 타입 : Boolean, boolean
- 제약 조건 : null을 허용하며, 값이 false 여야 한다.
@AssertTrue
- 지원 타입 : Boolean, boolean
- 제약 조건 : null을 허용하며, 값이 true 여야 한다.
@DecimalMax
- 지원 타입
- BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long, and their respective wrappers
- double, float 타입은 반올림 오류로 인해 지원하지 않는다.
- 제약 조건 : null을 허용하며, 지정된 maximum 값 보다 값이 작거나 같아야 한다.
@DecimalMin
- 지원 타입
- BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long, and their respective wrappers
- double, float 타입은 반올림 오류로 인해 지원하지 않는다.
- 제약 조건 : null을 허용하며, 지정된 minimum 값 보다 값이 크거나 같아야 한다.
@Digits
- 지원 타입
- BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long, and their respective wrappers
- 제약 조건 : null을 허용하며, 자릿수가 지정된 허용 범위 내여야 한다.
@Email
- 지원 타입
- 제약 조건 : 문자열이 올바른 형식의 이메일 주소여야 하며, null을 허용한다.
@Future
- 지원 타입
- Date
- Calendar
- Instant
- LocalDate
- LocalDateTime
- LocalTime
- ...
- 제약 조건 : null을 허용하며, 현재보다 미래의 시간이어야 한다.
@FutureOrPresent
- 지원 타입
- Date
- Calendar
- Instant
- LocalDate
- LocalDateTime
- LocalTime
- ...
- 제약 조건 : null을 허용하며, 현재와 같거나 미래의 시간이어야 한다.
@Max
- 지원 타입
- BigDecimal
- BigInteger
- byte, short, int, long, and their respective wrappers
- double, float 타입은 반올림 오류로 인해 지원하지 않는다.
- 제약 조건 : null을 허용하며, 지정된 maximum 값보다 값이 작거나 같아야 한다.
@Min
- 지원 타입
- BigDecimal
- BigInteger
- byte, short, int, long, and their respective wrappers
- double, float 타입은 반올림 오류로 인해 지원하지 않는다.
- 제약 조건 : null을 허용하며, 지정된 minimum 값보다 값이 크거나 같아야 한다.
@Negative
- 지원 타입
- BigDecimal
- BigInteger
- byte, short, int, long, and their respective wrappers
- 제약 조건 : null을 허용하며, 음수여야 하고 0은 허용하지 않는다.
@NegativeOrZero
- 지원 타입
- BigDecimal
- BigInteger
- byte, short, int, long, and their respective wrappers
- 제약 조건 : null을 허용하며, 음수여야 하고 0도 허용한다.
@NotBlank
- 지원 타입
- 제약 조건 : null을 허용하지 않으며, 공백이 아닌 1자리 이상의 문자열을 포함해야 한다.
@NotEmpty
- 지원 타입
- CharSequence (length of character sequence is evaluated)
- Collection (collection size is evaluated)
- Map (map size is evaluated)
- Array (array length is evaluated)
- 제약 조건 : null을 허용하지 않으며, empty가 아니어야 한다.
@NotNull
- 지원 타입
- 제약 조건 : null이 아니어야 한다.
@Null
- 지원 타입
- 제약 조건 : null이어야 한다.
@Past
- 지원 타입
- Date
- Calendar
- Instant
- LocalDate
- LocalDateTime
- LocalTime
- ...
- 제약 조건 : null을 허용하며, 현재보다 과거의 시간이어야 한다.
@PastOrPresent
- 지원 타입
- Date
- Calendar
- Instant
- LocalDate
- LocalDateTime
- LocalTime
- ...
- 제약 조건 : null을 허용하며, 현재와 같거나 과거의 시간이어야 한다.
@Pattern
- 지원 타입
- 제약 조건 : null을 허용하며, 지정된 패턴(정규식)에 부합해야 한다.
@Positive
- 지원 타입
- BigDecimal
- BigInteger
- byte, short, int, long, float, double, and their respective wrappers
- 제약 조건 : null을 허용하며, 양수여야 하고 0은 허용하지 않는다.
@PositiveOrZero
- 지원 타입
- BigDecimal
- BigInteger
- byte, short, int, long, float, double, and their respective wrappers
- 제약 조건 : null을 허용하며, 양수여야 하고 0도 허용한다.
@Size
- 지원 타입
- CharSequence (length of character sequence is evaluated)
- Collection (collection size is evaluated)
- Map (map size is evaluated)
- Array (array length is evaluated)
- 제약 조건 : null을 허용하며, 해당 요소의 평가대상이 지정된 size 값의 범위 내에 포함되어야 한다.
참고자료