spring @Valid 를 이용한 유효성(Validation) 검사

Q·2024년 5월 5일

Spring 심화

목록 보기
6/9

1. Dependency 추가

  • Gradle(build.gradle)
implementation 'org.springframework.boot:spring-boot-starter-validation'
  • Maven(pom.xml)
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
    <version>2.6.6</version>
</dependency>

2. @Valid

  • @Valid 는 JSR-303 표준 스펙(자바 진영)으로써 빈 검증기(Bean Validator)를 이용해 객체의 제약 조건을 검증하도록 하는 어노테이션입니다.

  • Spring 에서는 일종의 어댑터인 LocalValidatorFactoryBean 이 제약 조건 검증을 처리합니다.

  • 이를 사용하기 위해서는 빈으로 등록해야 하는데 위 Dependency 를 추가하면 사용할 수 있습니다.

2-1. 사용방법

  • 간단하게 API 를 만들어보겠습니다.
@RestController
@Slf4j
public class TestController {

    @PostMapping("/todos/save")
    public ResponseEntity<String> createJsonTodo(@RequestBody @Valid TodoRequest request){
        log.info("Post : Todo Save -: {}", request.toString);

        return ResponseEntity.ok().body("Todo 객체 검증 성공");
    }
}
  • 클라이언트로부터 전달받는 파라미터에 @RequestBody 어노테이션을 붙이고 그 앞에 @Valid 어노테이션을 작성하면, RequestBody 로 들어오는 객체에 대해서 Validation(검증)을 수행합니다.

  • @Valid 어노테이션의 검증의 세부적인 사항은 객체 안에 정의하여야 합니다.(여기서는 TodoRequest 에 정의)

@Getter
@Setter
@ToString
public class TodoRequest {

    @NotNull(message = "제목은 필수입니다.")
    private String title;

    @NotEmpty(message = "내용은 필수입니다.")
    private String content;

    private boolean completed;
    
    @Min(1)
    @Max(7)
    private int dDay;
}
  • 예를 들어 @NotNull 어노테이션은 필드의 값이 null 이 아님을 확인하고, @Min 어노테이션은 해당 값의 최솟값을 지정할 수 있습니다.

  • PostMan 으로 간단하게 @Valid 를 테스트하기 위해 content 값을 빈 값으로 요청하면 자동으로 일정 규격에 맞게 SpringBoot 에서 만든 에러를 응답합니다.

2-2. 동작원리

  • SpringBoot 에서 모든 요청은 프론트 컨트롤러인 DispatcherServlet 을 통해 Controller 로 전달됩니다.

  • 전달 과정에서는 컨트롤러 메소드의 객체를 만들어주는 ArgumentResolver 가 동작하는데, @Valid 어노테이션도 이 ArgumentResolver 에 의해 처리가 됩니다.

  • 검증 도중 오류가 있다면 MethodArgumentNotValidException 예외가 발생하고, 디스패처 서블릿에 기본으로 등록된 예외 리졸버(Exception Resolver)인 DefaultHandlerExceptionResolver 에 의해 400 BadRequest 가 발생하게 됩니다.

  • @Valid 는 기본적으로 Controller(컨트롤러)에서만 동작을 합니다.

  • 다른 계층(ex: service)에서 사용하기 위해서는 @Validated 어노테이션과 결합하여 사용해야만 합니다.

3. @Validated

  • 요청 파라미터의 유효성 검증은 Controller(컨트롤러)에서 최대한 처리하는 것이 좋습니다.

  • 하지만, 개발 도중 불가피하게 다른 곳에서 파라미터를 검증해야 할 수 있는데, Spring 에서 이를 위해 AOP 기반으로 메소드의 요청을 가로채어 유효성 검증을 진행해주는 @Validated 어노테이션을 제공하고 있습니다.

  • @Validated 어노테이션은 @Valid 어노테이션의 JSR 표준 기술이 아니며, 다르게 Spring Framework 에서 제공하는 어노테이션 및 기능입니다.

3-1. 사용방법

  • Service 계층에서 주로 사용하고 @Validated 어노테이션을 붙여 사용하시면 됩니다.
@Service
@Validated
public class TestTodoService {

    public ResponseEntity todoSave(@Valid TodoRequest request){

        return ResponseEntity.ok().body("Todo 객체 검증 성공");
    }
}
  • PostMan 으로 간단하게 테스트하기 위해 content 값을 빈 값으로 요청하면 자동으로 일정 규격에 맞게 SpringBoot 에서 만든 에러를 응답합니다.

3-2. 동작 원리

  • @Valid 는 특정 ArgumentResolver 에 의해 유효성 검사가 진행되었다면, @Validated 는 AOP 기반으로 메소드 요청을 Interceptor(인터셉터)하여 처리합니다.

  • @Validated 어노테이션을 클래스 레벨에 선언하면 해당 클래스에 유효성 검증을 위한 인터셉터(MethodValidationInterceptor)가 등록됩니다.

  • 클래스에 선언하게 되면 메소드들이 해당 클래스를 호출할 때 AOP 의 PointCut(포인트컷)으로써 요청을 가로채어 유효성 검증을 진행합니다.

  • 이러한 이유로 @Validated 를 사용하면 계층과 무관하게 Controller, Service, Repository 등 스프링 빈에 등록되면 유효성 검증을 진행할 수 있습니다.

  • @Valid 어노테이션과 다르게 예외는 ConstaintViolationException 으로 발생합니다.

4 .@Valid 제약조건 어노테이션 정리

  • JSR 표준 스펙은 다양한 제약 조건 어노테이션을 제공하고 있습니다.
Anotation제약조건
@NotNullNull 검증
@NullNull 만 입력 가능
@NotEmptyNull 이 아니고, 빈 스트링("") 이 아닌지 검증(" " 은 허용)
@NotBlankNull 이 아니고, 공백(""과 " " 모두 포함)이 아닌지 검증
@Size(min=,max=)해당 값이 주어진 값 사이에 해당하는지 검증(String, Collection, Map, Array 에도 가능)
@Pattern(regex=)주어진 패턴과 일치하는지 검증
@Max(숫자)지정 값 이하인지 검증
@Min(숫자)지정 값 이상인지 검증
@Future현재 보다 미래인지 검증
@Past현재 보다 과거인지 검증
@Positive양수만 가능
@PositiveOrZero양수와 0만 가능
@Negative음수만 가능
@NegativeOrZero음수와 0만 가능
@Email이메일 형식인지 검증
@Digits(integer=, fraction = )대상 수가 지정된 정수와 소수 자리 수 보다 작은지 검증
@DecimalMax(value=)지정된 값(실수) 이하 인지 검증
@DecimalMin(value=)지정된 값(실수) 이상 인지 검증
@AssertFalsefalse 여부 검증
@AssertTruetrue 여부 검증

참고

profile
Data Engineer

0개의 댓글