아래와 같이 Bean validation
을 적용했을 때 에러 메시지를 확인해 볼께요.
public class ExpenseRequest {
@NotBlank(message = "Expense name must not be empty.")
private String name;
@NotBlank(message = "Expense description must not be empty.")
private String description;
@NotNull(message = "Expense amount must not be null.")
private Integer amount;
@NotBlank(message = "Expense category must not be empty")
private String category;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@NotNull(message = "Expense date must not be null")
private LocalDate date;
// ... 생략
}
Bean validation
을 적용했을 때 기본적으로 적용되는 메시지입니다.
@NotNull
, @NotBlank
등으로 아주 쉽게 입력값에 대한 검증을 할 수 있었지만 에러 메시지의 포멧이 그리 친절하지는 않습니다.
message
에 설정한 메시지만을 출력해주면 더 좋을 것 같습니다.
Bean validation
에 의해 바인딩 된 에러를 꺼내서 에러 메시지를 커스텀 할 것 입니다.
@ControllerAdvice
가 지정된 API에서 발생하는 예외를 처리하는 클래스에서 ResponseEntityExceptionHandler
를 상속받아 사용합니다.
ResponseEntityExceptionHandler
의 여러 메서드 중 handleMethodArgumentNotValid
를 재정의합니다.
그리고 Map
으로 직접 HTTP 응답의 body를 만들어주면 됩니다.
@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
Map<String, Object> body = new HashMap<>();
body.put("statusCode", HttpStatus.BAD_REQUEST);
body.put("timestamp", LocalDateTime.now());
List<String> errors = ex.getBindingResult().getFieldErrors()
.stream()
.map(e -> e.getDefaultMessage())
.collect(Collectors.toList());
body.put("messages", errors);
return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST);
}
}
MethodArgumentNotValidException
의 getBindingResult()
와 getFieldErrors()
메서드로 현재 필드에 바인딩 된 모든 에러에 접근할 수 있습니다.
모든 필드에러의 메시지를 리스트로 만들어서 body로 구성하면 아래과 같은 결과를 만들 수 있습니다.
이전보다 확실히 깔끔한 에러 메시지를 구성할 수 있게 되었습니다 :) good