Spring/스프링 기본

Filter vs HandlerInterceptor - 간단 logging 기능 구현

공대키메라 2022. 2. 28. 12:24

저번에 Filter 와 HandlerInterceptor의 차이점에 대해서 공부를 해보았다.

 

https://tech-monster.tistory.com/119

 

Filters vs HandlerInterceptors - 개념

오늘은 filter와 interceptor에 대해서 정리하려고 한다. 둘 다 기능은 비슷한데 어떤 차이가 있는지 잘 모르겠다! 그래서 이번 기회에 정리하려고 한다. 1. Filter J2EE의 표준 스펙 기능.(Springframework의

tech-monster.tistory.com

 

이번에는 이것들을 직접 구현해서 적용해볼 것이다. 

 

1. Filter 적용해보기

 

filter를 먼저 적용해보려고 한다. 

 

들어오는 모든 요청과 응답을 로그로 남겨볼 것이다. 

 

package구조는 간단하다. 나누지도 않음!

 

controller, LogFilter, WebConfig를 만들어서 작성하였다. 

 

LogFilter.java

package filterinterceptorstudy.demo;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.UUID;

@Slf4j
public class LogFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();

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

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

 

Filter의 doFilter를 override하면 불편한 점이 파라미터가 ServletRequest, ServletResponse로 들어온다는 점이다.

 

HttpServletRequest와 HttpServletResponse로 다운 캐스팅을 해줘야 사용하기가 편안하다. 

 

WebConfig.java

package filterinterceptorstudy.demo;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;

@Configuration
public class WebConfig  {

    @Bean
    public FilterRegistrationBean logFilter() {
        FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter(new LogFilter());
        filterRegistrationBean.setOrder(1);
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ERROR);
        return filterRegistrationBean;
    }

}

 

FilterRegistrationBean을 이용해서 Filter를 등록한다.

 

딱 보면 뭐... filter를 등록하고, 현재 등록중인 filter의 실행 순서, 적용될 url pattern, dispatcher 타입을 설정하는 것으로 

딱~ 읽어보면 어떤 기능인지 그냥 보인다. 보여...

 

 

Controller.java

package filterinterceptorstudy.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Controller {

    @GetMapping("/test-logFilter")
    public String testLogFilter(String test){
        return "ok!";
    }
}

 

이렇게 서버를 켜보고 한 번 실행을 해보려 한다. 과연... 

 

 

왜 두번이냐 할텐데 두번 실행했다.

 

이렇게 filter가 적용된 것을 확인할 수 있다. 

 

2. HandlerInterceptor 적용해보기


LogInterceptor.java

package filterinterceptorstudy.demo;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;

@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);

        log.info("REQUEST -  HandlerInterceptor  [{}][{}][{}][{}]", uuid, request.getDispatcherType(), requestURI, handler);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle [{}]", modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        String requestURI = request.getRequestURI();
        String logId = (String)request.getAttribute(LOG_ID);
        log.info("RESPONSE - HandlerInterceptor [{}][{}][{}]", logId, request.getDispatcherType(), requestURI);
        if (ex != null) {
            log.error("afterCompletion error!!", ex);
        }
    }

}

 

WebConfig.java 수정

 

package filterinterceptorstudy.demo;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;

@Configuration
public class WebConfig  implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogInterceptor())
            .order(1)
            .addPathPatterns("/**")
            .excludePathPatterns("/css/**", "*.ico", "/error", "/error-page/**");//오류 페이지 경로
    }

    @Bean
    public FilterRegistrationBean logFilter() {
        FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter(new LogFilter());
        filterRegistrationBean.setOrder(1);
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ERROR);
        return filterRegistrationBean;
    }

}

 

실행 결과

 

filter가 먼저 실행이 되고 Interceptor가 실행되는 것을 확인할 수 있다. 

 

이렇게 적용을 해봤는데... 정리해보니 크게 어려운건 없었다.