@Valid 와 @Validated, BindingResult

5tr1ker·2023년 4월 25일
0

Spring

목록 보기
2/10
post-thumbnail

@Valid의 개념

@Valid는 JSR-303 표준 스펙 ( 자바 진영 스펙 ) 으로써 빈 검증기 ( Bean Validator ) 를 이용해 객체의 제약 조건을 검증하도록 지시하는 어노테이션입니다. JSR 표준의 빈 검증 기술의 특징은 필드에 달린 어노테이션으로 편리하게 검증을 합니다. Spring 에서는 LocalValidatorFactoryBean 가 제약 조건 검증을 처리하는데 이를 이용하려면 Bean 을 등록해야 하며 , SpringBoot에서는 아래의 의존성을 추가해주어야 합니다.

// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-validation'

@Valid의 동작 원리

모든 요청은 프론트 컨트롤러인 디스패처 서블릿을 통해 컨트롤러로 전달됩니다. 전달 과정에서 컨트롤러 메서드의 객체를 만들어주는 ArgumentResolver 가 동작하는데 @Valid 는 이러한 ArgumentResolver에 의해 처리됩니다.
대표적으로 @RequestBody 는 Json 메세지를 객체로 변환해주는 작업이 ArgumentResolver 의 구현체인 RequestResponseBodyMethodProcessor 가 처리하며 , 이 내부에서 @Valid로 시작하는 어노테이션이 있으면 유효성 검사를 시작합니다.

그리고 검증에 오류가 있다면 MethodArgumentNotValidException 예외가 발생하게 되고 디스패처 서블릿은 기본으로 등록된 예외 리졸버인 DefaultHandlerExceptionResolver 에 의해 400 Bad Request 에러가 발생합니다.

이러한 이유로 @Valid 는 기본적으로 컨트롤러에서만 동작하며 다른 계층에서는 검증을 하지 않습니다. 다른 계층에서 파라미터를 검증하기 위해서는 @Validated와 결합하여야 합니다.

@Validated의 개념

입력 파라미터의 유효성 검증은 컨트롤러에서 처리하는 것이 좋지만 불가피하게 다른 계층에서 파라미터를 검증해야 할 수 있습니다. Spring 에서는 이를 위해 AOP 기반으로 메서드의 요청을 가로채 유효성 검증을 진행하는 @Validated 를 제공합니다. @Validated는 JSR 표준 기술이 아닌 Spring 프레임워크에서 제공하는 어노테이션입니다.

@Validated의 동작 개념

특정 ArgumentResolver에 의해 유효성이 검사되었던 @Valid와 달리 , @Validated는 AOP 기반으로 메서드의 요청을 인터셉트하여 처리됩니다. @Validated를 클래스 레벨에 선언하면 해당 클래스의 유효성 검사를 위한 AOP 어드바이스 또는 인터셉터가 등록됩니다. 그리고 해당 클래스의 메서드들이 호출될 때 AOP 포인트 컷으로 요청을 가로채 유효성 검사를 합니다.

이러한 이유로 @Validated를 사용하면 컨트롤러 , 서비스 , 레파지토리 등 계층과 무관하게 스프링 빈이라면 유효성 검증을 할 수 있습니다. 대신 클래스에는 유효성 검증 AOP가 적용되도록 @Validated를 , 검증을 진행할 메서드에는 @Valid를 선언합니다.

또한 @Valdated의 또 다른 개념으로 유효성 검증 그룹을 지정해서 동일한 클래스에서 사용자마다 제약 조건을 다르게 할 수 있습니다.

제약 조건 어노테이션들

JSR 표준 스펙은 다양한 제약 조건 어노테이션을 제공하고 있는데, 대표적으로 다음과 같은 것들이 있습니다.

  • @NotNull : 해당 값이 Null이 아니다.
  • @NotEmpty : 해당 값이 Null이 아니며 , 빈 스트링이 아니다. ( "" )
  • @NotBlank : 해당 값이 Null이 아니며 , 공백이 아니다. ( "" 와 " " )
  • @AssertTrue : 해당 값이 true 이다.
  • @Size : 해당 값이 주어진 값 사이에 해당한다.
  • @Min : 해당 값이 @Min 보다 커야한다.
  • @Max : 해당 값이 @Max 보다 커야한다.
  • @Pattern : 해당 값이 주어진 패턴과 일치한다.
  • @Length : 길이를 설정할 수 있다.
  • @Range : 범위를 설정할 수 있다.

그 외에도 이메일 형식인지 확인하는 @Email 과 URL인지 확인하는 @URL 과 같은 많은 어노테이션이 있으며 우리가 필요로 하는 제약 조건 어노테이션을 찾아서 활용합니다.

BindingResult

BindingResult 는 스프링이 제공하는 값 검증 오류 처리의 핵심으로 , 유효성 검사에 실패하여 ConstraintViolationException 예외가 발생하면 그에 대한 에러 정보를 BindingResult에 담습니다.

만약 BindingResult가 있다면 오류 정보를 가지고 컨트롤러를 호출하며, BindingResult가 없다면 4xx 오류가 발생하면서 컨트롤러 호출이 되지 않습니다.

이러한 BindingResult의 검증 오류를 적용하는 방법은 다음과 같습니다.

  • @ModelAttribute 의 객체에 바인딩이 실패하면 스프링이 FieldError를 생성해 BindingResult에 넣어줍니다.
  • 개발자가 직접 new FieldError를 만들어 넣어줍니다.
  • Validator ( @Valid , @Validated ) 를 사용합니다.

BindingResult의 메서드

  • boolean hasErrors() : 에러의 유무를 반환합니다.
  • boolean hasGlobalErrors() : 글로벌 에러의 유무를 반환합니다.
  • void addError(ObjectError error) : field , type , value 등의 에러를 출력합니다.
  • void rejectValue() : field, errorCode, defaultMessage 등을 받아서 reject 됐을 때 데이터를 남길 수 있습니다.

BindingResult의 파라미터

  • objectName : 오류가 발생한 객체의 이름
  • field : 오류가 난 필드
  • rejectedValue : 거절된 사용자의 입력 값
  • bindingFailure : 타입 오류 같은 바인딩 실패인지 , 검증 실패인지 구분
  • codes : 메시지 코드
  • arguments : 메세지에서 사용하는 인자
  • defaultMessage : 기본 오류 메세지

정리

  • @Valid
    - JSR-303 자바 표준 스펙
    - ArgumentResolver를 통해 진행되어 컨트롤러 메서드의 유효성 검증만 가능

    • 유효성 검증에 실패하면 MethodArgumentNotValidException 예외 발생
  • @Validated
    - Spring Framework에서 제공하는 기능

    • AOP를 기반으로 스프링 빈의 유효성 검증을 수행
    • 유효성 검증에 실패하면 ConstraintViolationException 예외 발생

참고

참고 블로그 1 : https://mangkyu.tistory.com/174
참고 블로그 2 : https://velog.io/@mooh2jj/Spring-Boot-Validation-%EC%A0%81%EC%9A%A9%ED%95%98%EB%8A%94-%EB%B2%95
참고 블로그 3 : https://sweets1327.tistory.com/54

profile
https://github.com/5tr1ker

0개의 댓글