Java 웹 프로그래밍에서 프로그램 흐름의 앞 혹은 뒤에 공통적인 처리를 할 수 있는 방법이 있는데, 필터, 인터셉터, AOP가 있다. 이 세가지 방법에 중에서도 스프링과 무관한 Filter에 대해 먼저 정리해보았다.

Filter

필터는 HTTP의 요청과 응답을 변경할 수 있는 재사용 가능한 클래스이다. 서블릿 2.3 규약에 새롭게 추가되었다. 필터는 객체의 형태로 존재해 클라이언트에서 오는 요청(request)와 최종 자원(JSP, 서블릿 등) 사이에 위치해 클라이언트의 요청 정보를 알맞게 변경할 수 있다. 또한, 필터는 최종 자원과 클라이언트로 가는 응답(response) 사이에 위치해 요청 결과를 알맞게 변경할 수 있다.

주요 응용

  • 응답 데이터 변환
  • 특정 아이피만 접근허용
  • 인코딩 변환 처리
  • xss방어

필터의 기본 구조

위 그림으로 보면 알 수 있듯이, 자원이 받게되는 요청 정보는 클라이언트와 자원 사이에 존재하는 필터에 의해 변경된 요청 정보가 되며, 또한 클라이언트가 보는 응답 정보는 필터가 변경한 응답 정보가 된다. 필터는 한 개 뿐 아니라, 여러개의 필터가 모여 하나의 체인(chain)을 형성할 수도 있다.
여러 개의 필터가 모여 하나의 체인을 형성할 때, 첫번째 필터가 변경하는 요청정보는 클라이언트의 요청 정보가 되지만, 체인의 두 번째 필터가 변경하는 요청 정보는 첫번째 필터를 통해 변경된 요청정보가 된다. 응답 정보의 경우 요청 정보와 비슷한 과정을 거치지만, 필터의 적용 순서과 요청 때와는 반대라는 것을 유념해두어야 한다. 필터는 정보 뿐 아니라 흐름도 변경할 수 있다. 즉, 필터는 클라이언트의 요청을 필터 체인의 다음 단계에 보내는 것이 아니라, 다른 자원의 결과를 클라이언트에 전송할 수 있다. 이런 기능은 사용자 인증이나 권한 검사 같은 기능 구현시 용이하게 사용할 수 있다.

필터 구현 관련 인터페이스 및 클래스

필터를 구현하는데 있어 핵심 역할을 하는 아래 세가지가 있다.

  • javax.servlet.Filter 인터페이스 : 클라이언트와 최종 자원 사이에 위치하는 필터를 나타내며, 개발자가 구현해야 하는 인터페이스
  • javax.servlet.ServletRequestWrapper 클래스 : 필터가 요청을 변경한 결과를 저장하는 래퍼 클래스
  • javax.servlet.ServletResponseWrapper 클래스 : 필터가 응답을 변경하기 위해 사용하는 래퍼 클래스

개발자는 이 세 타입을 이용해 필터를 구현하고, 요청과 응답 정보를 변경하는 기능을 구현 할 수 있다.

Filter 인터페이스

Servlet 패키지에서는 아래와 같이 인터페이스가 정의되어 있다.

package javax.servlet;
 
import java.io.IOException;
 
public interface Filter {
 
    public void init(FilterConfig filterConfig) throws ServletException;
    
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException; 
 
 
    public void destroy();
}

위 인터페이스를 알맞게 구현해주기 위해 아래 메소드를 오버라이딩 해주어야 한다.

  • public void init(FilterConfig filterConfig)
    • 필터를 초기화 할 때 호출된다.
  • ` public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)`
    • 필터 기능을 수행하는 메소드. 클라이언트의 요청이 있을때마다 실행되며, chain을 이용해 체인의 다음 필터로 처리를 전달 할 수 있다.
  • ` public void destroy()` :
    • 필터가 웹 컨테이너에서 삭제될 때 호출. 보통 초기화시 생성했던 자원을 소멸시킬 때 사용된다.

필터 구현 및 등록 예제

필터를 구현하는 방법은 간단하다. Filter인터페이스를 구현하여 필터 클래스를 만들고, web.xml설정파일에서 어떤 경로로 접근할 때 필터를 적용할 지 등록해주기만 하면 끝이다! 아래 예제는 요청시 requestURL을 찍어주는 예제이다.

소스 부분

package org.test.one;
 
import java.io.IOException;
 
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
 
public class TestFilter implements Filter {
 
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { // 모든 요청(Request)에 대해서 이 부분이 실행된다.
        HttpServletRequest request = (HttpServletRequest)req;
        
        System.out.println("RequestURL : "+request.getRequestURL());
        
        chain.doFilter(req, res); //다음 필터로 넘어간다.
    }
 
    @Override
    public void init(FilterConfig config) throws ServletException { // 초기화할 때 실행되는 부분
        String testParam = config.getInitParameter("testParam");
        
        System.out.println("testParam : "+testParam);
    }
    
 
    @Override
    public void destroy() {
        
    }
}

