프로그래밍 언어/자바 웹

Filter API

· 코딩마이데이

필터란 브라우저에서 서블릿에 요청하거나 응답할 때 여러 요청이나 응답과 관련해 여러 가지 작업을 처리하는 기능입니다. 프로그래밍을 하다가 한글 인코딩처럼 각 서블릿에서 반복적으로 처리해야 하는 작업이 있을 수 있는데, 이런 경우 서블릿의 공통 작업을 미리 필터에서 처리하면 반복해서 작업할 필요가 없습니다.

필터 기능 수행 과정

 

필터는 용도에 따라 크게 요청 필터와 응답 필터로 나뉘며 다음과 같은 API가 있습니다.

 

요청 필터

  • 사용자 인증 및 권한 검사
  • 요청 시 요청 관련 로그 작업
  • 인코딩 기능

응답 필터

  • 응답 결과에 대한 암호화 작업
  • 서비스 시간 측정

필터 관련 API

  • javax.servlet.Filter
  • javax.servlet.FilterChain
  • javax.servlet.FilterConfig

Filter 인터페이스에 선언된 메서드

메서드 기능
destory() 필터 소멸 시 컨테이너에 의해 호출되어 종료 작업을 수행합니다.
doFilter() 요청/응답 시 컨테이너에 의해 호출되어 기능을 수행합니다.
init() 필터 생성 시 컨테이너에 의해 호출되어 초기화 작업을 수행합니다.

 

FilterConfig의 메서드

메서드 기능
getFilterName() 필터 이름을 반환합니다.
getInitParameter(String name) 매개변수 name에 대한 값을 반환합니다.
getServletContext() 서블릿 컨텍스트 객체를 반환합니다.

 

사용자 정의 Filter 만들기

사용자 정의 필터는 반드시 Filter 인터페이스를 구현해야 합니다. 그리고 init(), doFilter(), destory()의 추상 메서드를 구현해 주어야 합니다. 사용자 정의 필터를 생성하면 필터를 각각의 요청에 맞게 적용하기 위해 필터 매핑을 해야 하는데, 필터를 매핑하는 방법은 다음 두 가지입니다.

  • 애너테이션을 이용하는 방법
  • web.xml에 설정하는 방법

일반적으로 애너테이션을 이용하는 방법이 편리하므로 많이 사용합니다.

 

Filter를 이용한 한글 인코딩 실습

1. 다음과 같이 LoginTest, EncoderFilter 클레스 파일을 준비합니다.

실습 파일 위치

 

2. 로그인창에서 ID 대신 이름을 입력한 후 서블릿으로 전송하도록 login.html을 작성합니다.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인창</title>
</head>
<body>
  <form name="frmLogin"  method="post"  action="login"  encType="utf-8">
	  이름  :<input type="text" name="user_name"><br>
    비밀번호:<input type="password" name="user_pw"><br>
       <input type="submit" value="로그인">
       <input type="reset" value="다시입력">
  </form>
</body>
</html>

 

3. LoginTest 클레스를 다음과 같이 작성합니다. 서블릿에서는 getCharacterEncoding() 메서드를 주석 처리하여 한글 처리를 하지 않도록 합니다.

package sec03.ex01;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/login")
public class LoginTest extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		String user_name = request.getParameter("user_name");
		String user_pw = request.getParameter("user_pw");
		out.println("<html><body>");
		out.println("이름은 " + user_name + "<br>");
		out.println("비밀번호는 " + user_pw + "<br>");
		out.println("</body></html>");
	}
}

 

4. 다음은 인코딩 처리를 하지 않았을 때의 출력 결과입니다. 한글이 깨져서 표시되는 것을 볼 수 있습니다.

로그인 창에서 로그인

 

5. 이번에는 필터를 이용해 한글 인코딩 기능을 구현 보겠습니다. sec03.ex01 패키지를 선택하고 마우스 오른쪽 버튼을 클릭한 후 New > Filter를 선택합니다.

New > Filter 선택

 

4. Class name으로 EncoderFilter를 입력하고 Next를 클릭합니다.

클래스 이름으로 EncodeFilter 입력 후 Next 클릭

 

7. Filter mapping에서 /EncoderFilter를 선택한 후 Edit를 클릭합니다.

