웹 개발 기초/자바 웹을 다루는 기술

Filter API

sungw00 2023. 2. 22. 21:45
728x90

필터

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

 

필터 기능 수행 과정

 

필터를 사용하는 이유

request에 한글 인코딩을 설정하는 작업처럼 웹 페이지에서 입력한 한글을 서블릿에 전달하려면 setCharacterEncoding() 메서드를 이용해 한글 인코딩 설정을 서블릿마다 상단에 추가해야 했다. 하지만 서블릿에서 공통으로 처리하는 작업을 먼저 필터에서 처리해주면 편하게 작업이 가능하다.

 

필터의 종류

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

  • 요청 필터
    • 사용자 인증 및 권한 검사
    • 요청 시 요청 관련 로그 작업
    • 인코딩 기능
  • 응답 필터
    • 응답 결과에 대한 암호화 작업
    • 서비스 시간 측정
  • 필터 관련 API
    • javax.servlet.Filter
    • javax.servlet.FilterChain
    • javax.servlet.FilterConfig

 

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

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

FilterConfig의 메서드

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

사용자 정의 Filter 만들기

사용자 정의 필터는 반드시 Filter 인터페이스를 구현해야 하고, init( ), doFilter( ), destroy( )의 추상 메서드를 구현해야 함.

사용자 정의 필터를 생성하면 필터를 각각의 요청에 맞게 적용하기 위해 필터 매핑을 해야 하는데, 필터를 매핑하는 방법은 다음 두 가지이다.

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

주로 애너테이션을 이용하는 방법이 편리하여 많이 사용된다.

<!-- 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>
// LoginTest.java
package sec03.ex01;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class LoginTest
 */
@WebServlet("/login")
public class LoginTest extends HttpServlet {
	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		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>");
	}

}

 

인코딩 처리를 하지 않았을 때의 출력 결과

한글이 깨져서 표시됨

필터를 이용해 인코딩 기능을 구현하는 방법

1. 패키지 선택 후 New -> Filter 클릭

 

2. Class name을 작성한 후 Next 클릭

 

3. Filter mappings의 /EncoderFilter를 선택 후 Edit 클릭

 

4. URL pattern을 /*로 변경 후 OK 클릭

 

5. Filter mapping의 내용이 변경된 것을 확인한 후 Next 클릭

 

6. Finish를 클릭해서 필터 클래스가 생성된 것을 확인

 

7. EncoderFilter.java 클래스 파일 작성

// EncoderFilter.java
package sec03.ex01;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;

/**
 * Servlet Filter implementation class EncoderFilter
 */
@WebFilter("/*")
public class EncoderFilter extends HttpFilter implements Filter {
	ServletContext context;
	/**
	 * @see Filter#destroy()
	 */
	public void destroy() {
		System.out.println("destroy 호출");
	}

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

	/**
	 * @see Filter#init(FilterConfig)
	 */
	public void init(FilterConfig fConfig) throws ServletException {
		System.out.println("utf-8 인코딩................");
		context = fConfig.getServletContext();
	}

}

필터를 거친 출력 결과
필터가 호출될 때마다 메시지가 출력된다.


응답 필터 사용

서블릿에서 요청과 응답에 대한 필터 기능은 동일한 필터가 수행한다.

한 개의 필터에서 요청 필터와 응답 필터의 수행 방법

한 필터에서 요청과 응답 기능을 수행하는 방법은 필터에서 doFilter( ) 메서드를 기준으로 위쪽에 위치한 코드는 요청 필터 기능을 수행하고, 아래에 위치한 코드는 응답 필터 기능을 수행한다.

// EncoderFilter.java
package sec03.ex01;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;

/**
 * Servlet Filter implementation class EncoderFilter
 */
@WebFilter("/*")
public class EncoderFilter extends HttpFilter implements Filter {
	ServletContext context;
	/**
	 * @see Filter#destroy()
	 */
	public void destroy() {
		System.out.println("destroy 호출");
	}

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

	/**
	 * @see Filter#init(FilterConfig)
	 */
	public void init(FilterConfig fConfig) throws ServletException {
		System.out.println("utf-8 인코딩................");
		context = fConfig.getServletContext();
	}

}

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

실행하면 로그인 요청 작업에 걸린 시간을 콘솔로 표시한다. 로컬 PC에서의 실습이기때문에 너무 빨라 0ms를 표시한다.

 

이처럼 서블릿이나 JSP에서 공통으로 처리해야 할 작업을 필터에 구현해 놓고 사용하면 편리하게 사용할 수 있다.

728x90