🌿 스프링/스프링 MVC 2편

서블릿 필터와 스블릿 인터셉터

le2donguk 2026. 2. 15. 01:20

개요

로그인이 안 된 사용자는 로그인하라고 가게하고 로그인이 된 사용자만 우리 페이지를 보여주고 싶다

이런 건 모든 컨트롤러의 공통으로 해야 하는 과제다 

컨트롤러 하나 하나 하는게 아니라 요청이 오면 요청을 검사하는 공통으로 해야 하는 과제가 생겼다 

 

요구사항 

  • 지금 이 사용자가 로그인 됐는지 확인
  • 로그인이 안됐으면 리다이렉트 페이지로
  • 로그인이 됐으면 계속 이용하게 하자 

스프링 필터

 

필터의 위치

HTTP 요청 -> WAS(response,request객체) -> 필터 -> Dispatcher서블릿 -> 컨트롤러

 

스프링의 필터의 위치는 ServletContainer 안에 존재한다. 그리고 그중에서도 DispatcherServlet 앞단에 존재한다 

그래서 필터를 이용해 모든 고객의 요청 로그를 남길 수도 있다 

 

참고
HttpServletReqeust, HttpServletResponse 는 인터페이스야 이 인터페이스를 보고 WAS(Tomcat)가 구현객체인 response, request를 만들어줘 이 안에 무수한 많은 기능들이 있음을 이제까지 봤음. getCookie , getSession, getHeader.. 등등 이렇게 만든 그래서 Tomcat이 이래서 필요한 거군 아!!!

 

 

 

 

서블릿 필터 인터페이스

인터페이스는 는 다음과 같이 생겼다

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() {}
}

 

 

메서드는 총 3개가 있는데 진짜로 구현 해야하는 메소드는 doFilter다 

(왜냐면 default 가 붙여져 있어서 기본으로 구현되어 있다)

 

각 Method의 역할은 다음과 같다

  • init(): 필터 초기화 메서드, 서블릿 컨테이너가 생성될 때 호출된다
  • doFilter(): 고객의 요청이 올 때마다 해당 메서드가 호출된다. 필터의 로직을 구현하면 된다.
  • destroy(): 필터 종료 메서드, 서블릿 컨테이너가 종료될 때 호출된다.

 

 

 

 

우리만의 필터를 만들려면 이 필터 인터페이스를 구현해야 한다

@Slf4j
public class LogFilter implements Filter{

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("log filter init");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("log filter doFilter");

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();

        String uuid = UUID.randomUUID().toString();

        try {
            log.info("REQUEST [{}][{}]",uuid,requestURI);
            chain.doFilter(request,response);
        } catch (Exception e) {
            throw e;
        }finally {
            log.info("RESPONSE[{}][{}]",uuid,requestURI);
        }


    }

    @Override
    public void destroy() {
        log.info("log filter destory");
    }
}

 

 

doFilter에서 우리가 구현해야 하는 Fitler 로직을 구현해 주면 된다

여기서 중요한 점은

chain.doFilter(request,response);

 

이걸 꼭 해야 한다!!!!!!!!!!

그래야 스프링이 제공하는 다음 필터로 넘어가서 컨트롤러까지 쭉 요청이 갈 수 있다 이걸 안 하면 여기서 그냥 막히고 끝난다...

 

다시 한번 말하는데 꼭 doFilter를 해야 한다

 

 

 

 

 

 필터를 등록하자

@Configuration
public class WebConfig implements WebMvcConfigure {

    @Bean
    public FilterRegistrationBean logFilter() {
        FilterRegistrationBean<Filter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
        filterFilterRegistrationBean.setFilter(new LogFilter());
        filterFilterRegistrationBean.setOrder(1);
        filterFilterRegistrationBean.addUrlPatterns("/*");

        return filterFilterRegistrationBean;
    }
}

 

 

필터를 등록할 때 FilterRegistrationBean을 반환하는 빈을 설정해야 한다

오버라이드를 제공을 안 해서 조금 번거롭다

 

해당 빈에 우리의 필터를 등록하고(setFilter)