필터 메핑 이름 수정

 

8. 모든 요청에 대해 필터 기능을 수행하도록 Pattern /*로 수정합니다.

모든 요청에 대해 필터를 처리하도록 설정

 

9. URL Pattern에서 /*을 확인한 후 Next를 클릭합니다.

필터 매핑 이름 확인 후 Next 클릭

 

10. Finish를 클릭하여 필터 클래스가 생성된 것을 확인합니다.

Finish 클릭
@WebFilter 애니테이션으로 필터 생성 확인

 

11. 이제 다음과 같이 EncoderFilter 클래스를 작성합니다. 사용자 정의 필터 클래스는 반드시 Filter 인터페이스를 구현해야 합니다. 브라우저 요청 시 doFilter() 메서드의 매개변수로 request와 response가 전달되며, doFilter() 메서드는 FilterChain 타입인 chain을 세 번째 매개변수로 가집니다. 전달된 request를 이용해 한글 인코딩 작업을 합니다. chain.doFilter() 메서드를 기준으로 위쪽에 위차한 코드는 요청 필터 기능을 수행합니다.

package sec03.ex01;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;

import java.io.IOException;

@WebFilter("/*")
public class EncoderFilter implements Filter {
	ServletContext context;

	public void init(FilterConfig fConfig) throws ServletException {
		System.out.println("utf-8 인코딩............");
		context = fConfig.getServletContext();

	}

	/**
	 * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
	 */
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws ServletException, IOException {
		System.out.println("doFilter 호출");
		request.setCharacterEncoding("utf-8");
		String context = ((HttpServletRequest) request).getContextPath();
		String pathinfo = ((HttpServletRequest) request).getRequestURI();
		String mesg = " Context  정보:" + context + "\n URI 정보 : " + pathinfo;
		System.out.println(mesg);

	}

	/**
	 * 
	 * 
	 * /**
	 * 
	 * @see Filter#destroy()
	 */
	public void destroy() {
		System.out.println("destroy 호출");
	}

}

 

12. 톰캣을 재실행하고 로그인창에서 한글을 입력합니다. 이번에는 필터를 거쳐 한글이 제대로 출력되는 것을 확인할 수 있습니다. 요청 필터 기능을 수행할 때마다 doFilter()가 수행되므로 이클립스 콘솔에도 다음과 같은 메시지가 출력됩니다.

필터 호출 시 메시지 출력

 

 

응답 필터 사용

서블릿에서 요청과 응답에 대한 필터 기능은 동일한 필터가 수행합니다. 필터가 doFilter() 메서드를 기준으로 위쪽에 위치한 코드는 요청 필터 기능을 수행하고, 아래에 위치한 코드는 응답 필터 기능을 수행합니다.

 

응답 필터 기능으로 작업 시간 구하기

1. 앞 절의 EncoderFilter 클래스를 그대로 사용합니다. chain.doFilter() 메서드 위아래에 요청 전과 후의 시각을 구하는 코드를 각각 추가합니다.

package sec03.ex01;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;

import java.io.IOException;

@WebFilter("/*")
public class EncoderFilter implements Filter {
	ServletContext context;

	public void init(FilterConfig fConfig) throws ServletException {
		System.out.println("utf-8 인코딩............");
		context = fConfig.getServletContext();

	}

	/**
	 * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
	 */
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws ServletException, IOException {
		System.out.println("doFilter 호출");
		request.setCharacterEncoding("utf-8");
		String context = ((HttpServletRequest) request).getContextPath();
		String pathinfo = ((HttpServletRequest) request).getRequestURI();
		String mesg = " Context  정보:" + context + "\n URI 정보 : " + pathinfo;
		System.out.println(mesg);
		
		long begin = System.currentTimeMillis();
		chain.doFilter(request, response);
		
		long end = System.currentTimeMillis();
		System.out.println("작업 시간:" + (end - begin) + "ms");
	}

	/**
	 * 
	 * 
	 * /**
	 * 
	 * @see Filter#destroy()
	 */
	public void destroy() {
		System.out.println("destroy 호출");
	}

}

 

2. 실행하면 다음과 같이 로그인 요청 작업에 걸린 시간을 콘솔로 출력합니다.

응답 필터를 이용한 작업 수행 시간 출력 결과