티스토리 뷰

Back-End Framework/SpringBoot

@Valid 와 @Validated

아도니카 2023. 3. 9. 10:32

Validation 객체를 통해 데이터 유효성 검증을 진행해야하는데,

 

javax.validation.Valid 와

org.springframework.validation.annotation.Validated 간의 차이점을 알게되어 짧게 글을 남긴다.

 

** 검증할 객체

public class BoardAdd {

    @NotBlank
    private String title;

    //@NotBlank(message = "{validation.board.test}") // messageSource 에 접근 가능
    @NotBlank
    private String content;

    private String name;

    private String pwd;

    // Getter, Setter
}

 

 

1. @Valid

- Java 에서 지원하는 표준 검증

- Spring에선 Controller 진입시 Model 을 맵핑하는 과정에서 Annotation 을 감지, 검증을 진행하게 된다.

- 검증 실패시 MethodArgumentNotValidException 을 Throw 한다.

@PostMapping(value = {""})
public ResponseEntity<BoardVO> boardAdd(
        @RequestBody @Valid BoardAdd boardApp,
        @AuthenticationPrincipal OAuth2UserPrincipal oAuth2UserPrincipal
) {

    Long seqUser;
    if (oAuth2UserPrincipal != null) {
        seqUser = oAuth2UserPrincipal.getSeqUser();
    } else {
        seqUser = null;
    }

    return ResponseEntity.ok(boardManager.addBoard(boardApp, seqUser));
}

...

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<Map<String, Object>> handleValid(MethodArgumentNotValidException e) {
    logger.error("handleValid");
    BindingResult bindingResult = e.getBindingResult();

    ErrorResp errorResp = ErrorResp.getBadRequest();
    for (FieldError fieldError : bindingResult.getFieldErrors()) {
        errorResp.addError(fieldError.getObjectName(), fieldError.getRejectedValue(), fieldError.getDefaultMessage());
    }

    return ResponseEntity.status(errorResp.getStatus()).body(errorResp.toData());
}

 

2. @Validated

- Spring 에서 @Valid 를 감싼 검증 방식

- Spring에선 AOP 방식으로 요청을 가로채서 검증하기때문에 Controller 외의 모든 Bean 에서 검증이 진행된다.

- 검증 실패시 ConstraintViolationException 을 Throw 한다.

@PostMapping(value = {""})
public ResponseEntity<BoardVO> boardAdd(
        @RequestBody @Validated BoardAdd boardApp,
        BindingResult bindingResult,
        @AuthenticationPrincipal OAuth2UserPrincipal oAuth2UserPrincipal
) {

    if (bindingResult.hasFieldErrors()) {
        ErrorResp errorResp = ErrorResp.getBadRequest();
        for (FieldError fieldError: bindingResult.getFieldErrors()) {
            errorResp.addError(fieldError.getObjectName(), fieldError.getRejectedValue(), fieldError.getDefaultMessage());
        }
        throw errorResp;
    }

    Long seqUser;
    if (oAuth2UserPrincipal != null) {
        seqUser = oAuth2UserPrincipal.getSeqUser();
    } else {
        seqUser = null;
    }

    return ResponseEntity.ok(boardManager.addBoard(boardApp, seqUser));
}

( 단, 여기서 내가 사용한 방식이 좀 달랐던거 같은데,

일반적으론 class 에다가 @Validated를 선언하고, 멤버변수에는 @Valid 를 선언한뒤,

ConstraintViolationException 을 캐치하는 방식을 사용한다고 한다.

그러면 결국 위의 1번 방식과 동일하게 Exception Handling 이 가능해진다. )

 

** ConstraintViolationException Handler

@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<Map<String, Object>> handleValidated(ConstraintViolationException e) {
    logger.error("handleValidated");

    ErrorResp errorResp = ErrorResp.getBadRequest();
    for (ConstraintViolation<?> constraintViolation : e.getConstraintViolations()) {
        errorResp.addError(constraintViolation.getPropertyPath().toString(), constraintViolation.getInvalidValue(), constraintViolation.getMessage());
    }

    return ResponseEntity.status(errorResp.getStatus()).body(errorResp.toData());
}

 

 

Spring 이니까 @Validated 를 사용하는 방향으로 잡아야 할것 같은데,

 

당장에 Controller 외의 다른 부분에서 검증을 진행할 계획은 없기때문에 @Valid 를 사용하기로 한다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함