필터와 인터셉터는 컨트롤러 진입 이전에 작업을 수행한다.
공통적으로 수행하는 작업에 대한 중복 코드를 제거할 수 있다.

용도는 비슷해보이지만 필터와 인터셉터는 작업 위치가 다르다는 점에서 전혀 다른 기술이다.
필터는 JE22 표준 스펙의 기능으로, 스프링에 국한된 기술이 아니다.
필터는 스프링 컨텍스트 밖의 웹 컨텍스트에서, 디스패처 서블릿에 요청이 전달되기 전, 후에 URL 패턴이 맞는 모든 요청에 대한 추가 작업을 처리한다.

필터 작업은 서블릿 이전에 진행되며 체인 형식으로 작동한다.
필터는 request, response 객체를 직접 전달하여 클라이언트/서블릿에 변경된 요청/응답을 전달한다.
여러개의 필터는 체인으로 구성되어 순차적으로 처리 후 서블릿으로 요청이 전달된다.
스프링 밖에서 작동하지만 Bean으로 등록해 사용할 수 있다. 스프링에서는 web.xml 파일, 스프링 부트에서는 FilterRegistrationBean, @WebFilter 어노테이션으로 필터를 빈에 등록할 수 있다.
주로 보안, 로깅, 인코딩 변환, 데이터 압축 등 모든 요청에 대한 전역적인 작업 처리에 사용된다.
특히 스프링 컨텍스트 바깥에 위치한다는 특성상 요청이 스프링에 전달되기 전에 작업을 처리한다는 점에서 보안상 이점이 있다.
필터를 추가할 떄는 javax.servlet의 필터 인터페이스를 구현한다.
public interface Filter {
public default void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;
public default void destroy() {}
}
init()
필터 객체를 초기화하고 서비스에 추가한다.
웹 컨테이너에서 init()이 1번 호출되어 필터 객체를 초기화한다. 이후에는 doFilter()로 요청을 처리한다.
doFilter()
URL 패턴이 일치하는 모든 HTTP요청에 대해 요청이 디스패처 서블릿에 전달되기 이전에 실행된다.
doFilter() 메서드 실행 전/후에 필요한 작업을 구현하여 전/후처리를 할 수 있다.
destroy()
필터 객체를 서비스에서 제거하고 사용하는 자원을 반환한다. 이후에는 doFilter에 의해 처리되지 않는다.
스프링 컨텍스트 내에서는 일반적으로 ControllerAdvice, @ExceptionHandler 어노테이션을 이용해 예외를 처리한다.
위의 에러 핸들러를 이용하면 작동 중 발생한 예외에 대응하고 커스텀된 응답을 전달해 정상적으로 작동하도록 처리할 수 있다. 이 경우에는 에러가 서블릿까지 전달하지 않는다.
@RestControllerAdvice
public class ErrorHandler {
@ExceptionHandler
public ApiResponseDto handleUserConflict(CustumException e){
log.warn("handleUserConflict", e);
return makeResponse(e.getErrorCode());
}
하지만 필터는 스프링 바깥 영역에서 작동하기 때문에 위와 같이 스프링에서 제공하는 에러 처리 시스템을 사용할 수 없다.
필터 내에서 예외 발생시 서블릿이 에러 응답을 반환하기 때문에 필터 내에서 응답 객체를 수정해 예외를 처리하는 등 다른 방법으로 에러 핸들링을 구현해야 한다.
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse servletResponse = (HttpServletResponse) response;
servletResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
servletResponse.getWriter().print("Member Not Found");
}
}
출처: https://mangkyu.tistory.com/173 [MangKyu's Diary:티스토리]
인터셉트는 스프링 프레임워크가 제공하는 기술이다.
디스패쳐 서블릿과 컨트롤러 사이에 위치하여 요청 전후에 추가 작업을 처리한다.
여러 컨트롤러에서 공통적으로 수행되는 작업에 대해 중복 코드를 줄이기 위해 사용한다.
디스패쳐 서블릿은 핸들러 매핑을 통해 적절한 컨트롤러를 찾아 요청을 전달한다.
핸들러 매핑은 실행 체인을 반환하고 체인에 인터셉터가 등록되어 있다면 순차적으로 인터셉터를 거쳐 최종적으로 컨트롤러가 실행된다. 인터셉터가 없다면 바로 컨트롤러로 넘어간다.

인증/인가, 데이터 전처리 등에 사용한다.
요청이 컨트롤러에 전달되기 전, 사용자의 로그인 상태를 확인해 로그인 페이지로 리다이렉트 시키기, 여러 컨트롤러에 공통적으로 필요한 데이터 전처리 등의 작업이 가능하다.
인터셉트를 추가하기 위해 org.springframework.web.servlet의 HandlerInterceptor 인터페이스를 구현해야 한다.
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 {
}
}
preHandler()
컨트롤러 호출 전에 실행되는 메소드다. 컨트롤러 이전에 처리해야 하는 전처리 작업이나 인가 작업, 요청 정보의 가공이나 추가에 사용한다.
반환타입은 boolean으로 필터와 달리 요청을 직접적으로 제어할 수 없다.
postHandle()
컨트롤러 호출 후에 실행된다. 컨트롤러 이후 처리해야 하느 후처리 작업을 수행한다.
메소드의 실행 결과를 메소드의 실행 결과를 HttpSession 객체에 담아야 할 때
postHandle()를 이용하면 컨트롤러에서 HttpSession을 처리하지 않아도 된다.
컨트롤러 하위 계층에서 작업 진행중 예외가 발생하는 경우 postHandle()은 호출되지 않는다.
afterCompletion()
모든 뷰에서 최종 결과를 생성하는 일을 포함해 모든 작업이 완료된 후에 실행된다.
postHandler와 달리 컨트롤러 하위 계층에서 작업 중 예외가 발생하더라도 afterCompletion은 반드시 호출된다.

필터와 인터셉터는 컨트롤러(비즈니스 로직)과 이전에 수행되어야 하는 작업을 수행해야 할 때 사용한다는 점에서 비슷한 용도를 지닌다.
하지만 필터는 스프링 컨텍스트 바깥에서 작동하는 기능으로 Spring과 분리되어야 하는 작업, 혹은 웹 어플리케이션 전반에 사용되는 기능 구현에 사용된다.
인터셉터는 세부적인 클라이언트의 요청과 관련된 작업에 대한 추가 작업에 사용할 수 있다.