티스토리 뷰

SPRING 공부/서블릿

서블릿 필터

CodingDreamTree 2022. 7. 10. 03:30

 

필터란 말그대로 지정한 URL 패턴에 대해 거름막 역할을 해주는  기능이다.

가장 중요한 것은 서블릿을 투과한 후 Filter를 거치고 그 이후에 스프링 영역(DispatcherServlet)에 접근하게 된다.

 

주요 사용하는 용도로는 인코딩, XSS, CORS 등에 관한 설정을 주로 한다.

 

이전 Spring에서는 web.xml에서 Java파일을 Filter를 추가하여 사용 할 수 있었는데,

SpringBoot에서는 Annotation을 사용하여 Filter를 추가 할 수있다.

 

 

먼저 사용할 CustomerFilter를 Servlet이 제공하는 Filter인터페이스를 구현하여 만든다.

이때, chain.doFilter(request,response);를 해주지 않으면 다음 필터를 넘어가지 않게 되니 주의해서 등록하자

 

@Component
@Slf4j
@RequiredArgsConstructor
public class CustomTestFilter implements Filter {

    private final ExampleLog exampleLog;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
      log.info("필터 init메서드 호출");

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        log.info("필터 doFilter메서드 호출");
        log.info("필터 doFilter메서드 내의 exampleLog Bean 메서드 호출 시작 =====");
        exampleLog.testLog();
        log.info("필터 doFilter메서드 내의 exampleLog Bean 메서드 호출 끝 =====");
        Enumeration<String> attributeNames = request.getAttributeNames();
        ServletInputStream inputStream = request.getInputStream();
        StringBuilder sb  = new StringBuilder();
        String line = "";
        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
        while((line = br.readLine()) !=null){
            if(line.indexOf(" ")>0){
                sb.append("\n");
            }
            sb.append(line);
        }
        Iterator<String> names = attributeNames.asIterator();
        while(names.hasNext()){
            String next = names.next();

            log.info("next param = {}",next);
        }
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {
        log.info("필터 detroy메서드 호출");
    }
}

각 메서드 소개

* Init() : 필터기능을 진행하기전 실행되는 메소드이다.

* doFilter() : request, response ,chain을 파라미터로 받아서 필터작용을 해야하는 기능이 구현되어야하는 메소드이다.

* destroy() : 필터 소멸후 실행되는 메소드이다.

 

 

1. 기존 Web.xml방법

<filter>
    <filter-name>CustomerFilter</filter-name>
    <filter-class>com.example.filterinterceptoraopdifference.filter</filter-class>
</filter>
  
<filter-mapping>
    <filter-name>CustomFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

   

2. WebMvcConfigurer 구현체에 Bean등록하는방법

  FilterRegistrationBean 객체를 생성해서 Filter를 집어 넣어준 후 Bean을 등록하는 방법이다.


@RequiredArgsConstructor
@Configuration
public class WebConfig implements WebMvcConfigurer {

    private final CustomTestFilter customFilter;
    private final CustomInterceptor customInterceptor;

    //필터를 Bean으로 등록해주기
    @Bean
    public FilterRegistrationBean customFilter(){
        FilterRegistrationBean<Filter>  filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter(customFilter);
        filterRegistrationBean.setOrder(1);
        filterRegistrationBean.addUrlPatterns("/*");
        return filterRegistrationBean;
    }

}

 

3. @WebFilter 어노테이션으로 등록하는 방법

1. 우선 Filter를 구현한 CustomFilter2에 WebFilter 어노테이션을 달아 주자.

2. 그 다음 SpringBootApplication 어노테이션이 있는 곳에 가서  @ServletComponentScan을 어노테이션을 달아

    Servlet, Filter , Listener에 대한 스캔이 가능하게 해준다.

   Enables scanning for Servlet components (filters, servlets, and listeners)

@Slf4j
@WebFilter(urlPatterns = "/*")
public class CustomFilter2 implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("CustomerFilter2 DoFilter");
        chain.doFilter(request, response);
    }
}

4.결과

필터 적용 후 요청을 하였을 때의 로그

이상으로 필터에 대해 알아 봤는데, 다음은 이와 비슷한 기능을 하는 인터셉터를 알아보기로 하자.

 

 

***** 추가로  Spring Bean을 호출할 수 없는지 확인해보기

먼저 간단한 로그를 출력할 클래스를 Bean으로 등록하기

@Slf4j
@Component
public class ExampleLog {
    public void testLog(){
        log.info("Spring Container내의 ExampleLog Bean의 Test Log 호출");
    }
}

 

Filter에서 의존성 주입 후 testLog 호출

 

@Component
@Slf4j
@RequiredArgsConstructor
public class CustomTestFilter implements Filter {

    private final ExampleLog exampleLog;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
      log.info("필터 init메서드 호출");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("필터 doFilter메서드 호출");
        log.info("필터 doFilter메서드 내의 exampleLog Bean 메서드 호출 시작 =====");
        exampleLog.testLog();
        log.info("필터 doFilter메서드 내의 exampleLog Bean 메서드 호출 끝 =====");
        Enumeration<String> attributeNames = request.getAttributeNames();
        ServletInputStream inputStream = request.getInputStream();
        StringBuilder sb  = new StringBuilder();
        String line = "";
        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
        while((line = br.readLine()) !=null){
            if(line.indexOf(" ")>0){
                sb.append("\n");
            }
            sb.append(line);
        }
        Iterator<String> names = attributeNames.asIterator();
        while(names.hasNext()){
            String next = names.next();

            log.info("next param = {}",next);
        }
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {
        log.info("필터 detroy메서드 호출");
    }
}

 

결과 로그가 아래 처럼 나오게 된다.

 

분명 Servlet Filter와 Spring Context는 분리되어있는걸로 알고 있었는데, 왜 Bean 주입이 가능한 걸까?

스프링 부트 이전에 스프링에서는 org.springframework.web.filter.DelegatingFilterProxy 클래스가 Proxy패턴으로

Bean 주입을 가능하게 해주었다.

 

이후 스프링 부트에서는 내장톰캣을 사용하고 기본적으로 GenericFilterBean 을 상속한 클래스를 생성 하게되면서

Servlet Filter와 Spring Bean을 연결하게 해주었다.

 

 

 

지식 출처 : 13. 스프링부트 MVC - Filter 설정 · linked2ev

                    DelegatingFilterProxy (tistory.com)

'SPRING 공부 > 서블릿' 카테고리의 다른 글

Spring Interceptor  (0) 2022.07.13
Spring Servlet의 원리  (0) 2022.01.19
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함