스프링/4. 스프링 MVC-2

69. API를 위한 예외처리 기능

sdafdq 2023. 9. 13. 22:04

HandlerExceptionResolver.

 

컨트롤러에서 예외가 발생했다면,

 

그 예외를 어떻게 처리할 지 구현할 수 있는 인터페이스이다.

 

public interface HandlerExceptionResolver {
	@Nullable
	ModelAndView resolveException(
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex);

}

이것이 실제 HandlerExceptionResolver의 인터페이스이다. 이 추상체를 구현하면 되는거다.

 

 

위 인터페이스명과 함수명도 그렇고,

예외를 해결해 주는 것이다.

 

만약 Exception ex <- ~~~ 이러 한 예외가 넘어 왔다. 하면

이 예외에 대해 처리해 준 후, 정상적인 MdelAndView를 반환할 수 있게 해준다.

 

 

 

구현해 보겠다.

@Slf4j
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        try{
            if(ex instanceof IllegalArgumentException){
                response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
                return new ModelAndView();
            }
        } catch (IOException e){
            log.error("resolver ex", e);
        }
        return null;
    }
}

간단하게 그냥 IllegalArgumentException인 예외면

에러를 400(SC_BAD_REQUEST)로 바꿔서 보낸다는거다.

 

또, 예외 해결사인 이름 만큼 예외를 얘가 먹어버리는 거다.

return new ModelAndView() 해주면 이제 예외는 얘가 먹고 그냥 return~~ 하면서 응답 이어서 되는거다. response.sendError() 했으니 응답으로 예외가 보내질 것이다.

저거 안하더라도, ModelAndView를 잘 꾸며 정상적이게 보이게끔 처리도 가능하다.

 

return null을 하면, 예외를 얘가 먹어버리지 않고, 계속 타고 올라간다.

참고로, 얘가 호출되는 지점은 이렇다.

컨트롤러에서 예외가 발생하면, 그게 타고 올라가다가 DispatcherServlet에 가고, 그 예외를 ExceptionResolver한테 준다.

 

여기서 우리가 ExceptionResolver가 null이 아닌 ModelAndView를 return 하게끔 구현해 놨다면, 그냥 정상적으로 동작하는거다.

 

우리가 구현한 것이 return으로 비어있는 ModelAndView를 반환하지만, 그래도 정상응답으로 생각한다.

 

 

 

@Override
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
    resolvers.add(new MyHandlerExceptionResolver());
}

이렇게 WebConfig에 등록해 놔야 한다.

스프링의 기능을 이용한다는 것은 무언가 상속받아서(혹은 애노테이션을 붙여서) 구현하고, 그걸 스프링에 등록하는 것이다.

 

 

 

이름 그대로 예외를 해결하여 정상흐름 처럼 변경하는 것.

 

 

 

return의 종류에 따라 동작 방식을 설명한 다면,

 

비어있는 ModelAndView : 비어있기에 참조할 뷰 이름이 없어 랜더링 하지 않고, 정상흐름으로 서블릿으로 감.

채워져 있는 ModelAndView : View, Model등의 정보가 있을 경우 그 뷰를 따라서 랜더링 한다.

null : 예외를 자기가 먹지 않고 위로 뱉는다. 참고로 ExceptionResolver는 여러 개 등록 할 수 있고, 그 여러                                   ExceptionResolver 중 없으면 예외를 서블릿으로 던진다.

 

 

 

ExceptionResolver는 보통 다음과 같은 목적으로 활용된다.

예외 상태 코드 변환 : 보통 앞서 IllegalArgumentException는 잘못된 인수, 즉 사용자가 값을 잘못 넣었을 수도 있다. 그래서 원래 서버에서 예외터지면 500에러코드인데 그걸 400코드로 바꿔서 response.sendError()했다

 

뷰 템필릇 처리 : ModelAndView에 값을 채워 예외에 따른 새로운 오류화면 뷰를 보여준다.

 

API 응답 처리 : response.getWriter() 등 처럼 직접 메시지 바디에 넣을 수 있으므로, 예외 정보를 Json 형태로 만들어서 반환한다.

 

 

 

참고로 configureHandlerExceptionResolvers 도 있는데, 스프링이 기본으로 제공하는 ExceptionResolver가 제거되기 때문에, extendHandlerExceptionResolvers를 상속받아 사용하자.