web.xml 부분

...
    <filter>
    <filter-name>TestFilter</filter-name>
    <filter-class>
        org.test.one.TestFilter
    </filter-class>
    <init-param>
        <param-name>testParam</param-name>
        <param-value>This is Test Parameter!!!</param-value>
    </init-param>
    </filter>
    <filter-mapping>
        <filter-name>TestFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

필터 설정하기 : web.xml 이용

필터를 설정하는 방법은 두가지가 있는데, 첫번째 방법은 web.xml파일에 관련 정보를 추가하는 방법이다.


....

    <filter>
        <filter-name>NullParameter</filter-name>
        <filter-class>filter.NullParameterFilter</filter-class>
        <init-param>
            <param-name>parameterNames</param-name>
            <param-value>id,name</param-value>
        </init-param>
    </filter>

	<filter-mapping>
		<filter-name>NullParameter</filter-name>
		<url-pattern>*.jsp</url-pattern>
		<dispatcher>INCLUDE</dispatcher>
	</filter-mapping>

	<filter>
		<filter-name>LoginCheck</filter-name>
		<filter-class>filter.LoginCheckFilter</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>LoginCheck</filter-name>
		<url-pattern>/board/*</url-pattern>
		<url-pattern>/board2/*</url-pattern>
		<servlet-name>testServlet</servlet-name>
	</filter-mapping>

</web-app>

여기서 주요 태그를 살펴보자.

  • <filter> : 필터를 등록한다. <filter-name>에는 필터의 이름을 지정하고, <filter-class>는 구현한 필터 클래스를 패키지명까지 포함하여 지정해준다. 웹 컨테이너는 서버를 띄울 때 web.xml 설정의 <filter>태그를 읽어 필터 객체를 생성하고 초기화한다.
  • <filter-mapping> : 등록한 필터의 동작 범위를 설정할 수 있다. <filter-name>은 앞서 등록한 필터명을 지정하고, <url-pattern>은 URL패턴을 입력한다. 서블릿 등록시의 규칙과 동일하다. url패턴 말고 서블릿을 기준으로도 등록할 수 있는데, <servlet-name> 태그를 사용하면 필터링할 서블릿을 지정할 수 있다.(서블릿 클래스명이 아닌 web.xml에서 등록한 명칭이라는 점을 유의하자!)
    • 이 태그에서는 여러개의 <url-pattern><servlet-name>을 등록할 수 있다.
  • <dispatcher>: 필터가 적용하는 시점을 지정할 수 있다.
    • REQUEST : 클라이언트의 요청일 경우(DEFAULT 값)
    • FORWARD : forward()를 통해 제어 흐름을 이동하는 경우
    • INCLUDE : include()를 통해 포함되는 경우
    • ERROR : 에러페이지에 적용

필터 설정하기 : @WebFilter 애노테이션을 이용

web.xml을 이용해 설정하는것 외에도, 자바파일에서 @WebFilter애노테이션을 사용해 필터를 설정할 수 있다. 애노테이션을 사용하는 방법은 아래와 같다.


@WebFilter(filterName = "xsltFilter", urlPatterns = {"/xml/*"})
public class XSLTFilter implements Filter {
	...필터 구현 내용
}

이 경우, /xml/*을 통해 요청을 들어올경우 위 필터를 적용하게 된다. @WebFilter애노테이션의 주요 속성은 아래와 같다.

  • urlPattrns : 필터를 적용할 URL 패턴 목록을 지정한다.
  • servletNames : 필터를 적용할 서블릿 이름 목록을 지정한다.
  • filterNames : 필터 이름을 지정한다.
  • initParams : 초기화 파라미터 목록을 지정한다.
  • dispatcherTypes필터를 적용할 범위를 지정한다.

필터의 실행 순서

web.xml을 통해 필터를 생성하였을 경우, 해당 파일에 작성된 순서대로 필터가 실행된다. 즉, <filter-mapping>이 정의된 순서를 기준으로 필터체인의 정렬 순서를 정의한다.

<filer-mapping>
    <filter-name>firstFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filer-mapping>
 
 
<filer-mapping>
    <filter-name>secondFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filer-mapping>
 
 
<filer-mapping>
    <filter-name>thirdFilter</filter-name>
    <url-pattern>/third</url-pattern>
</filer-mapping>

위와 같이 작성된 web.xml파일에서, /third/hi를 요청할 경우 firstFilter -> secondFilter -> thirdFilter 순으로 실행이 된다. 하지만 @WebFilter 어노테이션을 이용하였을 경우, 필터의 실행 순서를 지정하는 속성이 없기 때문에 마구잡이로 실행될 수 있다..


참고 자료 :

  1. 최범균의 JSP 2.3 웹 프로그래밍: 기초부터 중급까지 CHAPTER 19 : 필터
  2. 자바 Filter 사용 방법 및 예제
  3. [서블릿/JSP] 필터(Filter) 사용 방법 및 예제

oksusutea's blog

꾸준히 기록하려고 만든 블로그