[검증]@Valid ? @Validated ?

2024. 10. 23. 21:29SPRING

검증이 필요한 이유 :

프로그램은 지정한 내용에 한해서 요청 처리가 가능하다.

하지만 세상은 넓고 이상한 요청은 많은 법.

 

이상한 요청이 들어왔을 때, 처리할 수도 없을 뿐더러,

요청에 대한 예외처리가 제대로 안 돼 있다면 바로 오류 -> 에러로 이어진다.

 

따라서, 검증은 개발에 있어 필수 덕목과 같다.

 

실습 환경 :

 - java17

 - spring 3.2

 


@Valid

@Valid는 JSR-303 표준 스펙이다.

Bean Validator 를 이용해 객체의 제약 조건을 검증하도록 지시하는 애노테이션이다.

 

JSR 표준 빈 검증 기술의 특징

= 객체의 필드에 달린 애노테이션으로 편리하게 검증한다.

@Getter
@RequiredArgsConstructor
public class AddUserRequest {

	@Email
	private final String email;

	@NotBlank
	private final String pw;

	@NotNull
	private final UserRole userRole;

	@Min(12)
	private final int age;

}

출처: https://mangkyu.tistory.com/174 [MangKyu's Diary:티스토리]

검증이 필요한 객체에 필요한 애노테이션과 속성값을 입력 후,

 

컨트롤러의 메서드에 @Valid 선언 시 검증이 진행된다.

@PostMapping("/user/add") 
public ResponseEntity<Void> addUser(@RequestBody @Valid AddUserRequest addUserRequest) {
      ...
}

출처: https://mangkyu.tistory.com/174 [MangKyu's Diary:티스토리]

 

@Valid 동작 원리

 

클라이언트 요청 응답 전달 순서

클라이언트 -  요청 발생 - 디스패처 서블릿(프론트 컨트롤러) - 컨트롤러 - 서비스
- 컨트롤러 - 디스페처 서블릿 - 클라이언트

 

  1. 클라이언트가 요청을 만들어 전송
  2. 디스패처 서블릿에서 header, api 의 정보를 읽고 해당 요청을 처리할 수 있는 컨트롤러 호출.
  3. 이 때, 요청값 컨트롤러가 제대로 처리할 수 있도록, 요청에 담긴 값을 개발자 개발 객체로 만들어주는 작업이 진행된다.
    ex) 클라이언트 JSON 데이터 -변환-> 서버 객체
  4. 이러한 작업은 ArgumentaResolver(인터페이스) 가 처리한다. (본 글에서의 구현체는 RequestResponseBodyMethodProcessor)
  5. '@Valid' 로 시작하는 애노테이션이 있는 경우 검증이 시작되는 모양이다. 
  6. 검증에 오류가 있다면, MethodArgumentNotValidException 예외가 발생.
  7. 디스 패처 서블릿이 가지고 있는 예외 리졸버(Exception Resolver)인 DefaultHandlerExceptionResolver 가 400 BadRequest 에러를 발생시킨다.

즉. @Valid는 '컨트롤러에서만 동작한다.'

다른 계층(서비스)에서 파라미터를 검증하기 위해 @Validated 가 존재한다.

 


@Validated

입력 파라미터의 유효성 검증은 컨트롤러에서 최대한 처리하는 것이 좋다.

어차피  유효하지 않은 데이터라면 불필요한 작업은 필요 없기 때문이다.

컨트롤러 - 서비스(검증 -> 반려) - 컨트롤러 - 프론트 컨트롤러 - 클라이언트
컨트롤러(검증 -> 반려) - 프론트 컨트롤러 - 클라이언트

개인적으론 중요 포인트라고 생각한다.

 

한 편, 위에서 언급한 바와 같이 @Valid 는 컨트롤러에서만 작동한다. 그렇게 만들어져 있다.

그러나, 불가피하게 다른 곳에서 파라미터 검증이 필요한 경우도 있는 모양이다.

 

Spring에서는 이를 위해 AOP 기반으로 메서드 요청을 가로채 유효성 검증을 진행하는 @Validated가 존재한다.

 

다만, @Validated 는 JSR 표준 기술이 아니다. Spring 프레임워크에서 제공하는 기술이다. 

 

사용법

1. 클래스 레벨에서 @Validated 선언

2. Controller 에서의 사용과 같이 Method 파라미터 영역에 @Valid 를 작성 해주면 된다.

@Service
@Validated
public class UserService {

	public void addUser(@Valid AddUserRequest addUserRequest) {
		...
	}
}

출처: https://mangkyu.tistory.com/174 [MangKyu's Diary:티스토리]

 

@Validated 동작 원리

@Valid 는 ArgumentResolver 에 의해 유효성 검사가 진행된다고 했다.

반면, @Validated 는 AOP 기반으로 메서드 요청을 인터셉트하여 처리된다.

 

클래스 레벨에서 @Validated 선언 시,

해당 클래스에 유효성 검증을 위한 AOP 의 어드바이스 또는 인터셉터가 등록된다.

이를 통해 @Valid가 있는 메서드를 실행하면 유효성 검증이 진행된다. (아무데서나 쓸 수 있다)

 

동작원리가 다른 만

 

 

JSR 표준 스펙(@Valid에 쓰이는)의 대표적인 어노테이션으로는 다음과 같은 것들이 있다.

  • @NotNull: 해당 값이 null이 아닌지 검증함
  • @NotEmpty: 해당 값이 null이 아니고, 빈 스트링("") 아닌지 검증함(" "은 허용됨)
  • @NotBlank: 해당 값이 null이 아니고, 공백(""과 " " 모두 포함)이 아닌지 검증함
  • @AssertTrue: 해당 값이 true인지 검증함
  • @Size: 해당 값이 주어진 값 사이에 해당하는지 검증함(String, Collection, Map, Array에도 적용 가능)
  • @Min: 해당 값이 주어진 값보다 작지 않은지 검증함
  • @Max: 해당 값이 주어진 값보다 크지 않은지 검증함
  • @Pattern: 해당 값이 주어진 패턴과 일치하는지 검증함

 

**

스프링 부트 3.2 부터는 유효성 검증 기능에 대한 기능 추가가 있었다고 한다.

@Constraint 가 기본적으로 지원되기 시작했다는데,

@Valid @Validation 애노테이션 없이 기본적 유효성 검증이 가능하다는 모양.

 

그 결과. 아래와 같은 검증도 되는 모양이다.

@RestController
class SystemController {

    @GetMapping("/hello")
    public Integer health(@RequestParam @Length(min = 10) String name){
        return 0;
    }
}

 

우선 오늘은 여기까지만 알아보자.

 

참조

https://mangkyu.tistory.com/174

 

'SPRING' 카테고리의 다른 글

JPA - 양방향 관계_mappedby  (0) 2024.10.29
자동문서화 - Swagger  (1) 2024.10.26
BindingResult  (0) 2024.09.19
로그  (0) 2024.08.27
MVC 패턴 - FrontController?  (0) 2024.08.21