[서블릿] 서블릿 Filter API

hoonak·2023년 6월 23일
0

서블릿

목록 보기
15/16

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

클라이언트 -> 처리(필터1) -> 처리(필터2) -> 서블릿 -> 처리(필터2) -> 처리(필터1) -> 클라이언트 A

즉 모든 서블릿에 공통으로 처리하는 작업을 먼저 필터에서 처리해 주면 편리함.

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

  1. 요청 필터
    1) 사용자 인증 및 권한 검사.
    2) 요청 시 요청 관련 로그 작업.
    3) 인코딩 기능.

  2. 응답 필터
    1) 응답 결과에 대한 암호화 작업.
    2) 서비스 시간 측정.

  3. 필터 관련 API
    1) javax.servlet.Filter
    2) javax.servlet.FilterChain
    3) javax.servlet.FilterConfig

사용자 정의 Filter 만들기
사용자 정의 필터는 반드시 Filter 인터페이스를 구현해야 함. 그리고 init(), doFilter(), destory()의 추상 메서드를 구현해야 함. 사용자 정의 필터를 생성하면 필터를 각각의 요청에 맞게 적용하기 위해 필터 매핑을 해야 하는데, 필터를 매핑하는 방법은 두가지 임.
1. 애너테이션을 이용하는 방법.
2. web.xml에 설정하는 방법.

실제 서블릿에서 제공하는 필터 관련 API의 여러 가지 메서드들임.

- Filter 인터페이스에 선언된 메서드
1. destory() : 필터 소멸 시 컨테이너에 의해 호출되어 종료 작업을 수행함.
2. doFilter() : 요청/응답 시 컨테이너에 의해 호출되어 기능을 수행함.
3. init() : 필터 생성시 컨테이너에 의해 호출되어 초기화 작업을 수행함.

- FilterConfig의 메서드
1. getFilterName() : 필터 이름을 반환함.
2. getInitParameter(String name) : 매개변수 name에 대한 값을 반환함.
3. getServletContext() : 서블릿 컨텍스트 객체를 반환함.

사용자 정의 Filter 만들기

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

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

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

예 1) Filter를 이용한 한글 인코딩 실습

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

  • login.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</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

서블릿에서는 setCharacterEncoding() 메서드를 주석 처리하여 한글 처리를 하지 않도록 함.

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;

@WebServlet("/login")
public class LoginTest extends HttpServlet {
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//request.setCharacterEncoding("utf-8"); // post 방식으로 한글 전송 시 인코딩 작업을 생략함.
		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("</html></body>");
		
	}

}

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

이번에는 필터를 이용해 한글 인코딩 기능을 구현해 보겠음.
페키지를 선택하고 마우스 오른쪽 버튼을 클릭한 후 new > Filter를 선택함.


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

EncoderFilter.java(응답 필터 기능으로 작업 시간 구하기도 포함)
필터에서 doFilter() 메서드를 기준으로 위쪽에 위치한 코드는 요청 필터 기능을 수행하고 아래에 위치한 코드는 응답 필터 기능을 수행함.

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.HttpServletRequest;

@WebFilter("/*") // webFilter 애너테이션을 이용해 모든 요청이 필터를 거치게 함.
public class EncoderFilter implements Filter { // 사용자 정의 필터는 반드시 Filter 인터페이스를 구현해야 함.

	ServletContext context;
	
	public void init(FilterConfig fConfig) throws ServletException {
		System.out.println("utf-8 인코딩...........");
		context = fConfig.getServletContext();
	}
	
	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(); // 웹 브라우저에서 요청한 요청 URI를 가져옴.
		String realPath = request.getRealPath(pathinfo); // 요청 uri의 실제 경로를 가져옴.
		String mesg = "Context 정보 : " + context
					+ "\n URI 정보 : " + pathinfo
					+ "\n 물리적 경로 : " + realPath;
		System.out.println(mesg);
		chain.doFilter(request, response); // 다음 필터로 넘기는 작업을 수행함.		
	}
	
	public void destory() {
		System.out.println("destory 호출");
	}
}

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

  1. 필터를 거친 출력 결과

  1. 필터 호출 시 메시지 출력

응답 필터 사용

이번에는 응답에 대해 수행하는 응답 필터를 알아보겠음. 서블릿에서 요청과 응답에 대한 필터 기능은 동일한 필터가 수행함.

한 필터에서 요청과 응답 기능을 수행하는 방법을 이미지에 나타냈음. 필터에서 doFilter() 메서드를 기준으로 위쪽에 위치한 코드는 요청 필터 기능을 수행하고, 아래에 위치한 코드는 응답 필터 기능을 수행함.

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

응답 필터 기능을 이용해 로그인 요청 시 작업 수행 시간을 구해 보겠음.

  • EncoderFilter.java

chain.doFilter() 메서드 위아래애 요청 전과 후의 시각을 구하는 코드를 각각 추가함.

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.HttpServletRequest;

@WebFilter("/*") // webFilter 애너테이션을 이용해 모든 요청이 필터를 거치게 함.
public class EncoderFilter implements Filter { // 사용자 정의 필터는 반드시 Filter 인터페이스를 구현해야 함.

	ServletContext context;
	
	public void init(FilterConfig fConfig) throws ServletException {
		System.out.println("utf-8 인코딩...........");
		context = fConfig.getServletContext();
	}
	
	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(); // 웹 브라우저에서 요청한 요청 URI를 가져옴.
		String realPath = request.getRealPath(pathinfo); // 요청 uri의 실제 경로를 가져옴.
		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"); // 작업 요청 전과 후의 시각 차를 구해 작업 수행 시간을 구함.
	}
	
	public void destory() {
		System.out.println("destory 호출");
	}
}

long begin = System.currentTimeMillis() 메서드는 chain.doFilter() 메서드 위쪽에 위치하므로 요청 시 시각을 구함. long end = System.currentTimeMillis() 메서드는 chain.doFilter() 메서드 아래에 위치하므로 응답 시 시각을 구함.

실행하면 다음과 같이 로그인 요청 작업에 걸린 시간을 콘솔로 출력함. 로컬 pc에서의 실습이므로 너무 빨라 0ms를 표시함.

이상으로 필터 기능에 대해 알아봤음. 서블릿이나 jsp에서 공통으로 처리해야 할 작업을 필터에 구현해 놓고 사용하면 편리하다는 것을 기억해둘 것.

profile
Hello World!

0개의 댓글