티스토리 뷰
필터란 말그대로 지정한 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을 연결하게 해주었다.
'SPRING 공부 > 서블릿' 카테고리의 다른 글
Spring Interceptor (0) | 2022.07.13 |
---|---|
Spring Servlet의 원리 (0) | 2022.01.19 |