ExceptionResolver 흐름
1.1 적용 전
1.2 적용 후
1) ExceptionResolver을 통해 해당 에러의 상태코드 등을 변경한다.
2) PostHandler 필터는 여전히 동작하지 않는다.우선 순위
- @ExceptionHandler
- @ResponseStatus
- DefaultHandlerExceptionResolver 사용
1. @ExceptionHandler - ExceptionHandlerExceptionResolver class (대부분 이거 사용하며, 이걸로 처리 가능)
1. 기존과의 차이
1) BasicErrorController를 사용하여 아예 사용자 방식의 Error을 반환하는 방식을 만들기에는 부족하다. (ResponseStatusExceptionResolver , DefaultHandlerExceptionResolver)
2) custom으로 직접 설정 할 경우 return ModelAndview도 Api 형식에는 굳이 필요 없고, 설정 방식도 번거롭다.2. 설명
1) 원하는 Controller에 @ExceptionHandler를 등록하면 된다.
3. 구현 , 분리
구현
3.1 예외를 속성으로 지정한 경우
@ExceptionHandler(IllegalArgumentException.class) public ErrorResult illegalExHandle(IllegalArgumentException e) { log.error("[exceptionHandle] ex", e); return new ErrorResult("BAD", e.getMessage()); }3.2 예외를 속성으로 지정 안할 시
@ExceptionHandler public ResponseEntity<ErrorResult> userExHandle(UserException e) { log.error("[exceptionHandle] ex", e); ErrorResult errorResult = new ErrorResult("USER-EX", e.getMessage()); return new ResponseEntity<>(errorResult, HttpStatus.BAD_REQUEST); }1) 예외를 지정하지 않으면 해당 메서드 파라미터 예외를 사용한다. 여기선 UserException에 적용된다.
2) 반환값
2-1) ErrorResult
2-2) ResponseEntity<'ErrorResult>분리 - @RestControllerAdvice
- 분리 객체 설정
@RestControllerAdvice public class ExControllerAdvice { @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(IllegalArgumentException.class) public ErrorResult IllegalEx(IllegalArgumentException ex){ log.info("IllegalEx ",ex); return new ErrorResult("BAD",ex.getMessage()); } }1) 해당 설정을 해놓으면 별도의 지정 없이 @RestController의 해당 에러에 모두 적용된다.
2. ResponseStatusExceptionResolver class 사용
설명
- @ResponseStatus(value = HttpStatus.NOT_FOUND) , throw ResponseStatusException을 사용 할 경우 ResponseStatusExceptionResolver()가 사용된다.
- @ResponseStatus의 설정을 response.sendError(statusCode, resolvedReason);를 담아서 반환한다.
- BasicController을 통해 해당 에러에 대한 값을 응답으로 반환한다.
1. 설정
@ResponseStatus을 사용 할 경우 (에러 정적 사용)
@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "error.bad") //response.sendError(code , reason)을 담아서 반환한다.throw ResponseStatusException인 경우(에러 동적 사용)
@GetMapping(value = "/api/response-status-ex2") public String responseStatusEx2(){ throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "잘못된 요청s",new IllegalArgumentException()); }3. 예외처리에 대한 설정을 안할 시 - DefaultHandlerExceptionResolver class
1. Basic Controller에 의한 설정 error을 반환한다.
// Basic Controller를 통한 해당 되는 에러 작동 @RequestMapping public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { HttpStatus status = this.getStatus(request); if (status == HttpStatus.NO_CONTENT) { return new ResponseEntity(status); } else { Map<String, Object> body = this.getErrorAttributes(request, this.getErrorAttributeOptions(request, MediaType.ALL)); return new ResponseEntity(body, status); } }2. 해당 코드 응답
{
"timestamp": "2024-12-26T06:44:26.742+00:00",
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.web.method.annotation.MethodArgumentTypeMismatchException",
"message": "Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; For input string: \"AAA\"",
"path": "/api/default-handler-ex"
}
Basic Controller만 사용하는 것은 html에서는 괜찮지만 api의 경우 상황별 커스텀하게 에러를 반환할 필요성이 있기에 HandlerExceptionResolver + Basic Controller 사용
1. 구현 및 설정
1.1 구현
@Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { try{ if(ex instanceof IllegalArgumentException){ log.info("IllegalArgumentException 400이다."); response.sendError(503,ex.getMessage()); return new ModelAndView(); } }catch (IOException e){ log.info("resolver ex",e); } return null; }
- 빈 ModelAndView 반환 시
뷰를 렌더링 하지 않고, 정상 흐름으로 서블릿이 리턴된다.
추가 설명) 서블릿으로 반환 되어 Was에서 response.sendError를 확인하고 재요청이 일어난다.1.2 설정
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) { resolvers.add(new MyHandlerExceptionResolver()); resolvers.add(new UserHandlerExceptionResolver()); } }1) WebMvcConfigurer을 통한 설정하면 된다.
1. WebServerFactoryCustomizer에 설정 정보를 통한 Url로 재요청
@Component public class WebServerCustomizer implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> { @Override public void customize(ConfigurableWebServerFactory factory) { ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/error-page/404"); ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error-page/500"); ErrorPage errorPageRuntime = new ErrorPage(RuntimeException.class, "/error-page/500"); factory.addErrorPages(/*errorPage404,*/errorPageRuntime,errorPage500); } }1. /error-page/500로 재요청 된 응답 반환
{
"message": "잘못된 요청입니다.",
"status": 500
}