티스토리 뷰
@Valid
Controller로 넘어오는 데이터를 검증하는 데 사용할 수 있다. 예를 들어, API를 호출할 때 user의 id를 반드시 전달해야 할 경우 @NotNull(message = "사용자의 id는 필수 정보입니다.")와 같이 검증 조건을 추가할 수 있다.
@Getter
public class FindSectionCountRequestDto {
@NotNull(message = "회고 보드 ID는 필수 입력 값입니다.")
private Long retrospectiveId;
@NotNull(message = "템플릿 섹션 ID는 필수 입력 값입니다.")
private Long templateSectionId;
}
Controller에서 API를 호출할 때 위에서 정의한 dto를 받는다. 위에서 사용한 검증 조건을 잘 준수했는지 확인하기 위해서 @Valid 애너테이션을 사용해야 한다.
@GetMapping("/counts")
public CommonApiResponse<FindSectionCountResponseDto> getSectionCounts(@RequestBody @Valid FindSectionCountRequestDto request) {
FindSectionCountResponseDto response = sectionService.getSectionCounts(request);
return CommonApiResponse.successResponse(HttpStatus.OK, response);
}
검증 실패 시 던지는 예외 클래스와 예외 메시지
다음 데이터를 담은 dto를 controller에 전달한다.
{
"retrospectiveId":1
}
위 데이터의 문제는 templateSectionId에 대한 데이터가 존재하지 않는 것이다. 이는 @NotNull 조건을 준수하지 않은 것으로 되어 @Valid에 의해 검증에 실패하게 된다.
검증에 실패한 경우 MethodArgumentNotValidException 예외 클래스가 발생한다. 나는 @ExceptionHanlder를 사용하여 전역에서 발생하는 예외를 한 곳에서 처리하도록 다음과 같이 코드를 작성했다.
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> validMissingParameterException(MethodArgumentNotValidException ex) {
log.error("유효성 검사 실패", ex);
ErrorResponse response = new ErrorResponse(ErrorCode.MISSING_REQUEST_PARAMETER, ex.getMessage());
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
}
위에서 예외를 처리하고 클라이언트에 다음 메시지를 전달한다.
여기서 문제점은 예외 메시지가 너무 길다는 것이다. 나는 @NotNull에 작성한 "템플릿 섹션 ID는 필수 입력 값입니다."만 필요할 뿐이다.
검증 애너테이션에 작성한 default message만 가져오기 위해서 다음과 같이 작성한다. getDefaultMessage()를 통해 기본으로 등록된 메시지를 가져올 수 있다.
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> validMissingParameterException(MethodArgumentNotValidException ex) {
log.error("유효성 검사 실패", ex);
String errorMessage = ex.getBindingResult().getFieldError().getDefaultMessage();
ErrorResponse response = new ErrorResponse(ErrorCode.MISSING_REQUEST_PARAMETER, errorMessage);
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
}
다음과 수정되었음을 알 수 있다.