필터의 핵심 메서드 [출처] : (https://dololak.tistory.com/598)
- doFilter()는 클라이언트의 요청이 있을때마다 매번 실행
- ServletRequest와 ServletResponse 객체를 넘겨주기 때문에 이를 가지고 요청과 응답을 조작 가능
- 그리고 FilterChain을 통해 조작 이후 요청을 원래 목적지인 서블릿으로 전달
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;
출처: https://dololak.tistory.com/598 [코끼리를 냉장고에 넣는 방법]
(+) 출처
(+) 출처
- 표준 스펙인 필터(Filter)와 달리 Spring이 제공하는 기술로써, 디스패처 서블릿(Dispatcher Servlet)이 컨트롤러를 호출하기 전과 후에 요청과 응답을 참조하거나 가공할 수 있는 기능을 제공한다. 즉, 웹 컨테이너에서 동작하는 필터와 달리 인터셉터는 스프링 컨텍스트에서 동작을 하는 것이다.
- 디스패처 서블릿은 핸들러 매핑을 통해 적절한 컨트롤러를 찾도록 요청하는데, 그 결과로 실행 체인(HandlerExecutionChain)을 돌려준다. 그래서 이 실행 체인은 1개 이상의 인터셉터가 등록되어 있다면 순차적으로 인터셉터들을 거쳐 컨트롤러가 실행되도록 하고, 인터셉터가 없다면 바로 컨트롤러를 실행한다.
- 인터셉터는 스프링 컨테이너 내에서 동작하므로 필터를 거쳐 프론트 컨트롤러인 디스패처 서블릿이 요청을 받은 이후에 동작하게 되는데, 이러한 과정을 그림으로 표현하면 다음과 같다.
코드를 입력하세요
[ 인터셉터(Interceptor)의 메소드 ][출처](https://mangkyu.tistory.com/173)
인터셉터를 추가하기 위해서는 org.springframework.web.servlet의 HandlerInterceptor 인터페이스를 구현(implements)해야 하며, 이는 다음의 3가지 메소드를 가지고 있다.
- preHandle 메소드
- postHandle 메소드
- afterCompletion 메소드
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
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) throws Exception {
}
}
(+) 출처
Filter와 Interceptor 비교
- 필터는 DispatcherServlet 앞에서 먼저 동작하고,
- 인터셉터는 DispatcherServlet에서 Controllr(Handler) 사이에서 동작
필터
웹 어플리케이션의 Context의 기능
스프링 기능을 활용하기에 어려움
일반적으로 인코딩, CORS, XSS, LOG, 인증, 권한 등 을 구현
인터셉터
스프링의 Spring Context의 기능이며 일종의 빈
스프링 컨테이너이기에 다른 빈을 주입하여 활용성이 좋음
다른 빈을 활용 가능하기에 인증, 권한 등을 구현
filter
패키지 만들기
TransactionLogFilter
클래스 만들기public class TransactionLogFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(TransactionLogFilter.class);
@Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
String requestUUID = UUID.randomUUID().toString().split("-")[0];//단순 구분자
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
logger.debug("[{}] start request : {} {}",
requestUUID,
httpServletRequest.getMethod(),
httpServletRequest.getRequestURI()
);
//chain 호출하기 전까지가 filter 이 spring에 전달되기 전
logger.info("* response status code : {}",((HttpServletResponse)response).getStatus());
chain.doFilter(request, response); //chain 호출
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
logger.info("* response status code : {}",((HttpServletResponse)response).getStatus());
logger.info("[{}], send response : {} ",
requestUUID, httpServletResponse.getStatus());
}
public class HeaderLoggingInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(HeaderLoggingInterceptor.class);
@Override
// 이 부분에선 session 관리 등의 기능 수행
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//위 핸들러는 여기 도달하기 위한 핸들러
//어떤 함수에 매핑수행할 건지 정해주기 위함
HandlerMethod handlerMethod = (HandlerMethod) handler;//핸들러형변환
logger.info("start processing of {}", ((HandlerMethod) handler).getMethod().getName());
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()){
String headerName = headerNames.nextElement();
logger.trace("{}: {}", headerName, request.getHeader(headerName));
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
Collection<String> headerNames = response.getHeaderNames();
for (String headerName : headerNames){
logger.trace("{} : {} ", headerName, response.getHeader(headerName));
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
logger.info("start processing of {}", handlerMethod.getMethod().getName());
if (ex != null) logger.error("Exception occurred while processing", ex);
}
//Interceptor 다 만든 후엔 Configuration에 등록시켜줘야 함
}
DemoConfiguration.java
@Configuration
//WebMvcConfigurer 을 implement 수행
//addInterceptors 를 상속받기 위해서 상속받는 것
public class DemoConfig implements WebMvcConfigurer {
private static final Logger logger = LoggerFactory.getLogger(DemoConfig.class);
private final HeaderLoggingInterceptor headerLoggingInterceptor;
public DemoConfig(
@Autowired HeaderLoggingInterceptor headerLoggingInterceptor
){
this.headerLoggingInterceptor=headerLoggingInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry
.addInterceptor(headerLoggingInterceptor)
.addPathPatterns("post/**")
.excludePathPatterns("/except/**");
}
}