Interceptor는 Filter와 마찬가지로 웹 요청이 컨트롤러에 도착하기전에 먼저 작동할 수있는 기능을 제공합니다.
Filter, Interceptor 실행 순서
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러
Filter와 Interceptor의 차이점
Filter는 서블릿에서 제공하는 기술이고,
Interceptor는 스프링MVC가 제공하는 기술입니다.
둘다 공통적인 처리를 가능하게 하지만 적용되는 순서와 범위, 사용방법이 다릅니다.
Interceptor메서드
- preHandle` : 컨트롤러 호출 전에 호출된다. (더 정확히는 핸들러 어댑터 호출 전에 호출된다.)
preHandle의 응답값이 `true` 이면 다음으로 진행하고, `false` 이면 더는 진행하지 않는다. `false` 인 경우 나머지 인터셉터는 물론이고, 핸들러 어댑터도 호출되지 않는다. - postHandle` : 컨트롤러 호출 후에 호출된다. (더 정확히는 핸들러 어댑터 호출 후에 호출된다.)
- afterCompletion` : 뷰가 렌더링 된 이후에 호출된다.

컨트롤러에서 예외가 발생하면 PostHandle은 호출이 되지 않으며, afterCompletion은 항상 호출이 됩니다.
afterCompletion은 예외가 발생하더라도 항상 호출이 되므로 예외와 무관한 공통처리는 afterCompletion을 사용해야합니다.
그렇게 된다면 예외는 ex에 담아서 실행이 됩니다.
가능하다면 Filter보다는 Interceptor를 사용하는게 편리합니다.
사용 예제
@Slf4j
public class logInterceptor 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("POST HANDLER[{}",modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
String requestURI = request.getRequestURI();
Object logId = request.getAttribute(LOG_ID);
log.info("RESPONST [{}][{}][{}]",logId,requestURI,handler);
if(ex != null){
log.error("afterCompletion error!!",ex);
}
}
}
앞에 설명과 같이 3개 메서드에 각각 호출이 되는지 확인하는 로그를 찍어보았습니다.
이제 필터와 마찬가지로 등록을 해주면 됩니다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new logInterceptor())
.order(1)
.addPathPatterns("/**") //모든 요청에 인터셉터 적용
.excludePathPatterns("/css/**","/*.ico","/error"); // 여기에 요청은 제외
}
}
`WebMvcConfigurer가 제공하는 addInterceptors()를 사용해서 인터셉터를 등록할 수 있다.
- registry.addInterceptor(new logInterceptor()) : 인터셉터를 등록한다.
- order(1) : 인터셉터의 호출 순서를 지정한다. 낮을 수록 먼저 호출된다.
- addPathPatterns("/**") : 인터셉터를 적용할 URL 패턴을 지정한다.
- excludePathPatterns("/css/**", "/*.ico", "/error") : 인터셉터에서 제외할 패턴을 지정한다.
기존의 Filter등록과 차이가 좀 더 세밀한 요청URL구분이 가능한 모습입니다.
addPathPartterns에 "/**"가 보이는데 정확한 사용처는
사용예제 2
@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestURI = request.getRequestURI();
HttpSession session = request.getSession(false);
if(session == null || session.getAttribute(SessionConst.LONG_MEMBER) == null){
response.sendRedirect("/login?redirectURL="+requestURI);
return false;
}
return true;
}
}
기본적으로 인터셉터에는 pre,post,after 3종류를 사용할 수 있지만 post와 after는 기본이 default로 되어있어서 굳이 사용하지 않아도 됩니다. 그래서 예제2에서는 preHandle만 불러와서 회원세션을 체크하여 로그인이 되어있지 않다면 현재 uri를 가지고 login페이지로 이동하는 코드를 만들었엇습니다. 이제 등록을 해보겠습니다.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new logInterceptor())
.order(1)
.addPathPatterns("/**") //모든 요청에 인터셉터 적용
.excludePathPatterns("/css/**","/*.ico","/error"); // 여기에 요청은 제외
registry.addInterceptor(new LoginCheckInterceptor())
.order(2)
.addPathPatterns("/**")
.excludePathPatterns("/","/members/add","/login","/logout","/css/**","/*.ico","/error");
}
}
이전에 예제1에서 등록한 인터셉터를 유지한 상태로 방금 만든 인터셉터를 추가하였습니다.
'spring' 카테고리의 다른 글
Validation 정리 (0) | 2024.06.02 |
---|---|
Exception (0) | 2024.06.01 |
Spring Filter (0) | 2024.06.01 |
Session Cookies (0) | 2024.05.31 |
Bean Validation (0) | 2024.05.18 |