@Slf4j
@RestControllerAdvice
@RequiredArgsConstructor
public class CommonControllerAdvice extends ResponseEntityExceptionHandler {
private final MessageSource messageSource;
@ResponseStatus(value = HttpStatus.NOT_FOUND)
@ExceptionHandler(UserNotFoundException.class)
public ExceptionResponse notFoundExceptionHandler(UserNotFoundException e, WebRequest request) {
log.error("[Not Found Exception] :", e);
return new ExceptionResponse(
HttpStatus.NOT_FOUND.value(),
messageSource.getMessage("error.user_not_found", new Object[]{e.getUserId()}, null),
request.getDescription(false)
);
}
}
위와 같이 예외를 처리할 때, WebRequest
또한 받을 수 있는데, 사용자가 요청한 정보에 대한 내용을 다시 한번 응답으로 돌려줄 때 유용하다.
CommonControllerAdvice
에 ResponseEntityExceptionHandler
를 추가하면 해당 인터페이스에 있는 메소드를 구현하여 많은 예외를 처리해볼 수 있다.
공식문서에 가보면 어떤 arguments
들을 활용할 수 있는지에 대해 상세히 나와있다. HttpServletRequest
와 같은 타입도 활용 가능하다.
@Slf4j
@RestControllerAdvice
@RequiredArgsConstructor
public class CommonControllerAdvice extends ResponseEntityExceptionHandler {
private final MessageSource messageSource;
@ResponseStatus(value = HttpStatus.NOT_FOUND)
@ExceptionHandler(UserNotFoundException.class)
public ExceptionResponse notFoundExceptionHandler(UserNotFoundException e, HttpServletRequest request) {
log.error("[Not Found Exception] :", e);
return new ExceptionResponse(
HttpStatus.NOT_FOUND.value(),
messageSource.getMessage("error.user_not_found", new Object[]{e.getUserId()}, null),
request.getRequestURI()
);
}
}
User
에 String
으로 description
이라는 것을 추가하고, 거기에 URI
경로까지 출력해보도록 했다.@Slf4j
@RestControllerAdvice
@RequiredArgsConstructor
public class CommonControllerAdvice extends ResponseEntityExceptionHandler {
private final MessageSource messageSource;
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
public ExceptionResponse allExceptionsHandler(Exception e, HttpServletRequest request) {
log.error("[Exception] :", e);
return new ExceptionResponse(
HttpStatus.INTERNAL_SERVER_ERROR.value(),
messageSource.getMessage("error.server", null, null),
request.getRequestURI()
);
}
위와 같이 모든 예외의 상위 예외인 Exception.class
의 예외가 터졌을 때, 사용할 공통 예외처리 부분을 만들어보았다.
@GetMapping("/exception")
public void exception(){
throw new RuntimeException();
}
무조건 RuntimeException
을 던지는 예외용 메소드를 하나 만들었다.
의도한대로 잘 작동한다.
그런데 혹시 Exception.class
를 예외처리하도록 설정했으니, 이전에 작성한 UserNotFoundException.class
에 대해서도 기본 예외처리가 적용되는 게 아닐까?
이전에 작성한 UserNotFoundException.class
에서는 의도한대로 잘 처리 된다. 그 이유는 스프링이 최대한 구체적인 것을 우선순위로 두기 때문이다.
UserNotFoundException.class
는 Exception.class
의 하위 클래스는 맞지만, 훨씬 더 구체적이기 때문에 우선순위가 높다.