티스토리 뷰
[SpringBoot] 스프링 부트3.2(SpringBoot3.2)에 추가된 유효성 검사 기능(MethodValidator) 파헤치기
망나니개발자 2024. 7. 9. 10:00
1. 스프링 부트3.2에 추가된 유효성 검사 기능(MethodValidator) 파헤치기
[ 스프링 부트3.2에 추가된 유효성 검사 기능 파헤치기 ]
스프링 부트 2를 기준으로, 사용 가능한 유효성 검사 방법이 크게 2가지 종류가 있었다.
- 컨트롤러에서 @Valid를 활용하기
- 컨트롤러가 아닌 곳에서 @Validated + @Valid 활용하기
앞선 포스팅에서 자세히 살펴볼 수 있듯이, 컨트롤러에서 @Valid를 활용하면 ArgumentResolver를 활용하여 컨트롤러 객체로 넘겨줄 파라미터를 생성할 때 유효성 검사가 진행된다. 따라서 컨트롤러가 아닌 다른 계층에서는 추가적으로 클래스 선언에 @Validated를 추가해주어야 한다. 그러면 AOP가 적용되어 유효성 검사를 진행하게 된다.
컨트롤러에서 @Valid를 동작하는 방식이 ArgumentResolver 내부에서 검사를 진행하기 때문에, 다음과 같은 유효성 검사가 불가능하였다.
@RestController
class HelloController {
@GetMapping("/hello")
public String hello(@RequestParam @Length(min = 10) String name){
return name;
}
}
이로 인해 @Valid가 동작하는 방식과 이를 바탕으로 적용되는 케이스와 되지 않는 케이스를 구분할 필요가 있었다. 하지만 스프링 부트3에서는 유효성 검사가 동작하는 새로운 방식이 추가되었는데, 이에 대해 알아보도록 하자.
[ 스프링 부트3 에서 추가된 유효성 검사 방법 ]
새로운 유효성 검사 기능(MethodValidator)의 동작 원리
스프링 부트3(엄밀히는 스프링 6.1)부터 Spring MVC와 WebFlux에서 유효성 검사를 위한 @Constraint 관련 애노테이션을 기본적으로 지원하도록 개선되었다. 이에 대해 자세히 살펴보도록 하자.
스프링은 요청이 오면, RequestMappingHandlerAdapter를 통해 요청을 위임할 컨트롤러와 메서드를 탐색한다. 그리고 컨트롤러 메서드 호출을 위해 필요한 정보들을 감싸서 실제 호출을 위임한다. 보다 자세한 내용은 다음의 포스팅에서 참고하도록 하자.
이러한 상황에서 스프링은 유효성 검사 기능을 고도화하기 위해 RequestMappingHandlerAdapter에 유효성 검사를 위한 Validator를 등록해두고, 컨트롤러 메서드 호출 시에 유효성 검사를 진행하도록 개선하였다. 보다 자세히 설명하면, 컨트롤러를 위한 파라미터를 생성하는 ArgumentResolver들이 모두 동작하고, 컨트롤러의 메서드 호출이 준비되었을 때 유효성 검사가 진행된다. 스프링은 이를 MethodValidator라고 부른다.
새로운 유효성 검사 기능(MethodValidator) 사용법
스프링의 MethodValidator 관련 기능을 활용하기 위해서는 다음의 조건들이 충족되면 된다.
- 컨트롤러에 @Validated를 통한 AOP 기반 검증이 존재하지 않음
- LocalValidatorFactoryBean와 같은 jakarta.validation.Validator 타입의 빈이 등록됨
- 메서드 파라미터에 유효성 검증 애노테이션이 붙어있음
jakarta.validation.Validator 타입의 빈 등록을 위해서는 다음의 의존성만 추가해주면 자동 구성(AutoConfiguration)되므로, 다음의 의존성을 추가해주도록 하자.
implementation("org.springframework.boot:spring-boot-starter-validation")
이를 통해 기존에는 불가능했던 다음과 같은 방식으로도 동작이 가능해진다. 대표적으로 @RequestParam에도 바로 유효성 검증을 적용할 수 있는 것이다. 왜냐하면 파라미터가 모두 준비된 이후에, 파라미터에 붙어 있는 유효성 검사 애노테이션을 파싱하여 유효성 검사를 진행하기 때문이다.
@RestController
class HelloController {
@GetMapping("/hello")
public String hello(@RequestParam @Length(min = 10) String name){
return name;
}
}
참고 자료