책을 찾지 못 하는 오류를 Exception으로 처리하기

각각 Validator에서 처리

기존에는 책을 찾지 못하는 오류를, 아래와 같이 처리했었다. 이 경우, id라는 필드에 매핑하고 있었다. 이 방법도 나쁘지는 않지만, 어떤 요소는 id 필드가 따로 존재하지 않기도 했다. 또, 그러려면 Dto 클래스에 id를 추가해주어야 하기도 했다. 간단한 경우 굳이 Dto에 id를 추가하지 않고, @PathVariable에 넣는 방법으로 해야 하는데, 이 경우 global이라는 별도의 필드를 만들어 처리해주어야 했다. 즉, 처리에 일관성이 있지 않다.

@Override
public void validate(Object target, Errors errors) {
    ModifyBookDto book = (ModifyBookDto) target;
    Book findOldBook = bookService.findBookById(book.getId());

    ...

    if (findOldBook == null) {
        errors.rejectValue("id", NOT_FOUND_FIELD);
        return;
        // 책 못 찾으면 여기서 종료
    }

    ...

}

NotFoundBookException 도입

추가적으로 글을 작성하겠지만, 이번에 Optional을 도입하면서, 코드가 조금 변경되긴 했지만, 책을 찾지 못 할 경우 NotFoundBookException 예외를 발생시키도록 했다. 메시지는 예외명을 매우 명확히 작성했으므로, 생략하도록 클래스를 만들어두었다.

public class NotFoundBookException extends RuntimeException {
    public NotFoundBookException() {
    }
}
@Override
public void validate(Object target, Errors errors) {
    ModifyBookDto book = (ModifyBookDto) target;
    String isbn = book.getIsbn();

    bookService.findBookById(book.getId())
            .ifPresentOrElse(findOldBook -> {
                // ISBN 중복 체크
                if (isDuplicated(findOldBook.getIsbn(), isbn)) {
                    errors.rejectValue("isbn", DUPLICATED_FIELD, null);
                }
            }, () -> {
                throw new NotFoundBookException();
            });

}

그리고, FieldValidationHandler 클래스에서 이 예외를 처리한다. FieldValidationHandler는 @ControllerAdvice 애노테이션이 있어서, 발생되는 예외를 잡아줄 수 있다. 이전에 BeanValidation 에러를 처리하기 위해 이 클래스를 이용한 바 있다.

@ControllerAdvice
@RequiredArgsConstructor
public class FieldValidationHandler {

    private final ValidationUtils validationUtils;

   ...

    @ExceptionHandler(NotFoundBookException.class)
    public ResponseEntity<ErrorResponse> handleNotFoundBookError() {
        return validationUtils.handleNotFoundErrors("book");
    }
}

ValidationUtils에 handleNotFoundErrors에 object 명을 전달해서, 재사용성을 높였다.

public ResponseEntity<ErrorResponse> handleNotFoundErrors(String object) {
    Map<String, String> errors = new HashMap<>();

    String errorMessage = messageSource.getMessage(
            "not.found." + object,
            null,
            Locale.getDefault());

    errors.put(object, errorMessage);

    return new ResponseEntity<>(ErrorResponse.builder()
            .code("validation")
            .message("validation 실패")
            .errors(errors).build()
            , HttpStatus.BAD_REQUEST);
}

handleNotFoundErrors 에서는 메시지 소스에서 적절한 not found 에러를 찾아서 보내준다.

댓글

개발자  김철준

백엔드 개발자 김철준의 블로그입니다.

주요 프로젝트