Spring

[SpringBoot] API 예외처리

꾸준함. 2021. 8. 8. 01:57

개요

기존에 정리한 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));
}
}
view raw .java hosted with ❤ by GitHub

 

 

위 코드에서 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);
}
...
}
view raw .java hosted with ❤ by GitHub

 

 

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;
}
}
view raw .java hosted with ❤ by GitHub

 

 

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;
}
}
view raw .java hosted with ❤ by GitHub

 

 

WebConfig.java (ExceptionHandler 등록)

 

@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
resolvers.add(new CustomHandlerExceptionResolver());
resolvers.add(new CustomHandlerExceptionResolver2());
}
}
view raw .java hosted with ❤ by GitHub

 

 

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;
}
}
view raw .java hosted with ❤ by GitHub

 

 

* 주석을 보시면 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", "내부 오류");
}
}
view raw .java hosted with ❤ by GitHub

 

 

3.1.2 ControllerAdvice 부연설명

  • @ControllerAdvice는 대상으로 지정한 여러 컨트롤러에 @ExceptionHandler 뿐만 아니라 @InitBinder 기능을 부여해주는 역할
  • 앞서 언급한 것처럼 @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;
}
//
}
view raw .java hosted with ❤ by GitHub

 

출처

인프런 스프링 MVC 2편 (김영한 강사님)

반응형