
Filter
사용자의 HTTP 요청과 응답이 서블릿에 도달하기 전, 후에
가로채 처리를 수행하는 컴포넌트
Spring 에서는 DispatcherServlet 앞에서 모든 요청, 응답을 처리한다
Interceptor 와 차이?
Interceptor 는 Spring 에서만 작동하는 것
또한 컨트롤러 전, 후에서 제어
다시 한번 되짚어 보는 실행 순서
요청
→ Filter (Request를 처리하는)
→ DispatcherServlet
→ Interceptor.preHandle()
→ Controller
→ Interceptor.postHandle()
→ View 렌더링
→ Interceptor.afterCompletion()
→ Filter (Response를 처리하는)
→ 응답
Filter의 종류
OncePerRequestFilter
요청 당 한 번만 실행되도록 보장
요청 당 한번만 이라는게 무슨 소리일까?
우선 먼저 Dispatch 라는 개념을 알아야 한다
여기서 Dispatch 는 적절한 핸들러로 전달하는 것을 말한다
Spring 에서는 한 요청에 대해 여러번 Dispatch 가 발생할 수 있다예를 들어서,
요청 → DispatchServlet → Controller (사이에서 1번째)
→ 다른 url 로 처리되도록 forward
→ DispatchServlet → url 에 매핑된 다른 Controller (사이에서 2번째)
또한 비동기처리 시 처리 후 다시
DispatcherServlet에 접근하게 되므로 Dispatch가 계속 발생할 수 있다
그럴 때마다 Filter 가 동작하니, OncePerRequestFilter 는
처음 한번만 하겠다는 것
인증/인가, 로깅, 트랜잭션 관리 같은 곳에 사용
CharacterEncodingFilter
모든 요청/응답에 지정한 인코딩(UTF-8 등)을 적용
RequestContextFilter
현재 요청을
RequestContextHolder에 바인딩@RequestScopeBean 사용 시 필요
Filter 사용법
@Component
public class MyFilter implements Filter {
@Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain
) throws IOException, ServletException {
// 요청 후
chain.doFilter(request, response); // 계속 진행
// 응답 전
}
}
// OncePerRequestsFilter
@Component
public class MyFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain
) throws ServletException, IOException {
// 요청 후
filterChain.doFilter(request, response); // 계속 진행
// 응답 전
}
// 제외 조건
// 만약 /go 로 시작하는 URL은 필터 통과
@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
return request.getRequestURI().startsWith("/go");
}
}만약 여러개의 필터가 실행되어야 한다면?
FilterChain이 해결해준다, 다만 순서는 @Order 어노테이션으로 해야한다
@Slf4j
@Order(1)
@Component
public class TestFilter2 extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 요청
log.info("Test Filter2 IN");
filterChain.doFilter(request, response);
// 응답
log.info("Test Filter2 OUT");
}
}@Slf4j
@Order(2)
@Component
public class TestFilter2 extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
// 요청
log.info("Test Filter2 IN");
filterChain.doFilter(request, response);
// 응답
log.info("Test Filter2 OUT");
}
}필터의 전체 작동의 흐름은
Test Filter 1 IN → Test Filter 2 IN → Test Filter 2 OUT → Test Filter 1 OUT