controller 에서 예외가 발생 하면 handlerExceptionResolver 가 작동한다고 했다.
ResponseStatusExceptionResolver 는 spring이 기본으로 제공해주는 handlerExceptionResolver의 구현체 중 하나로서 , @ResponseStatus가 붙은 예외와 ResponseStatusException 예외를 처리해주는 것이다.
/** * A {@link org.springframework.web.servlet.HandlerExceptionResolver * HandlerExceptionResolver} that uses the {@link ResponseStatus @ResponseStatus} * annotation to map exceptions to HTTP status codes. * * <p>This exception resolver is enabled by default in the * {@link org.springframework.web.servlet.DispatcherServlet DispatcherServlet} * and the MVC Java config and the MVC namespace. * * <p>As of 4.2 this resolver also looks recursively for {@code@ResponseStatus} * present on cause exceptions, and as of 4.2.2 this resolver supports * attribute overrides for {@code@ResponseStatus} in custom composed annotations. * * <p>As of 5.0 this resolver also supports {@link ResponseStatusException}. * * @author Arjen Poutsma * @author Rossen Stoyanchev * @author Sam Brannen * @since 3.0 * @see ResponseStatus * @see ResponseStatusException */ publicclassResponseStatusExceptionResolverextendsAbstractHandlerExceptionResolverimplementsMessageSourceAware{ }
ResponseStatusExceptionResolver 소스코드를 쭉 따라가보면 결국에는 다음과 같이 response.sendError(응답코드,메시지) 를 반환한다.
추가로 다음과 같이 @ResponseStatus에 reason 속성을 message에서 찾아서 처리해줄 수도 있다.
1 2 3 4 5 6
@ResponseStatus(code = HttpStatus.BAD_REQUEST , reason = "error.bad" ) publicclassBadRequestExceptionextendsRuntimeException{ // resources/messages.properties 아래 error.bad 값을 찾아 메세지로 넣어줌. }
ResponseStatusExceptionResolver는 ResponseStatusException 을 처리해준다. 일종의 에러를 또 감싸주는 wrapper 에러라고 생각하면 편하다.
1 2 3 4 5 6 7 8 9
@GetMapping("/api/response-status-ex2") public String responseStatusEx2(){ // 404 로 illeganArgumentException을 반환 thrownew ResponseStatusException(HttpStatus.NOT_FOUND,"error.bad",new IllegalArgumentException()); }
DefaultHandlerExceptionResolver
spring 내부의 예외를 처리해준다. ex) parameter binding시점의 TypeMismatchException 를 400 오류로 반환해줌
ExceptionHandlerExceptionResolver
예외를 처리하고 싶은 controller에서 처리하고 싶은 예외를 @ExceptionHandler 로 지정해주고, 해당 controller에서 예외가 발생하면 ExceptionHandlerExceptionResolver가 호출되어, @ExceptionHandler가 붙은 메소드를 실행시켜준다.
@ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(IllegalArgumentException.class) // IllegalArgumentException 또는 그 자식 예외가 들어올떄 실행된다. public ErrorResult illegalExHandler(IllegalArgumentException e){ log.error("[exceptionHandle] ex",e); returnnew ErrorResult("BAD",e.getMessage()); }
@ExceptionHandler // 예외 class를 별도로 지정해주지 않는 경우에는 parameter의 예외를 처리해준다 즉 아래의 경우에는 UserException이 들어올떄 실행된다. public ResponseEntity<ErrorResult> userExHandle(UserException e){ log.error("[exceptionHandle] ex",e); ErrorResult errorResult = new ErrorResult("USER-EX", e.getMessage()); returnnew ResponseEntity<>(errorResult,HttpStatus.BAD_REQUEST); }
}
위 방식의 단점은 controller에 예외처리코드와 controller 본연의 requestMapping 코드가 섞여있다. spring에서는 위와 같은 책임을 분리할 수 있는 방법도 제공하고 있다.
@ControllerAdvice annotaion을 활용하면 에러코드 로직을 별개의 class로 분리할 수 있다.