개요
기존에 정리한 HTML 예외처리(https://jaimemin.tistory.com/1888)와 달리 API 예외처리는 고려해야 할 요소가 상당히 많습니다.
HTML 예외처리 같은 경우 적절한 예외 페이지만 있으면 대부분의 문제를 해결할 수 있지만, API 예외처리 같은 경우 각 API마다 정해진 규약이 다르므로 각 에러 상황에 맞는 에러 응답 스펙을 정의해야 하고 JSON으로 데이터를 내려주어야 합니다.
이처럼 API마다 정해진 규약이 다르기 때문에 실무 개발을 진행하다 보면 각 프로젝트마다 API 규격 정의서를 작성해야 하는데, 규격도 양방향으로 합의한 후 정해야하기 때문에 해당 프로세스에 상당히 많은 시간을 투자해야 합니다.
API 규격은 회사마다 상이하고 심지어 팀 마다도 다를 수 있으므로 생략하고 이번 포스팅에서는 API 예외처리 방법에 대해 정리해보겠습니다.
1. API 호출 후 예외 발생 시 예외 페이지만 정의되어 있다면?
기존 게시글에서 예외 페이지를 WebServerCustomizer에 등록하고 ErrorPageController에서 예외를 처리했습니다.
이 상태에서 API 호출 후 예외가 발생한다면 응답은 JSON 타입이 아닌 500 에러 HTML 페이지가 반환될 것입니다.
API의 경우 응답이 반드시 JSON으로 반환되어야 하므로 ErrorPageController에서 API 응답하는 컨트롤러를 추가해야 합니다.
ErrorPageController.java
@Slf4j | |
@Controller | |
public class ErrorPageController { | |
@RequestMapping("/error-page/404") | |
public String errorPage404(HttpServletRequest request, HttpServletResponse response) { | |
log.info("errorPage 404"); | |
return "error-page/404"; | |
} | |
@RequestMapping("/error-page/500") | |
public String errorPage500(HttpServletRequest request, HttpServletResponse response) { | |
log.info("errorPage 500"); | |
return "error-page/500"; | |
} | |
@RequestMapping(value = "/error-page/500", produces = MediaType.APPLICATION_JSON_VALUE) | |
public ResponseEntity<Map<String, Object>> errorPage500Api(HttpServletRequest request | |
, HttpServletResponse response) { | |
log.info("API errorPage 500"); | |
Exception exception = (Exception) request.getAttribute(ERROR_EXCEPTION); | |
Map<String, Object> result = new HashMap<>(); | |
result.put("status", request.getAttribute(ERROR_STATUS_CODE)); | |
result.put("message", exception.getMessage()); | |
Integer statusCode = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE); | |
return new ResponseEntity<>(result, HttpStatus.valueOf(statusCode)); | |
} | |
} |
위 코드에서 errorPage500Api가 API 예외 처리하는 컨트롤러입니다.
- 주목해야 할 부분은 @RequestMapping 어노테이션 내 produces = MediaType.APPLICATION_JSON_VALUE 부분인데 이는 클라이언트가 요청하는 HTTP Header의 Accept 값이 application/json일 경우에만 해당 메서드가 호출된다는 뜻
- Accept 값이 application/json이 아닌 나머지 요청에서 예외가 발생할 경우 html로 반환
- Jackson 라이브러리는 Map을 JSON 구조로 변환
- 응답 객체로 ResponseEntity를 사용했기 때문에 메시지 컨버터가 동작하면서 HTTP Body에 JSON 데이터 반환
- 정리를 하자면, produces = MediaType.APPLICATION_JSON_VALUE를 @RequestMapping 어노테이션에 포함시킨 상태에서 ResponseEntity를 반환하면 응답 값이 JSON 형태로 반환되므로 API 호출 후 예외 발생 시 예외 페이지가 아닌 JSON 형태로 반환이 됩니다.
1.1 BasicErrorController
- 스프링 부트에서 제공하는 기본 에러 컨트롤러인 BasicErrorController 또한 ErrorPageController.java와 비슷하게 동작
- 차이점이라면 BasicErrorController에서는 html 예외처리를 하는 errorHtml 메서드에 produces = MediaType.TEXT_HTML_VALUE 를 부여한 뒤 View를 제공
- 즉, html 예외처리를 제외한 다른 예외처리는 error 메서드로 처리
@Controller | |
@RequestMapping("${server.error.path:${error.path:/error}}") | |
public class BasicErrorController extends AbstractErrorController { | |
@RequestMapping(produces = MediaType.TEXT_HTML_VALUE) | |
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { | |
HttpStatus status = getStatus(request); | |
Map<String, Object> model = Collections | |
.unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML))); | |
response.setStatus(status.value()); | |
ModelAndView modelAndView = resolveErrorView(request, response, status, model); | |
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model); | |
} | |
@RequestMapping | |
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) { | |
HttpStatus status = getStatus(request); | |
if (status == HttpStatus.NO_CONTENT) { | |
return new ResponseEntity<>(status); | |
} | |
Map<String, Object> body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL)); | |
return new ResponseEntity<>(body, status); | |
} | |
... | |
} |
2. HandlerExceptionResolver
- 스프링 MVC는 컨트롤러 밖으로 exception이 던져진 경우 예외를 해결하고 새로 동작을 정의할 수 있는 방법을 제공
- 컨트롤러 밖으로 던져진 예외를 해결하고 새로 동작을 정의하고 싶으면 HandlerExceptionResolver를 사용해야 함
- HandlerExceptionResolver를 ExceptionResolver라고도 부름
- 필터와 인터셉터처럼 WebConfig에 등록해야함
2.1 HandlerExceptionResolver 적용 전
- HandlerExceptionResolver를 적용하기 전에는 필터, 인터셉터 정리 글(https://jaimemin.tistory.com/1887)에서 소개한 것처럼 아래와 같은 흐름을 진행이 됨
- DispatcherServlet에서 컨트롤러를 호출하기 전 preHandle 메서드가 호출되고 컨트롤러 내에서 예외가 발생할 경우 postHandle 메서드는 호출이 되지 않고 afterCompletion 메서드가 호출됨
- 이후 예외가 DispatcherServlet을 거쳐 WAS까지 전달이 됨
- WAS에서 다시 예외처리를 위해 호출
- 이 때문에, 기존 게시글에서 다룬 것처럼 예외 발생 시 아래와 같은 흐름으로 진행
- HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 인터셉터 -> 컨트롤러 - 예외 발생 -> 인터셉터 -> 서블릿 -> 필터 -> WAS - 예외 페이지 정보 확인 -> 필터 -> 서블릿 -> 인터셉터 -> 예외 페이지 컨트롤러 -> 예외 페이지 (View)

2.2 HandlerExceptionResolver 적용 후
- HandlerExceptionResolver 적용 후에는 예외가 WAS까지 전달되지 않고 ExceptionResolver 내에서 예외를 처리
- try catch문에서 예외를 처리하고 정상 흐름으로 변경하는 것과 비슷
- 정상 흐름으로 변경하기 위해 ModelAndView 반환
- 빈 ModelAndView라도 반환하는 것은 정상 흐름으로 변경하기 위해
- 클래스명 그대로 예외를 처리하는 것이 목적

2.3 ExceptionResolver 반환 값에 따른 동작 방식
- Empty ModelAndView
- new ModelAndView()처럼 빈 ModelAndView를 반환할 경우 뷰가 렌더링 되지 않고, 정상 흐름으로 서블릿이 반환됨
- ModelAndView 지정
- ModelAndView에 View, Model 등의 정보를 지정하고 반환할 경우 해당 뷰를 렌더링 함
- Exception과 에러 페이지를 매핑할 때 적용
- null
- null 반환 시, 다음 ExceptionResolver를 찾아서 실행 (여러 ExceptionResolver 등록 가능)
- 끝까지 처리할 수 있는 ExceptionResolver를 발견 못할 경우, 기존에 발생한 예외를 WAS까지 전달
2.4 ExceptionResolver 활용방안
- 예외 상태 코드 변환
- 예외를 response.sendError(xxx) 메서드를 호출함으로써 서블릿에서 상태 코드에 따른 오류 처리하도록 위임
- 이후 WAS는 서블릿 오류 페이지를 찾아서 내부 호출
- 예를 들자면, 스프링 부트가 기본으로 설정한 /error 호출
- 대고객 서비스의 경우 예외가 발생할 때 4xx, 5xx 에러코드를 반환하면 보안에 문제가 있을 수 있으므로 200으로 반환하는 케이스도 있음
- 뷰 템플릿 처리
- ModelAndView에 값을 채워 예외에 따른 오류 화면을 매핑하여 뷰 렌더링 하여 고객에게 제공
- API 응답처리
- 복잡하기 때문에 추천하는 방법은 아님
- HttpServletResponse 내 writer를 불러와 HTTP 응답 바디에 직접 데이터를 넣어주는 방식
- JSON으로 응답하면 API 응답 처리 가능
CustomExceptionHandler 예시 (500 -> 400 에러 변환)
@Slf4j | |
public class CustomHandlerExceptionResolver implements HandlerExceptionResolver { | |
@Override | |
public ModelAndView resolveException(HttpServletRequest request | |
, HttpServletResponse response | |
, Object handler | |
, Exception ex) { | |
try { | |
if (ex instanceof IllegalArgumentException) { | |
log.info("500 에러를 400 에러로 변환"); | |
response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage()); | |
return new ModelAndView(); // 정상흐름으로 변경하기 위해 빈 ModelAndView 반환 | |
} | |
} catch (IOException e) { | |
log.error("resolver ex", e); | |
} | |
return null; | |
} | |
} |
CustomExceptionHandler2 예시 (HTTP Header Accept 타입에 따라 분기 처리)
@Slf4j | |
public class CustomHandlerExceptionResolver2 implements HandlerExceptionResolver { | |
// Jackson 라이브러리 | |
private final ObjectMapper objectMapper = new ObjectMapper(); | |
@Override | |
public ModelAndView resolveException(HttpServletRequest request | |
, HttpServletResponse response | |
, Object handler | |
, Exception ex) { | |
try { | |
if (ex instanceof CustomException) { | |
String acceptHeader = request.getHeader("accept"); | |
response.setStatus(HttpServletResponse.SC_BAD_REQUEST); // 500 -> 400 에러로 변경 | |
// application/json 즉, api 응답일 경우 | |
if (MediaType.APPLICATION_JSON_VALUE.equals(acceptHeader)) { | |
Map<String, Object> errorResult = new HashMap<>(); | |
errorResult.put("ex", ex.getClass()); | |
errorResult.put("message", ex.getMessage()); | |
String result = objectMapper.writeValueAsString(errorResult); | |
response.setContentType(MediaType.APPLICATION_JSON_VALUE); | |
response.setCharacterEncoding("utf-8"); | |
response.getWriter() | |
.write(result); | |
return new ModelAndView(); | |
} else { | |
// TEXT/HTML일 경우 | |
return new ModelAndView("error/500"); | |
} | |
} | |
} catch (IOException e) { | |
log.error("resolver ex", e); | |
} | |
return null; | |
} | |
} |
WebConfig.java (ExceptionHandler 등록)
@Configuration | |
public class WebConfig implements WebMvcConfigurer { | |
@Override | |
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) { | |
resolvers.add(new CustomHandlerExceptionResolver()); | |
resolvers.add(new CustomHandlerExceptionResolver2()); | |
} | |
} |
3. 스프링에서 기본으로 제공하는 ExceptionResolver
앞선 예시들처럼 BasicErrorController나 커스텀 ExceptionResolver로는 세밀한 제어가 필요한 API 예외처리를 하기 힘드므로 스프링에서 세 가지의 기본 ExceptionResolver를 제공합니다.
API 예외처리의 어려운 점
- 앞선 예시의 HandlerExceptionResolver의 경우 정상 흐름으로 돌리기 위해 매번 ModelAndView를 반환해야 했지만 이는 API 응답에는 사실 필요 없는 객체
- 앞서 ExceptionResolver의 활용방안으로 HttpServletResponse에 직접 응답 데이터를 넣어도 된다고 했지만 이 것은 과거 서블릿을 사용하던 시절로 돌아가는 것과 비슷하므로 불편함
- 같은 exception이라도 컨트롤러마다 다르게 처리하고 싶을 수 있는데 이를 매번 커스텀 ExceptionResolver로 처리하기에는 한계가 있음
HandlerExceptionResolverComposite에 기본으로 제공하는 ExceptionResolver가 아래의 순서대로 등록이 되어있으며 순서는 우선순위 순입니다.
- ExceptionHandlerExceptionResolver
- ResponseStatusExceptionResolver
- DefaultHandlerExceptionResolver
3.1 ExceptionHandlerExceptionResolver
- 스프링에서 기본으로 제공하는 ExceptionResolver 중에 우선순위가 가장 높음
- @ExeptionHandler 어노테이션을 사용하여 처리하며 API 예외 처리의 대부분이 해당 기능으로 해결 가능
- @ExceptionHandler 어노테이션을 선언한 뒤 해당 컨트롤러에서 처리하고 싶은 예외를 지정해주면 됨
- 해당 컨트롤러에서 예외가 발생하면 이 메서드가 호출되며 지정한 예외 또는 그 예외의 자식 클래스를 모두 처리
- 컨트롤러에 예외처리까지 하면 코드가 지저분해지므로 ControllerAdvice 어노테이션을 붙인 클래스를 별도로 선언하여 @ControllerAdvice 내에서 @ExceptionHandler 메서드들을 선언해도 됨 (밑에 추가 설명 예정)
- @ExceptionHandler 어노테이션을 통해 JSON으로 응답을 보낼 수 있지만 앞선 예시처럼 html 형식으로도 응답을 보낼 수 있음
- 즉, API 예외처리와 HTML 예외처리 둘 다 가능
3.1.1 예제 코드
ErrorResult.java (API 응답 객체)
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ErrorResult {
private String code;
private String message;
}
ApiExceptionController.java
@Slf4j | |
@RestController | |
public class ApiExceptionController { | |
private static final String WRONG_USER = "wrong-user"; | |
private static final String BAD_REQUEST = "bad-request"; | |
private static final String USER_EXCEPTION = "user-exception"; | |
@GetMapping("/api2/members/{id}") | |
public MemberDto getmember(@PathVariable("id") String id) { | |
if (WRONG_USER.equals(id)) { | |
throw new RuntimeException("잘못된 사용자"); | |
} else if (BAD_REQUEST.equals(id)) { | |
throw new IllegalArgumentException("잘못된 입력 값"); | |
} else if (USER_EXCEPTION.equals(id)) { | |
throw new CustomUserException("사용자 오류"); | |
} | |
return new MemberDto(id, "안녕하세요 " + id + "님"); | |
} | |
// IllegalArgumentException에 대한 ExceptionHandler | |
@ResponseStatus(HttpStatus.BAD_REQUEST) // 500 에서 400 에러로 변환 | |
@ExceptionHandler(IllegalArgumentException.class) | |
public ErrorResult illegalExceptionHandler(IllegalArgumentException e) { | |
log.error("[exceptionHandler] exception", e); | |
return new ErrorResult(BAD_REQUEST, e.getMessage()); | |
} | |
// 커스텀 exception에 대한 ExceptionHandler | |
// 별도 예외를 지정하지 않을 경우 매개변수를 통해 판단 | |
// 즉, @ExceptionHandler(CustomUserException.class) 와 동일 | |
@ExceptionHandler | |
public ResponseEntity<ErrorResult> customUserExceptionHandler(CustomUserException e) { | |
log.error("[exceptionHandler] ex", e); | |
ErrorResult errorResult = new ErrorResult(USER_EXCEPTION, e.getMessage()); | |
return new ResponseEntity(errorResult, HttpStatus.BAD_REQUEST); | |
} | |
// 500 에러로 응답 | |
// 앞서 언급한 IllegalArgumentException과 CustomUserExceptiond을 제외한 나머지 exception에 대한 ExceptionHandler | |
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) | |
@ExceptionHandler | |
public ErrorResult exHandler(Exception e) { | |
log.error("[exceptionHandler] exception", e); | |
return new ErrorResult("EXCEPTION", "내부 오류"); | |
} | |
@Data | |
@AllArgsConstructor | |
static class MemberDto { | |
private String memberId; | |
private String name; | |
} | |
} |
* 주석을 보시면 ExceptionHandler 활용법을 익히실 수 있습니다.
* 예시에는 없지만, ModelAndView 반환 시 에러 페이지 렌더링 가능 (예시에는 모두 JSON으로 응답)
ExceptionControllerAdvice.java
- 앞서 언급한 것처럼, ApiExceptionController.java 내 ExceptionHandler까지 있으면 코드가 깔끔해 보이지 않음
- 따라서, ExceptionHandler들을 ExceptionControllerAdvice로 옮겨서 코드 리팩터링 가능
- ControllerAdvice는 명시하지 않을 경우 모든 컨트롤러에서 발생하는 예외를 처리하고 별도로 명시할 경우 특정 어노테이션, 패키지, 혹은 컨트롤러에 대해서만 처리할 수 있음
@Slf4j | |
@RestControllerAdvice(annotations = RestController.class) | |
public class ExceptionControllerAdvice { | |
private static final String WRONG_USER = "wrong-user"; | |
private static final String BAD_REQUEST = "bad-request"; | |
private static final String USER_EXCEPTION = "user-exception"; | |
// IllegalArgumentException에 대한 ExceptionHandler | |
@ResponseStatus(HttpStatus.BAD_REQUEST) // 500 에서 400 에러로 변환 | |
@ExceptionHandler(IllegalArgumentException.class) | |
public ErrorResult illegalExceptionHandler(IllegalArgumentException e) { | |
log.error("[exceptionHandler] exception", e); | |
return new ErrorResult(BAD_REQUEST, e.getMessage()); | |
} | |
// 커스텀 exception에 대한 ExceptionHandler | |
// 별도 예외를 지정하지 않을 경우 매개변수를 통해 판단 | |
// 즉, @ExceptionHandler(CustomUserException.class) 와 동일 | |
@ExceptionHandler | |
public ResponseEntity<ErrorResult> customUserExceptionHandler(CustomUserException e) { | |
log.error("[exceptionHandler] ex", e); | |
ErrorResult errorResult = new ErrorResult(USER_EXCEPTION, e.getMessage()); | |
return new ResponseEntity(errorResult, HttpStatus.BAD_REQUEST); | |
} | |
// 500 에러로 응답 | |
// 앞서 언급한 IllegalArgumentException과 CustomUserExceptiond을 제외한 나머지 exception에 대한 ExceptionHandler | |
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) | |
@ExceptionHandler | |
public ErrorResult exHandler(Exception e) { | |
log.error("[exceptionHandler] exception", e); | |
return new ErrorResult("EXCEPTION", "내부 오류"); | |
} | |
} | |
3.1.2 ControllerAdvice 부연설명
- @ControllerAdvice는 대상으로 지정한 여러 컨트롤러에 @ExceptionHandler 뿐만 아니라 @InitBinder 기능을 부여해주는 역할
- @InitBinder 어노테이션은 기존 게시글(https://jaimemin.tistory.com/1874) 내 WebDataBinder 설명 참고
- 앞서 언급한 것처럼 @ControllerAdvice에 대상을 지정하지 않을 경우 글로벌하게 모든 컨트롤러에 대해 적용
- 대상은 크게 아래와 같이 세 가지를 지정 가능
- 어노테이션
- 패키지
- 컨트롤러
- 대상은 크게 아래와 같이 세 가지를 지정 가능
- @RestControllerAdvice = @ControllerAdvice + @ResponseBody
- @RestController가 @Controller + @ResponseBody인 것과 비슷
- 보다 자세한 내용은 https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-controller-advice 참고
3.2 ResponseStatusExceptionResolver
- @ResponseStatus 어노테이션을 통해 HTTP 상태 코드 지정
- 앞선 ApiExceptionController 예시 코드 내 ExceptionHandler에서 사용한 바 있음
- 즉, 정리를 하자면 ResponseStatusExceptionResolver는 예외에 따라 HTTP 상태 코드를 지정해주는 역할
- ResponseStatusExceptionResolver는 아래의 두 가지 경우를 처리
- @ResponseStatus가 달려있는 예외
- ResponseStatusException 예외
- 코드를 분석해보면 ResponseStatusExceptionResolver가 결국 HttpServletResponse의 sendError(statusCode, resolvedReason) 메서드를 호출하기 때문에 WAS에서 재정의된 HTTP 상태 코드에 대한 예외 페이지(/error)를 내부 요청하는 것을 확인 가능
- 라이브러리에서 제공하는 예외 코드 같은 경우 개발자가 커스텀하게 @ResponseStatus 어노테이션을 부여하기 힘드므로 이 때는 ResponseStatusException 예외를 사용
3.2.1 @ResponseStatus 예제 코드
BadRequestException (커스텀 exception)
- ResponseStatus 어노테이션을 통해 500 -> 400 에러로 변환
@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "잘못된 요청")
public class BadRequestException extends RuntimeException {
}
ApiExceptionController.java
@GetMapping("/api/response-status-exception1")
public String responseStatusException1() {
throw new BadRequestException();
}
* ResponseStatusExceptionResolver가 결국 HttpServletResponse의 sendError(statusCode, resolvedReason) 메서드를 호출하기 때문에 WAS에서 재정의된 HTTP 상태코드에 대한 예외 페이지(/error)를 내부 요청하는 것을 확인 가능
에시 응답
{
"status": 400,
"error": "Bad Request",
"exception": "com.tistory.jaimemin.exception.BadRequestException",
"message": "잘못된 요청",
"path": "/api/response-status-exception1"
}
* 응답으로 message까지 표기하기 위해서는 application.properties 혹은 application.yml 내 server.error.include-message=always 설정 필요
3.2.2 ResponseStatusException 예제 코드
ApiExceptionController.java
@GetMapping("/api/response-status-exception2")
public String responseStatusException2() {
throw new ResponseStatusException(HttpStatus.NOT_FOUND
, "error.bad" // messages.properties에서 메시지 불러올 수 있음
, new IllegalArgumentException());
}
* IllegalArgumentException 에러코드를 404로 변환하고 message를 MessageSource 객체를 이용해 messages.properties에서 불러올 수 있음
예시 응답
{
"status": 404,
"error": "Not Found",
"exception": "org.springframework.web.server.ResponseStatusException",
"message": "잘못된 요청",
"path": "/api/response-status-exception2"
}
3.3 DefaultHandlerExceptionResolver
- 스프링 내부에서 발생하는 스프링 예외 해결
- 스프링 프레임워크 내 DefaultHandlerExceptionResolver 클래스를 확인하면 보통 4XX, 5XX로 처리하는 수많은 400대 500대 에러에 대해서도 처리한 것을 확인할 수 있음
- 코드를 보면 결국, HttpServletResponse 내 sendError 메서드를 통해 알맞은 HTTPStatusCode로 변경하는 것을 확인할 수 있음
- HTTP 응답 코드를 적절하게 변경할 수 있지만 ResponseStatusExceptionResolver와 달리 message에 원하는 내용 넣기 힘듦
public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionResolver { | |
// 중략 | |
@Override | |
@Nullable | |
protected ModelAndView doResolveException( | |
HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) { | |
try { | |
if (ex instanceof HttpRequestMethodNotSupportedException) { | |
return handleHttpRequestMethodNotSupported( | |
(HttpRequestMethodNotSupportedException) ex, request, response, handler); | |
} | |
else if (ex instanceof HttpMediaTypeNotSupportedException) { | |
return handleHttpMediaTypeNotSupported( | |
(HttpMediaTypeNotSupportedException) ex, request, response, handler); | |
} | |
else if (ex instanceof HttpMediaTypeNotAcceptableException) { | |
return handleHttpMediaTypeNotAcceptable( | |
(HttpMediaTypeNotAcceptableException) ex, request, response, handler); | |
} | |
else if (ex instanceof MissingPathVariableException) { | |
return handleMissingPathVariable( | |
(MissingPathVariableException) ex, request, response, handler); | |
} | |
else if (ex instanceof MissingServletRequestParameterException) { | |
return handleMissingServletRequestParameter( | |
(MissingServletRequestParameterException) ex, request, response, handler); | |
} | |
else if (ex instanceof ServletRequestBindingException) { | |
return handleServletRequestBindingException( | |
(ServletRequestBindingException) ex, request, response, handler); | |
} | |
else if (ex instanceof ConversionNotSupportedException) { | |
return handleConversionNotSupported( | |
(ConversionNotSupportedException) ex, request, response, handler); | |
} | |
else if (ex instanceof TypeMismatchException) { | |
return handleTypeMismatch( | |
(TypeMismatchException) ex, request, response, handler); | |
} | |
else if (ex instanceof HttpMessageNotReadableException) { | |
return handleHttpMessageNotReadable( | |
(HttpMessageNotReadableException) ex, request, response, handler); | |
} | |
else if (ex instanceof HttpMessageNotWritableException) { | |
return handleHttpMessageNotWritable( | |
(HttpMessageNotWritableException) ex, request, response, handler); | |
} | |
else if (ex instanceof MethodArgumentNotValidException) { | |
return handleMethodArgumentNotValidException( | |
(MethodArgumentNotValidException) ex, request, response, handler); | |
} | |
else if (ex instanceof MissingServletRequestPartException) { | |
return handleMissingServletRequestPartException( | |
(MissingServletRequestPartException) ex, request, response, handler); | |
} | |
else if (ex instanceof BindException) { | |
return handleBindException((BindException) ex, request, response, handler); | |
} | |
else if (ex instanceof NoHandlerFoundException) { | |
return handleNoHandlerFoundException( | |
(NoHandlerFoundException) ex, request, response, handler); | |
} | |
else if (ex instanceof AsyncRequestTimeoutException) { | |
return handleAsyncRequestTimeoutException( | |
(AsyncRequestTimeoutException) ex, request, response, handler); | |
} | |
} | |
catch (Exception handlerEx) { | |
if (logger.isWarnEnabled()) { | |
logger.warn("Failure while trying to resolve exception [" + ex.getClass().getName() + "]", handlerEx); | |
} | |
} | |
return null; | |
} | |
// | |
} |
출처
인프런 스프링 MVC 2편 (김영한 강사님)
'Spring' 카테고리의 다른 글
[SpringBoot] 파일 업로드 및 다운로드 (2) | 2021.08.14 |
---|---|
[SpringBoot] 스프링 TypeConverter 정리 (1) | 2021.08.11 |
[SpringBoot] HTML 예외처리와 예외 페이지 (0) | 2021.08.03 |
[SpringBoot] Filter, Interceptor 개념 정리 및 로그인 처리 (4) | 2021.08.01 |
[SpringBoot] 쿠키, 세션을 이용한 로그인 처리 (2) | 2021.07.31 |