각각 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 에러를 찾아서 보내준다.