우선순위를 설정한 다음 (setOrder())

필터를 통과할 Url을 설정한다 (addUrlPatters)


 

스프링 인터셉터

 

스프링 인터셉터도 공통 관심 사항을 효과적으로 해결할 수 있는 기능인데 서블릿 필터는 서블릿이 제공하는 기능이고 스프링 인터셉터는 스프링 MVC 가 제공하는 기술이다

 

흐름

HTTP요청 -> WAS -> 서블릿 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러

 

스프링 인터셉터는 Dispatcher 서블릿과 컨트롤러를 호출 직전에 호출한다

스프링 인터셉터도 URL 패턴을 적용할 수 있는데 서블릿 URL 패턴과는 다르게 매우 정밀하게 설정 가능하다

 

이렇게 생각하자

  • 서블릿 필터 들어가기 전에 → 서블릿 필터
  • 서블릿 필터 나오고 난 후 → 스프링 인터셉터

 

 

 

 

인터페이스 

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) throws Exception {}

 

  • preHandle
    → 응답이 true 면 다음 인터셉터 or Controller 호출 → 응답이 false 면 더 이상 진행 X
    → 핸들러 어댑터 호출 전에 호출됨
  • postHandle
    → 컨트롤러 호출 후
  • afterCompletion
    → 뷰가 렌더링 된 이후에 호출

 

 

인터셉터의 예외

 

인터셉터의 예외 상황

 

예외가 발생 시

  • preHandle: 컨트롤러 호출 전에 호출된다.
  • postHandle :컨트롤러에서 예외가 발생하면 postHandle 은 호출되지 않는다.
  • afterCompletion: afterCompletion 은 항상 호출된다. 이 경우 예외( ex)를 파라미터로 받아서 어떤 예외가 발생했는지 로그로 출력할 수 있다

 

 

afterCompletion은 예외가 발생해도 호출된다.

  • 예외가 발생하면 postHandle()는 호출되지 않으므로 예외와 무관하게 공통 처리를 하려면 afterCompletion()을 사용해야 한다.
  • 예외가 발생하면 afterCompletion()에 예외정보(ex)를 포함해서 호출된다.

 

서블릿 필터를 사용할 특수한 상황이 아니라면 인터셉터를 사용하자

 

 

 

 

 

요구사항에 맞춰 인터셉터를 구성해 보면


@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestURI = request.getRequestURI();

        log.info("인증 체크 인터셉터 실행 {}", requestURI);

        HttpSession session = request.getSession();

        if (session == null || session.getAttribute(SessionConst.LOGIN_MEMBER) == null) {
            log.info("미인증 사용자 요청 입니다");
            //로그인으로 리다이렉트
            response.sendRedirect("/login?redirectURL="+requestURI);
            return false;
        }

        return true;
    }

}

 

이렇게 간단하게 구현할 수 있다 

preHandle에서 컨트롤러에 들어가기 전에 Session을 꺼내보기 시작한다

만일 Session이 비어있다면 아직 로그인이 되지 않은 상황임으로 redirect를 진행한다 

 

참고
Filter를 살펴보면 어디서 많이 본듯한 것 같다 
맞다! 스프링 Security가 이 필터로 구성되어 있다

 

 

 

 

인터셉터의 등록

    public class WebConfig implements WebMvcConfigure{
    @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");
    }

 

 

인터셉터는 Filter와는 다르게 Override를 제공한다 

registry에서 인터셉터를 등록을 하고 (addInterceptor),

우선순위 설정 (order)과

검증 url 설정(addPaterrns("/**") ,

그리고 excludePathPattern을 통해 인터셉터에서 제외할 URL을 구성하면 된다

 

 

'🌿 스프링 > 스프링 MVC 2편' 카테고리의 다른 글

API 예외처리  (0) 2026.02.15
서블릿 예외 처리와 오류 페이지  (0) 2026.02.15
로그인 처리- 쿠키,세션  (0) 2026.02.14
Validation  (0) 2026.02.14
메시지 , 국제화 기능  (0) 2026.02.14