오봉이와 함께하는 개발 블로그

스프링 MVC 2 - ExceptionResolver Part. 1 본문

BE/Spring

스프링 MVC 2 - ExceptionResolver Part. 1

오봉봉이 2022. 8. 31. 02:12
728x90

API 예외 처리 - 스프링이 제공하는 ExceptionResolver 1

스프링 부트가 기본으로 제공하는 ExceptionResolver는 다음과 같다.
HandlerExceptionResolverComposite에 다음 순서로 등록

  1. ExceptionHandlerExceptionResolver
  2. ResponseStatusExceptionResolver
  3. DefaultHandlerExceptionResolver -> 우선 순위가 가장 낮다.

ExceptionHandlerExceptionResolver
@ExceptionHandler을 처리한다.
API 예외 처리는 대부분 이 기능으로 해결한다.
따로 자세히 설명한다.

ResponseStatusExceptionResolver
예외가 발생했을 때 HTTP 상태 코드를 지정해준다.
예 : @ResponseStatus(value = HttpStatus.NOT_FOUND)

DefaultHandlerExceptionResolver
스프링 내부 기본 예외를 처리한다.

ResponseStatusExceptionResolver

ResponseStatusExceptionResolver는 예외에 따라서 HTTP 상태 코드를 지정해주는 역할을 한다.

다음 두 가지 경우를 처리한다.

  • @ResponseStatus가 달려있는 예외
  • ResponseStatusException 예외

예외에 다음과 같이 @ResponseStatus 어노테이션을 적용하면 HTTP 상태 코드를 변경해준다.

@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "잘못된 요청 오류")
public class BadRequestException extends RuntimeException {

}

BadRequestException예외가 컨트롤러 밖으로 넘어가면 ResponseStatusExceptionResolver예외가 해당 어노테이션을 확인해서 오류 코드를 HttpStatus.BAD_REQUEST(400)으로 변경하고, 메시지도 담는다.

ResponseStatusExceptionResolver코드를 확인해보면 결국 response.sendError(statusCode, resolvedReason)를 호출하고 ModelAndView를 반환한다.
sendError(400)를 호출했기 때문에 WAS에서 다시 오류 페이지(/error)를 내부 요청한다.

ApiExceptionController - 추가

@GetMapping("/api/response-status-ex1")
public String responseStatusEx1() {
    throw new BadRequestException();
}

결과

{
    "timestamp": "2022-08-30T16:57:33.081+00:00",
    "status": 400,
    "error": "Bad Request",
    "exception": "hello.exception.exception.BadRequestException",
    "path": "/api/response-status-ex1"
}

메시지 기능
reasonMessageSource에서 찾는 기능도 제공한다. reason = "error.bad"
ResponseStatusExceptionResolver에서 MessageSource에 등록된 메시지를 먼저 검색하고 찾지 못 하면 디폴트 메시지를 사용한다.

@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "error.bad")
public class BadRequestException extends RuntimeException {

}

messages.properties

error.bad=잘못된 요청 오류입니다. 메시지 사용

메시지 사용 결과

{
    "timestamp": "2022-08-30T17:03:06.392+00:00",
    "status": 400,
    "error": "Bad Request",
    "exception": "hello.exception.exception.BadRequestException",
    "message": "잘못된 요청 오류입니다. 메시지 사용",
    "path": "/api/response-status-ex1"
}

ResponseStatusException

@ResponseStatus는 개발자가 직접 변경할 수 없는 예외(시스템이나 라이브러리가 제공하는 예외)에는 적용할 수 없다.
(어노테이션을 직접 넣어야 하는데, 내가 코드를 수정할 수 없는 라이브러리의 예외 코드 같은 곳에는 적용할 수 없다.)
추가로 어노테이션을 사용하기 때문에 조건에 따라 동적으로 변경하는 것도 어렵다.
이때는 ResponseStatusException예외를 사용하면 된다.

ApiExceptionController - 추가

@GetMapping("/api/response-status-ex2")
public String responseStatusEx2() {
    throw new ResponseStatusException(HttpStatus.NOT_FOUND, "error.bad", new IllegalArgumentException());
}

ResponseStatusException(HttpStatus, resson(에러 메시지), Throwable cause(진짜 발생하는 예외))

결과

{
    "timestamp": "2022-08-30T17:09:13.619+00:00",
    "status": 404,
    "error": "Not Found",
    "exception": "org.springframework.web.server.ResponseStatusException",
    "message": "잘못된 요청 오류입니다. 메시지 사용",
    "path": "/api/response-status-ex2"
}
출처 : 인프런 김영한 지식공유자님 강의 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
728x90
Comments