스프링에는 HandlerExceptionResolverComposite 이라는 파일에 다음 순서로 ExceptionResolver 들이 등록되어있다.
- ExceptionHandlerExceptionResolver: 이 예외 해결자는 사용자가 정의한 @ExceptionHandler 메서드를 찾아서 예외를 처리합니다. 따라서 가장 먼저 호출되어 예외가 발생한 경우에 대해 사용자가 정의한 처리 로직을 수행합니다.
- ResponseStatusExceptionResolver: 이 예외 해결자는 @ResponseStatus 애노테이션이 적용된 예외를 처리합니다. 예외에 해당 애노테이션이 적용되어 있으면 설정된 HTTP 상태 코드와 함께 해당 응답을 반환합니다. 따라서 두 번째로 호출됩니다.
- DefaultHandlerExceptionResolver: 이 예외 해결자는 기본적인 예외 처리 로직을 수행합니다. 컨트롤러에서 발생한 예외를 처리하고 기본적인 오류 페이지로 리디렉션합니다. 따라서 마지막으로 호출됩니다.
커스텀 ExceptionResolver가 있을 시 맨처음 수행됩니다.
HandlerExceptionResolver의 기본 흐름과 목적(Exception Resolver)
(인터셉터가 적용되어 있는것 주의)
1. preHandle을 호출한다
2. 핸들러(컨트롤러)를 호출한다
3. 예외가 발생한다
4. postHandle은 호출되지 않고 afterCompletion이 되어진다
1. preHandle을 호출한다
2. 핸들러(컨트롤러)를 호출한다
3. 예외가 발생한다
4. postHandle을 여전히 호출되지 않고 ExceptionResolver에 예외를 처리할 수 있는지 확인한다
5. afterCompletion을 호출한다
6. 만약 ExceptionResolver에서 처리할 수 있다면 ModelAndView를 반환한다
ExceptionResolver의 종류
ExceptionResolver를 찾지 못하면 다음 Resolver를 검색하는데 이 과정에서 우선순위가 존재하며 아래와 같다
1. ExceptionHandlerExceptionResolver
: Spring MVC에서 예외를 처리하는 방법을 결정하는 데 사용되는 예외 해결자입니다. 이 해결자는 컨트롤러에서 발생한 예외를 처리하고 적절한 응답을 생성합니다.
일반적으로 @ExceptionHandler 애노테이션과 함께 사용되며, 이 애노테이션을 메서드에 적용하여 특정 예외를 처리하는 메서드를 지정할 수 있습니다.
@ControllerAdvice // 전역 예외 처리를 위한 어노테이션
public class DemoExceptionHandler {
@ExceptionHandler(Exception.class) // 예외 타입을 지정하여 처리할 메소드를 정의합니다.
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) // 응답 상태 코드를 설정합니다.
@ResponseBody // 응답 본문을 설정합니다.
public String handleException(Exception e) {
return "예외가 발생했습니다: " + e.getMessage();
}
}
RETURN TYPE
• @ReponseBody
• HttpEntity<B>, ResponseEntity<B>
• String
• View
• Map, Model
• @ModelAttribute
@ExceptionHandler 또한 예외처리에서 우선순위 (부모예외처리 후 자식예외처리 )
@ExceptionHandler(부모예외.class)
public String 부모예외처리()(부모예외 e) {}
@ExceptionHandler(자식예외.class)
public String 자식예외처리()(자식예외 e) {}
여러 Exception처리
@ExceptionHandler({AException.class, BException.class})
public String ex(Exception e) {
log.info("exception e", e);
}
2. ReponseStatusExceptionResolver
: Spring MVC에서 HTTP 응답 상태 코드를 설정하는데 사용되는 예외 해결자입니다. 이 해결자는 @ResponseStatus 애노테이션이 적용된 예외를 처리하고, 해당 애노테이션에서 지정한 HTTP 응답 상태 코드와 함께 클라이언트에게 응답을 반환합니다.
@ResponseStatus(code = HttpStatus.BAD_REQUEST, reason = "잘못된 요청 오류")
public class BadRequestException extends RuntimeException {
}
ResponseStatusExceptionResolver가 작동하는 코드를 확인해보면 결국 서블릿의
response.sendError(statusCode, resolvedReson)을 사용하기 때문에 sendError(400)을 호출하게 되면 WAS에서 오류 페이지를 요청하게 됩니다.
@GetMapping("/api/responsereoslver")
public String responseStatus() {
throw new BadRequestException();
}
이를 위와 같이 API 오류에 반환하게 된다면 아래와 같이 출력됩니다.
{
"status": 400,
"error": "Bad Request",
"exception": "hello.exception.exception.BadRequestException",
"message": "잘못된 요청 오류",\
"path": "/api/responsereoslver"
}
3. DefaultHandlerExceptionResolver
DefaultHandlerExceptionResolver는 Spring MVC에서 기본적인 예외 처리를 수행하는 예외 해결자입니다. 이 예외 해결자는 컨트롤러에서 발생한 예외를 처리하고 기본적인 오류 페이지로 리디렉션합니다.
일반적으로 컨트롤러에서 발생한 예외를 처리하기 위해 @ExceptionHandler 애노테이션을 사용하는 것이 일반적입니다. 그러나 @ExceptionHandler로 처리되지 않은 예외는 DefaultHandlerExceptionResolver가 처리합니다.
이때 DefaultHandlerExceptionResolver가 각 상황에 맞는 응답 코드를 리턴해줍니다.
요청에 맞는 컨트롤러(핸들러)를 못 찾는 경우 -> 404 Not Found
컨트롤러 실행 중 예외가 발생하는 경우 -> 500 Internal Server Error
컨트롤러의 파라미터 타입 미스매치 경우 -> 400 BadRequest
정리
4.1. 예외가 발생하였기 때문에 ExceptionResolver가 작동한다, 이때 가장 우선순위가 높은 @ExceptionHandler에서 가 작동하고 해당 컨트롤러에 발생한 예외를 처리할 수 있는 @ExceptionHanlder가 존재하는지 확인한다
4.2. ResponseStatus에 지정된 응답 코드를 반환한다
5. afterCompletion 호출
6. 예외처리가 되었으므로 API 응답
https://whitepro.tistory.com/392
https://maenco.tistory.com/entry/Spring-MVC-API-Error-API-%EC%98%A4%EB%A5%98-%EC%B2%98%EB%A6%AC
'WEB개발' 카테고리의 다른 글
[SPRING] BEAN (0) | 2023.03.06 |
---|---|
[Spring] 주석2 (Annotation) (0) | 2023.01.19 |
[WEB기본] forward vs redirect (0) | 2023.01.02 |
[WEB기본] Servlet & JSP(EL, JSTL) (0) | 2022.11.23 |
[WEB기본] html선언 (0) | 2022.06.28 |