우리는 개발을 하다보면 다양한 곳에서 다양한 Exception을 마주하게 된다. 그때마다 Exception에 대한 코드를 작성하다보면 나중에 관리할 때 끔찍한 경험을 하게 될 것이다.
그래서 우리는 스프링에서 제공해주는 @ControllerAdvice, @RestControllerAdvice 어노테이션을 활용해서 Exception을 통합적으로 관리하는 핸들러를 작성해서 관리하는 방식을 사용한다.
@Slf4j
@RestControllerAdvice
public class CommonExceptionHandler {
@ExceptionHandler(NoSuchElementFoundException.class)
public ResponseEntity<?> noSuchElementFound(NoSuchElementFoundException e){
log.error(e.getMessage(), e);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(e.getMessage()));
}
}
이러한 방식으로 모든 컨트롤러에서 발생하는 Exception들에 대한@ExceptionHandler 추가하면서 관리가 가능하다.
이러한 방식의 사용하면 이러한 이점을 얻을 수 있다.
@Valid 를 사용해서 유효성 검사를 진행하게 되면 Spring에서 MethodArgumentNotValidException 을 발생시키기 때문에 해당 Exception 핸들러를 추가해줘야 한다.
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<> methodArgumentNotValidException(MethodArgumentNotValidException e) {
log.error(e.getMessage(), e);
List<String> errorMessage = e.getAllErrors()
.stream()
.map(objectError -> (FieldError) objectError)
.map(fieldError -> fieldError.getField() + " => " + fieldError.getDefaultMessage())
.toList();
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(errorMessage));
}
getAllErrors()를 통해서 유효성검사에 실패한 데이터 목록을 가져올 수 있다. 이때 ObjectError를 FieldError로 타입을 변경시키면 해당 필드의 필드명과 에러메세지를 불러올 수 있다. 이러한 데이터들을 각자 API 결과타입에 맞춰서 가공해서 결과를 내려주면 된다.