Spring Boot에서 데이터의 유효성을 검사하기 위해 Validation 기능을 사용한다. 이 기능은 데이터 전송 객체(DTO)에 주석을 달아 유효성 검사를 정의할 수 있다. 유효성 검사가 필요한 부분에서는 주로 컨트롤러 메소드에서 검사를 수행하고, 유효하지 않은 경우 예외를 통해 처리한다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter-validation'
}
Spring에서 유효성 검사를 수행할 때 사용하는 두 가지 어노테이션인 @Valid와 @Validated가 존재한다. 두 어노테이션은 유사한 목적을 가지고 있지만, 적용되는 범위와 기능에 약간의 차이가 있다.
@ValidJava EE에서 지원해주는 Java Bean Validaion 표준에 포함된 어노테이션으로, Java EE 환경뿐만 아니라 Spring에서도 이 어노테이션을 유효성 검증에 활용한다.
일반적으로 컨트롤러 메소드의 인자 또는 엔티티 클래스에서 유효성 검사를 적용할때 사용한다.
@Valid는 메소드 인자에 적용될 때 해당 인자가 유효한지 검증한다. 만약 유효성 검사를 통과하지 못하면 org.springframework.web.bind.MethodArgumentNotValidException 예외가 발생한다.
@Valid의 동작 원리
모든 요청은 프론트 컨트롤러인 디스패처 서블릿을 통해 컨트롤러로 전달된다. 전달 과정에서는 컨트롤러 메소드의 객체를 만들어주는 ArgumentResolver가 동작하는데,@Valid역시ArgumentResolver에 의해 처리가 된다.
대표적으로@RequestBody는 Json 메세지를 객체로 변환해주는 작업이 ArgumentResolver의 구현체인
RequestResponseBodyMethodProcessor가 처리하며, 이 내부에서@Valid로 시작하는 어노테이션이 있을 경우에 유효성 검사를 진행한다. (이러한 이유로@Valid가 아니라 커스톰 어노테이션인@ValidMangKyu여도 동작한다.) 만약@ModelAttribute를 사용중이라면 ModelAttributeMethodProcessor에 의해@Valid가 처리된다.
출처: https://mangkyu.tistory.com/174 [MangKyu's Diary:티스토리]
import javax.validation.Valid;
import org.springframework.web.bind.annotation.*;
@RestController
public class UserController {
@PostMapping("/users")
public User createUser(@RequestBody @Valid User user) {
// 유효성 검사 통과 후 로직
return user;
}
}
import javax.validation.constraints.*;
public class User {
@NotBlank
private String name;
@Min(18)
private int age;
// getters, setters, etc.
}
@Validated@Validated는 JSR 표준 기술이 아닌 Spring에서 제공하는 어노테이션으로, AOP 기반으로 메소드의 요청을 가로채서 유효성 검증을 진행해준다.
@Validated는 클래스, 인터페이스, 메소드에 적용할 수 있다. 특정 유효성 검사 그룹을 지정할 수 있으므로, 다양한 상황에 맞춰 유효성 검사를 유연하게 조정할 수 있다.
인터페이스에 적용하면 해당 인터페이스의 모든 구현 클래스에 유효성 검사가 적용된다.
유효성 검증에 실패하면 javax.validation.ConstraintViolationException 예외가 발생한다.
@Validated의 동작 원리
특정 ArgumnetResolver에 의해 유효성 검사가 진행되었던@Valid와 달리,@Validated는 AOP 기반으로 메소드 요청을 인터셉터하여 처리된다.@Validated를 클래스 레벨에 선언하면 해당 클래스에 유효성 검증을 위한 AOP의 어드바이스 또는 인터셉터(MethodValidationInterceptor)가 등록된다. 그리고 해당 클래스의 메소드들이 호출될 때 AOP의 포인트 컷으로써 요청을 가로채서 유효성 검증을 진행한다.
이러한 이유로@Validated를 사용하면 컨트롤러, 서비스, 레포지토리 등 계층에 무관하게 스프링 빈이라면 유효성 검증을 진행할 수 있다. 대신 클래스에는 유효성 검증 AOP가 적용되도록@Validated를, 검증을 진행할 메소드에는@Valid를 선언해주어야 한다.
이러한 이유로@Valid에 의한 예외는MethodArgumentNotValidException이며,@Validated에 의한 예외는ConstraintViolationException이다. 이를 알고 있으면 나중에 예외 처리를 할 때 도움이 된다.
출처: https://mangkyu.tistory.com/174 [MangKyu's Diary:티스토리]
import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.*;
import org.springframework.stereotype.Service;
@Service
@Validated
public class UserService {
public void createUser(@Validated(UserChecks.class) User user) {
// 유효성 검사 통과 후 로직
}
}
import javax.validation.constraints.*;
public class User {
@NotBlank(groups = UserChecks.class)
private String name;
@Min(value = 18, groups = UserChecks.class)
private int age;
// getters, setters, etc.
}
public interface UserChecks {
// 유효성 검사 그룹 정의
}
이 외에도 다양한 어노테이션이 존재한다.