2016년 8월 30일 화요일

spring mvc의 exceptionHandler에서 redirect 할 경우 주의해야할 점

spring 의 exceptionHandler를 사용하는 경우 보통 다음과 같은 형태이다.
@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ModelAndView handleError(SomeException exception) {
        ExceptionMessage exceptionMessage = new ExceptionMessage();
        // exception 결과 표시용 객체 처리
        return new ModelAndView("/error", exceptioMessage);
    }
}

응답 결과를 redirect 하는 경우는 redirect: 를 사용한다.

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ModelAndView handleError(SomeException exception) {
        ExceptionMessage exceptionMessage = new ExceptionMessage();
        // exception 결과 표시용 객체 처리
        return new ModelAndView("redirect:/error", exceptioMessage);
    }
}
그런데 이 경우 redirect가 동작하지 않는 문제점이 있다.

이유는 바로 @ResponseStatus 어노테이션 때문이다.

리다이렉트 처리는 302로 응답을 내려보내고 다시 redirect할 주소로 이동을 해야하는데 @ResponseStatus가 명시되어 있으면 해당 status 로 응답이 처리되어 redirect가 동작하지 않는다.

따라서 redirect를 해야할 경우 status는 메소드 내의 view의 status 선언으로 처리를 해야한다.

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler
    //@ResponseStatus(HttpStatus.BAD_REQUEST)
    public ModelAndView handleError(SomeException exception) {
        ExceptionMessage exceptionMessage = new ExceptionMessage();
        // exception 결과 표시용 객체 처리
        ModelAndView modelAndView = new ModelAndView("redirect:/error", exceptioMessage);
        return modelAndView;
    }
}


html, json 요청에 따라 redirect html, json response 처리를 하는 것은 이전 글을 참조하면 된다.
[ spring mvc의 exceptionHandler에서 mediaType 정보 획득하기 ]

만약 동일 Exception에 대해 status 처리를 분기하고 싶은 경우 (또는 위처럼 redirect가 있거나 exception status 처리를 나눠야 하는 경우)는 다음과 같이 처리를 한다.

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler
    //@ResponseStatus(HttpStatus.BAD_REQUEST)
    public ModelAndView handleError(SomeException exception, HttpServletResponse response) {
        ExceptionMessage exceptionMessage = new ExceptionMessage();
        if (리다이렉트의 경우) {
            // exception 결과 표시용 객체 처리
            ModelAndView modelAndView = new ModelAndView("redirect:/error", exceptioMessage);
            return modelAndView;
        }
        // http status코드를 내려야하는 경우
        ModelAndView modelAndView = new ModelAndView(PAGE_ERROR, resultMap);
        response.setStatus(HttpStatus.BAD_REQUEST.value());
        return modelAndView;
    }
}


ModelAndView의 setStatus 메소드를 사용하는 것이 exception 처리에서는 제대로 동작하지 않는 듯 하다.

댓글 없음:

댓글 쓰기