-
스프링 인터셉터
스프링 인터셉터도 서블릿 필터와같이 웹과 관련한 공통 사항을 효과적으로 해결 할 수 있다.
서블릿 필터가 서블릿이 제공하는 기능이고 스프링 인터셉터는 스프링 MVC가 제공하는 기술이다.
하지만 이 둘은 적용되는 순서와 범위 사용방법이 다르다.스프링 인터셉트가 훨씬 더 많은 기능을 제공한다.
HTTP요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러
이것은 필터
HTTP요청-> WAS -> 필터 -> 서블릿 -> 컨트롤러
여기서의 서블릿은 스프링 MVC에서 사용하므로 디스패쳐 서블릿이다.
스프링 인터셉터는 디스패쳐서블릿과 컨트롤러 사이에서 컨트롤러 호출 직전에 호출된다.
스프링 인터셉터는 스프링 MVC가 제공하는 기능이기 때문에 결국 디스패쳐 서블릿 이후에 등장하게 된다.
또한 URL패턴도 적용할 수 있다 .HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러 //로그인 사용자 HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터(적절하지 않은 요청이라 판단, 컨트롤러 호출(X)) // 비 로그인 사용자
또한 적절하지 못한 요청이라고 판단하면 바로 끝낼 수 있다.
체인 구성도 가능하며 중간에 인터셉터를 자유롭게 추가할 수 있다.
스프링 인터셉터의 구조
public interface HandlerInterceptor { default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {} default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {} default void afterCompletion(HttpServletRequest request, HttpServletResponse response,Object handler, @Nullable Exception ex) throwsException {} }
HandlerInterceptor를 구현하면 된다.
서블릿 필터의 경우 단순하게 doFilter() 하나만 제공된다.
하지만 인터셉터는 컨트롤러 호출 전에 preHandle(), 호출 후에 postHandle() , 요청 완료 이후에 afterCompletion() 와 같이 단계적으로 잘 세분화 되어 있다.
또한 어떤 컨트롤러handler가 호출되었는지 호출 정보도 받는것이 가능하다.- 디스패쳐 서블릿은 먼저 preHandle을 호출한다.
- 그다음 핸들러를 호출하고 Model&View를반환한다.
- 그다음 postHandle을 호출한다.Model&View도 넘겨준다.
- view를 랜더링 하고 afterCompletion을 호출한다.
preHandle의 응답값이 true이면 다음을 진행하고, false면 더 진행하지 않는다.
예외가 발생하면
- preHandle이 컨트롤러 호출전에 호출된다.
- postHandle은 예외가 발생하면 호출되지 않는다.
- 단, afterCompletion은 항상 호출된다. 이때 파라미터로 Exception이 넘어오는데 오류log를 출력하는 등으로 사용할 수 있다.
@Slf4j public class Interceptor implements HandlerInterceptor { public static final String LOG_ID = "logId"; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String requestURI = request.getRequestURI(); String uuid = UUID.randomUUID().toString(); request.setAttribute(LOG_ID, uuid); if (handler instanceof HandlerMethod) { HandlerMethod hm = (HandlerMethod) handler; } log.info("REQUEST [{}][{}][{}]", uuid, requestURI, handler); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { log.info("postHandle [{}]", modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { String requestURI = request.getRequestURI(); String logId = (String)request.getAttribute(LOG_ID); log.info("RESPONSE [{}][{}]", logId, requestURI); if (ex != null) { log.error("afterCompletion error!!", ex); } } }
보시다시피 HandlerInterceptor를 오버라이딩 하여 적용한 모습이다.
- request.setAttribute(LOG_ID, uuid)
서블릿 필터의 경우 지역변수로 해결이 가능하지만, 스프링 인터셉터는 호출 시점이 완전히 분리되어 있다.
따라서 preHandle 에서 지정한 값을 postHandle , afterCompletion 에서 함께 사용하려면 어딘가에 담아두어야 한다. LogInterceptor 도 싱글톤 처럼 사용되기 때문에 맴버변수를 사용하면 위험하다.
따라서 request 에 담아두었다. 이 값은 afterCompletion 에서 request.getAttribute(LOG_ID 로 찾아서 사용한다.- return true
true 면 정상 호출이다. 다음 인터셉터나 컨트롤러가 호출된다.
인터셉터는 작성후 MVC에서 제공하기 때문에
WebMvcConfigurer
를 상속하여 addInterceptors를 override해주어야 한다.
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LogInterceptor()) .order(1) .addPathPatterns("/**") .excludePathPatterns("/css/**", "/*.ico", "/error"); }
excludePatter으로 해당 인터셉터를 적용시키지 않을 경로를 명시하면 된다.
필터와 비교해보면 인터셉터는 addPathPatterns , excludePathPatterns 로 매우 정밀하게 URL 패턴을 지정할 수 있다.
728x90'스프링' 카테고리의 다른 글
Swagger 이용하기 (0) 2023.01.09 인터셉터-2 (0) 2023.01.08 필터-2 (0) 2023.01.08 필터-1 (0) 2023.01.08 로그인 처리 - 세션3 (0) 2023.01.07