HandlerExceptionResolver
발생하는 예외에 따라 상태 코드, 오류 메시지, 형식 등을 다르게 처리할 수 있다.
HandlerExceptionResolver는 예외가 컨트롤러 밖으로 던져진 경우의 동작을 새로 정의할 수 있다.
줄여서 ExceptionResolver라고 한다.
기존에는 IllegalArgumentException을 400으로 처리하고 싶어도 호출하면 500으로 처리해버린다.
적용 전
요청이 컨트롤러에 전달됐다가 실패한다.
postHandle()은 건너뛰고 afterCompletion()을 호출한다.
WAS에 예외가 전달된다.
적용 후
요청이 컨트롤러에 전달됐다가 실패한다.
DispatcherServlet에 예외가 반환되면 ExceptionResolver에게 처리할 수 있는지 물어본다.
ExceptionResolver가 예외를 해결하려고 시도하고 ModelAndView를 반환한다.
이때 예외를 해결해도 postHandle()은 호출되지 않는다.
afterCompletion()을 호출한다.
ModelAndView에 따라 뷰를 렌더링 하거나 하지 않고 바로 WAS에 반환한다.
WAS는 sendError()가 호출됐음을 알고 오류 페이지를 뒤진다.
핸들러 정보와 발생한 예외를 가지고 처리하는 것을 알 수 있다.
MyHandlerExceptionResolver
IllegalException이 발생하면 response.sendError(400)을 호출해 상태 코드를 지정하고 빈 ModelAndView를 반환한다.
try-catch처럼 예외를 처리해 정상 흐름처럼 변경하기 위해 ModelAndView를 반환한다.
ExceptionResolver의 반환 값에 따른 DispatcherServlet의 동작 방식
빈 ModelAndView
뷰를 렌더링 하지 않고 정상 흐름으로 서블릿을 리턴한다.
ModelAndView 지정
ModelAndView에 View, Model 정보를 지정해서 반환하면 뷰를 렌더링 한다.
null
다음 ExceptionResolver를 찾아 실행한다.
처리할 수 있는 ExceptionResolver가 없으면 예외 처리를 하지 않고 서블릿 밖으로 던진다.
Exception Resolver 활용
예외 상태 코드 변환
response.sendError() 호출로 상태 코드에 따라 오류를 처리하도록 위임한다.
WAS는 sendError()를 보고 알맞은 서블릿 오류 페이지를 찾는다.
ex. 스프링 부트가 기본으로 설정한
/error
페이지를 호출한다.
뷰 템플릿 처리
ModelAndView에 값을 채워서 예외에 따라 새로운 오류 화면을 렌더링 해서 제공한다.
API 응답 처리
response.getWriter().println("hello")처럼 HTTP 응답 바디에 직접 데이터를 넣을 수 있다.
여기에 JSON을 넣으면 API 응답 처리를 할 수 있다.
ExceptionHandler 등록
등록 방식에는 2가지가 있다.
configureHandlerExceptionResolvers()
스프링이 기본으로 등록하는 ExceptionResolver가 제거된다.
extendHandlerExceptionResolvers()
따라서 이 메서드를 활용하자.
예외를 여기서 마무리하기
굳이 WAS까지 예외를 던지고 WAS에서 다시 오류 페이지 정보를 찾아 호출하는 것은 복잡하다.
ExceptionResolver에서 예외를 깔끔하게 마무리 해보자.
user-ex를 호출하면 dispatcherServlet을 거친 걸 알 수 있다.
HTTP 요청 헤더의 Accept가
application/json
이면 JSON으로 오류를 내려준다.그 외에는
error/500
에 있는 HTML 오류 페이지를 보여준다.
application/json
요청에는 직접 만든 오류 메시지가 뜬다.로그를 보면 UserHandlerExceptionResolver만 찍히고 dispatcherServlet은 찍히지 않았다.
서블릿 컨테이너까지 갔다가 다시 호출하는 번거로운 작업을 하지 않았다.
그 외 요청은 html 화면을 반환한다.
정리
ExceptionResolver를 사용하면 컨트롤러에서 예외가 발생해도 ExceptionResolver에서 처리한다.
서블릿 컨테이너까지 예외가 전달되지 않고 스프링 단에서 끝난다.
결과적으로 WAS 입장에서는 정상 처리로 인식한다.
예외를 모두 ExceptionResolver 한 곳에서 처리할 수 있는 것이 핵심이다.
Last updated