티스토리 뷰
Bean Validation
Bean Validation
은 엔터프라이즈 레벨의 애플리케이션 개발시 자주 반복되는 유효성 검사 패턴을 정리한 Java EE 표준이다. 레드햇, 오라클 등 세계 굴지의 IT 기업에 종사하는 전문가 집단이 참여하여 표준을 만들었다. 인터페이스를 잘 이해하고 구현체를 활용하면 소스 코드의 가독성을 높아지고 많은 코드를 절약할 수 있다.- 1.0(JSR 303)이 최초 버전으로 2009-10-12 발표되었다. [스펙 링크]
- 1.1(JSR 349)가 2013-04-10 발표되었다. [스펙 링크]
- 2.0(JSR 380)이 현재 최신 버전으로 2017-08-03 발표되었다. Java 8이 요구되며 그 밑의 버전은 지원하지 않는다. [스펙 링크]
- JSR 380 스펙의 인터페이스는 javax.validation 그룹의
validation-api
아티팩트에서 확인할 수 있다. [메이븐 저장소 링크] 인터페이스에 대한 대표적인 구현체로는 org.hibernate.validator 그룹의hibernate-validator
아티팩트가 있다. [메이븐 저장소 링크] Spring Boot 2.0 기반의 프로젝트라면 이미 둘다 적용되어 있어 따로 종속성 관리를 할 필요가 없다. - Spring Boot에서의 사용법은 무척 간단하다. 컨트롤러 메써드의 파라메터 레벨에 JSR 380이 제공하는
@Valid
어노테이션만 명시하면 된다.
목표
- 컨트롤러 메써드의
@PathVariable
,@RequestParam
요청 파라메터에 대해 JSR-380 유효성 검사를 수행한다. - 컨트롤러 메써드의 POJO 요청 클래스에 대해 JSR-380 유효성 검사를 수행한다.
요청 클래스
- 클라이언트로부터의 요청 파라메터를 담을 클래스를 아래와 같이 작성한다.
- 필드 레벨에 JSR 380이 제공하는 유효성 검사 어노테이션을 명시하면 자동으로 유효성 검사를 수행해준다.
- 필드 타입에 Nullable 조건을 추가해야 누락된 파라메터에 대해서 정상적으로 유효성 검사를 수행할 수 있다. Nullable 조건 없는 필드 타입의 파라메터를 생략할 경우, org.springframework.beans.BeanInstantiationException(내부적으로는 IllegalArgumentException: Parameter spectified as non-null is null) 예외가 발생한다. 또한, 문자열 타입의 파라메터의 경우
@NotNull
이 아닌@NotEmpty
조건을 명시해야 유효성 검사가 가능하다. (@NotNull은 무시된다.) @AssertTrue
는 JSR 380이 제공하지 않는 별도의 유효성 검사를 작성하고자 할 경우 사용할 수 있다.- 한편, JSR 380은 유효성 검사 실패시
message
속성에 단일 메시지만 전달할 수 있어, error_code, error_message가 한쌍을 이루는 현대적인 REST API의 응답 설계와는 어울리지 않는 면이 있다. API 응답을 받는 클라이언트 입장에서는 인간 친화적인 error_message만 받는 것 보다는, error_code를 받는 편이 코드 레벨로 오류를 식별하고 처리하기 직관적이기 때문이다. 이를 극복하기 위해, message 속성에는 error_code만 명시하고 이에 맵핑되는 error_message를 별도로 정의한 후 아래 설명할@ControllerAdvice
를 통해 별도의 오류 응답 로직을 작성하는 방법을 추천한다.
@ControllerAdvice
- 유효성 검사의 결과가 여과없이 클라이언트에게 노출되는 것을 방지하기 위해 컨트롤러 어드바이스 클래스를 아래와 같이 작성한다.
- 컨트롤러에서 유효성 검사 실패시 발생하는 예외는 2가지가 있다. 메써드 레벨에 @RequestBody가 명시되었을 경우(주로 POST, PUT 요청)
MethodArgumentNotValidException
예외가 발생한다. 메써드 레벨에 @RequestBody가 명시되어 있지 않을 경우(주로 GET 요청) @ModelAttribute가 기본 적용되어BindException
이 발생한다. 따라서 2가지 경우에 대한 예외 처리를 작성하면 입맛에 맞는 커스텀 오류 응답을 클라이언트에게 제공할 수 있다 [관련 링크] - 위 예제는 전체 컨트롤러 동작에 영향을 끼치는 전역 유효성 검사 로직이라고 할 수 있다. 만약, 유효성 검사의 범위를 특정 단일 컨트롤러로 국한하고 싶다면 해당 컨트롤러 내부에 처리 메써드를 작성하고
@ExceptionHandler
를 명시하면 된다. 유효성 검사의 범위를 2개 이상의 복수개의 컨트롤러에 국한하고 싶다면 위 예제에서@ControllerAdvice(assignableTypes = [FooController::class, BarController::class])
와 같이 변경하면 된다.
@RestController
- 컨트롤러 클래스를 아래와 같이 작성한다.
- 요청 파라메터 앞에 명시한
@Validated
가 유효성 검사를 활성해주는 역할을 한다. (@Valid
를 명시해도 된다.)
GET 요청 파라메터를 POJO로 처리하기
- 컨트롤러 클래스에서 GET 요청 파라메터는 일반적으로 메써드 아규먼트 레벨에서 @RequestParam으로 직접 받아 처리하는 것이 일반적이다. 이 경우, Bean Validation을 적용하려면 제약이 많아, 앞서 POST 요청에서와 같이 POJO로 처리하게 되면 이점이 많아진다.
- 이 경우, 한가지 제약사항이 있는데 Spring MVC는 요청 파라메터명을 무조건 camelCase(ex: fooBar)로만 받을 수 있기 때문에, 다른 네이밍 컨벤션을 사용할 수 없게 된다. 이를 해결하기 위해 원하는 컨벤션으로 요청 파라메터명을 받아 camelCase로 변경하는 커스텀 필터를 제작하면 제약에서 자유로워진다. 커스텀 필터 제작 방법은 아래와 같다.
@RequestParam, @PathVariable 유효성 검사하기
- 앞서 예제를 통해 POJO의 경우 JSR-380의 유효성 검사가 완전히 가능함을 확인했다. 문제는 컨트롤러의 메써드 파라메터로 바로 작성하는
@RequestParam
,@PathVariable
이다. JSR-380을 적용하려면 아래와 같은 접근 방법이 요구된다.
- 반드시 컨트롤러 클래스 레벨에
@Validated
를 명시해야 유효성 검사가 작동한다. 메써드의 파라메터 레벨에는 명시해도 작동하지 않는다. (참고로 Java EE 표준 어노테이션인 @Valid는 클래스 레벨에 명시가 불가능하여 본 기능에는 사용할 수 없다.) - 파라메터 레벨에서는 앞서와 다르게 유효성 검사 오류시
javax.validation.ConstraintViolationException
예외를 발생시킨다. 위 예제와 같이 전역 또는 해당 컨트롤러에서@ExceptionHandler
를 작성하여 적절한 오류 응답 로직을 작성하면 된다.
요청 DTO에 대한 Enum 타입 필드 유효성 검사하기
- 요청 DTO의 필드에 Enum 타입이 포함되었을 경우 유효성 검사 방법은 직관적이지는 않지만 가능한 방법이 있다. 먼저 아래는 Enum 클래스의 작성 예이다.
- Spring Boot는 정의되지 않은 Enum 코드가 JSON 필드 값에 들어올 경우, 파씽 오류와 함께
HttpMessageNotReadableException
예외를 발생시킨다. 위와 같이,@JsonCreator
을 부여하면 파씽 오류 부분을 제어할 수 있는데 위의 경우 파씽 오류시 의도적으로 FooBarException이라는 특정 예외를 발생시키도록 작성했다. - 위와 같이 의도한 예외를 발생시켜도, HttpMessageNotReadableException 예외가 발생하는 것에는 변함이 없다. 아래와 같이 HttpMessageNotReadableException 예외를 처리하는
@ExceptionHandler
작성이 필요하다.
- HttpMessageNotReadableException 예외가 발생해도, 최초의 조상이 되는 예외는 앞서 의도적으로 발생시킨 FooBarException가 된다. 이를 이용해 원하는 오류 응답 처리를 수행하도록 코드를 작성할 수 있다.
참고 글
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 로드 바이크
- graylog
- 구동계
- bootstrap
- Spring MVC 3
- CentOS
- JHipster
- java
- spring
- kotlin
- chrome
- Eclipse
- 평속
- jsp
- 로드바이크
- jstl
- Docker
- Kendo UI
- Kendo UI Web Grid
- 태그를 입력해 주세요.
- DynamoDB
- Spring Boot
- jpa
- node.js
- 자전거
- maven
- 알뜰폰
- JavaScript
- MySQL
- Tomcat
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
글 보관함