API 예외 처리 - HandlerExceptionResolver 활용

현시기얌·2021년 8월 17일
0

Api 예외처리

목록 보기
2/6

예외 발생 시 불편한점

예외가 발생하면 WAS까지 예외가 던져지고, WAS에서 오류 페이지 정보를 찾아서 다시 /error를 호출하는 과정은 생각해보면 너무 복잡하다. ExceptionResolver를 활용하면 예외가 발생했을 때 이러한 복잡한 과정 없이 ExceptionResolver에서 문제를 깔끔하게 해결할 수 있다.

사용자 정의 예외 추가하기

public class UserException extends RuntimeException{

    public UserException() {
        super();
    }

    public UserException(String message) {
        super(message);
    }

    public UserException(String message, Throwable cause) {
        super(message, cause);
    }

    public UserException(Throwable cause) {
        super(cause);
    }

    protected UserException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

사용자 정의 예외 ExceptionResolver

@Slf4j
public class UserHandlerExceptionResolver implements HandlerExceptionResolver {

    private final ObjectMapper objectMapper;

    public UserHandlerExceptionResolver(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }


    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
       try{
           if (ex instanceof UserException) {
               log.info("UserException resolver to 400");
               String acceptHeader = request.getHeader("accept");
               response.setStatus(HttpServletResponse.SC_BAD_REQUEST);

               if ("application/json".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("application/json");
                   response.setCharacterEncoding("utf-8");
                   response.getWriter().write(result);
                   return new ModelAndView();
               }
               return new ModelAndView("error/500");
           }
       } catch (IOException e){
           log.error("resolver ex", e);

       }
       return null;
    }
}

WebConfig

@Configuration
public class WebConfig implements WebMvcConfigurer {

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

결과

Accept값이 application/json일 때

Accept값이 application/json이 아닐 때

정리

ExceptionHandler를 사용하면 컨트롤러에서 예외가 발생해도 ExceptionResolver에서 예외를 처리해버린다.
따라서 예외가 발생해도 서블릿 컨테이너까지 예외가 전달되지 않고, 스프링 MVC에서 예외 처리는 끝이 난다.
결과적으로 WAS입장에서는 정상 처리가 된 것이다.
이렇게 예외를 이곳(ExceptionHandler)에서 모두 처리할 수 있다는 것이 핵심이다.

서블릿 컨테이너까지 예외가 올라가면 복잡하고 지저분하게 추가 프로세스가 실행된다. 반면에 ExceptionResolver를 사용하면 예외처리가 상당히 깔끔해진다.

profile
현시깁니다

0개의 댓글