👀 들어가기 앞서
이번에 프로젝트를 진행하다가 DTO와 객체에 대한 유효성 검증을 어떻게 할까 많이 고민했다.
별도로 검증하는 클래스를 만들자니 대상이 많이 없어서 괜히 구현하면 의존성만 커질 것 같았다.
그래서 Annotation을 구현해서 검증을 해보도록 했다.
🤔 왜 사용했나요?
커스텀 어노테이션은 양날의 검이라고 생각한다. 덕지덕지 붙은 어노테이션 불호..!
어노테이션을 까보지 않는 이상 어떤 의도로 동작하는지 정확하게 알 수 없기 때문이다!
하지만 간결함이 큰 강점이기 때문에 고민했다.
이메일을 후보키처럼 사용해 많은 로직에 이메일을 요구했는데, 검증용 클래스가 그만큼 여러 곳에서 사용되었다.
커스텀을 통해서 검증 클래스를 없애 의존성을 줄이고, 서비스 계층에 들어오기 전에 처리하고 싶었다.
추가적으로 특별히 사용하는 이메일 양식이 있었기 때문에 충분히 구현할만하다고 생각했다.
🪄 @Valid와 @Validated
커스텀 어노테이션을 만들기 앞서 "검증을 진행해!"라고 메세지를 던져줄 두 어노테이션에 대해서 알아야 한다.
어떤 차이가 있고 어떻게 동작하는지 가볍게 알아보자.
🌀Valid
빈 검증기를 통해서 조건을 검증하는 자바 진영의 유효성 검사기이다.
Spring에서는 LocalValidatorFactoryBean
을 통해서 검증하는데 아래 의존성을 추가해 주면 된다.
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-validation'
사용할 DTO의 필드에 어노테이션을 붙여주고 컨트롤러에 @Valid
를 붙여주면 검증을 해준다.
// DTO
public class TestDTO {
@Email
private String email;
...
}
// Controller
@RequestStatus(OK)
@PostMapping("/test")
public ResponseEntity test(@RequestBody @Valid TestDTO testDTO) {
...
}
💡 동작
모든 요청은 프론트 컨트롤러에서 처리되는데, 프론트 컨트롤러 내부의 ArgumentResolver
에서 처리된다.
검증 오류 시 MethodArgumentNotValidException
예외를 던지고,
프론트 컨트롤러에 등록된 DefaultHandlerExceptionResolver
에서 400 Error
를 발생시킨다.
🌀Validated
@Valid
와 다르게 스프링 진영에서 제공하는 어노테이션이다.
컨트롤러 계층에서 유효성 검증을 처리하는 게 좋지만 그럴 수 없는 상황에 사용한다.
클래스에 어노테이션을 붙여주고 @NotNull
이나 @Size
같은 검증용 어노테이션을 붙여주면 끝이다!😋
@Servie
@Validated
public class TestService {
public void test(@NotBlank String name) {
...
}
}
💡 동작
스프링 기반답게 @Validated
는 AOP 기반으로 요청을 인터셉트해서 처리한다.
@Validated
를 선언한 클래스에 AOP의 어드바이스(혹은 인터셉터)가 추가되어 메서드가 호출될 때 가로채서 검증한다.
계층에 관계없이 스프링 빈이라면 모두 검증할 수 있고, 검증 오류 시 ConstraintViolationException
예외를 던진다.
😋 정리
- @Valid
- 자바 진영의 유효성 검사기
- 프론트 컨트롤러의
ArgumentResolver
가 검증한다. 즉, 컨트롤러 계층에서만! - 검증 실패 시
MethodArgumentNotValidException
예외 발생
- @Validated
- 스프링 진영의 유효성 검사기
- AOP 기반으로 요청이 발생할 때 인터셉트해서 검증한다. 즉, 계층에 영향이 없다!
- 검증 실패 시
ConstraintViolationException
예외 발생
2편에서 계속...
-Reference https://chat.openai.com/chat
😋 지극히 개인적인 블로그지만 훈수와 조언은 제 성장에 도움이 됩니다 😋
'Web > Spring' 카테고리의 다른 글
[Spring] @ModelAttribute (2) | 2023.04.19 |
---|---|
[Spring] @Valid, @Validated과 Custom Annotation (2) (0) | 2023.03.21 |
[토비의 스프링] 테스트 (2장) (0) | 2023.01.16 |
[토비의 스프링] 오브젝트와 의존관계 (1장) (0) | 2022.12.21 |
[Spring] AOP (feat. Proxy Pattern) (0) | 2022.09.21 |
댓글