[스프링 MVC] 서블릿 필터 예외처리 방법
RestControllerAdvice로 서블릿 필터 예외처리가 안되는 이유 🥲
일반적으로 스프링을 사용하면 ControllerAdvice
와 ExceptionHandler
를 이용하여 예외처리를 기능을 사용합니다.
(이를 통해 예외가 서블릿으로 전달되지 않고 처리됩니다.^^)
@RestControllerAdvice
public class BasicExceptionHandler {
@ExceptionHandler(BasicException.class)
public ResponseEntity<Object> basicExceptionHandle(BasicException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
}
}
그런데…
스프링 시큐리티를 사용하면....RestControllerAdvice
, ExceptionHandler
가 동작하지 않는 것을 알 수 있습니다.
왜 그럴까요? 😭
우리가 주목해야할 점은 스프링 시큐리티는 필터 체인 방식입니다.
그말은 필터를 사용한다는 의미 입니다.
필터...?!
요청 흐름
HTTP 요청 -> WAS -> 필터 -> 디스패처 서블릿 -> 컨트롤러
여기서 디스패처 전에 필터가 있는것이 보이나요?
저녀석이 바로 서블릿 컨테이너 입니다.!!!!
스프링 시큐리티 구조는 필터 체인이다.
스프링 시큐리티 공식 문서에서 가져온 그림입니다.
보시는 것처럼 필터를 사용하는 것을 알 수 있습니다.
필터는 서블릿 컨테이너의 영역으로DelegatingProxyFilter
의 등장과 스프링 부트에서 내장 톰캣의 사용하여
스프링에서 빈을 등록해서 사용할 수는 있지만, 스프링 컨테이너에서 직접 제어할 수 는 없습니다.
따라서 컨트롤러(디스패처 서블릿) 내부에서 발생한 예외는 RestControllerAdvice
, ExceptionHandler
(인터셉터)를 사용하여 예외 처리를 할 수 있지만,
필터에서 발생한 예외는 필터에서 예외를 처리해야 합니다.^^
필터 예외 처리
테스트를 해봅시다.
필터에서 예외처리를 하기 위해서는 예외가 발생하는 필터의 상위필터에서 예외를 처리해야 합니다.
왜 냐구요? 🤔
필터의 흐름을 살펴 보시죠~!
필터 흐름
필터1 -> 필터2 -> 필터3
필터1 <- 필터2 <- 필터3
위와 같은 순서로 필터가 동작하게 됩니다.
필터3에서 예외가 발생한다면 이보다 상위 필터인 필터1 또는 필터2에서 예외처리를 해야합니다.
그래야 필터2, 필터1에서 예외를 받아서 처리할 수 있겠죠?
필터1 -> 필터2 -> 필터3 (예외 발생!!)
필터1(필터2, 3의 예외 처리 가능) <- 필터2(필터3의 예외 처리 가능) <- 필터3
테스트
FirstFilter
@Component
@Order(0) // 필터 호출 순서
public class FirstFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
System.out.println("FirstFilter 호출");
chain.doFilter(request, response);
System.out.println("FirstFilter 종료");
} catch (RuntimeException e) {
System.out.println(e.getMessage()+" FirstFilter 가 예외 처리한다.");
HttpServletResponse servletResponse = (HttpServletResponse) response;
servletResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST);
servletResponse.getWriter().println(e.getMessage());
}
}
}
SecondFilter
@Component
@Order(1) // 필터 호출 순서
public class SecondFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("SecondFilter 호출");
chain.doFilter(request, response);
System.out.println("SecondFilter 종료");
}
}
ThirdFilter
@Component
@Order(2) // 필터 호출 순서
public class ThirdFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
throw new RuntimeException("ThirdFilter error!!");
}
}
TestController
@RestController
public class TestController {
@GetMapping("/")
public String test() {
LocalDateTime now = LocalDateTime.now();
return now.toString();
}
}
결과
'0+ 스프링 > 0+ 스프링 MVC' 카테고리의 다른 글
[스프링 MVC] 어떻게 컨트롤러는 다양한 종류의 파라미터를 받아서 처리할 수 있을까? 🤔 (0) | 2023.05.27 |
---|---|
[스프링 MVC] 서블릿 필터가 있는데 인터셉터는 왜 나온거지? (0) | 2023.05.26 |
[스프링 MVC] 서블릿 필터를 어떻게 스프링 빈으로 관리할 수 있을까? (0) | 2023.05.25 |
[스프링 MVC] XML 데이터 파싱(RestTemplate) (0) | 2023.05.06 |
[스프링 MVC] Java에서 서블릿이 등장한 이유(Feat. 서블릿 기초 개념) (0) | 2023.03.28 |