본문 바로가기

JSP 웹 프로그래밍/수업내용

[JSP 웹 프로그래밍] 필터(filter)

1. 필터의 개요

필터(filter)

클라이언트와 서버 사이에서 requestresponse 객체를 먼저 받아 사전/사후 작업 등 공통적으로 필요한 부분을 처리하는

클라이언트의 요청이 웹 서버의 서블릿, JSP, HTML 페이지 같은 정적 리소스에 도달하기 전과, 반대로 정적 리소스에서 클라이언트로 응답하기 전에 필요한 전처리를 가능하게

필터는 HTTP 요청과 응답을 변경할 수 있는 코드로 재사용 가능

클라이언트와 정적 리소스 사이에 여러 개의 필터로 이루어진 필터 체인을 제공하기도

 

2. Filter 인터페이스의 구현 클래스

Filter 인터페이스

필터 기능을 구현하는 데 핵심적인 역할을

클라이언트와 서버의 리소스 사이에 위치한 필터의 기능을 제공하기 위해 자바 클래스로 구현해야

 

 

 

init() 메소드

JSP 컨테이너가 필터를 초기화할 때 호출되는 메소드

init( ) 메소드는 JSP 컨테이너 내에서 초기화 작업을 수행할 필터 인스턴스를 생성한 후 한 번만 호출

init( ) 메소드는 JSP 컨테이너에 의해 호출되어 필터의 서비스가 시작되고 있음을 나타냄

 

doFilter() 메소드

JSP 컨테이너가 필터를 리소스에 적용할 때마다 호출되는 메소드

init( ) 메소드 후에 호출되며, 필터가 어떤 기능을 수행할 필요가 있을 때마다 호출

번째 매개변수 ServletRequest 객체는 체인을 따라 전달하는 요청이고,

번째 매개변수 ServletResponse 객체는 체인을 따라 전달할 응답

번째 매개변수 FilterChain 객체는 체인에서 다음 필터를 호출하는 데 사용  만약 호출 필터가 체인의 마지막 필터이면 체인의 끝에서 리소스를 호출

 

destroy() 메소드

필터 인스턴스를 종료하기 전에 호출하는 메소드

JSP 컨테이너가 필터 인스턴스를 삭제하기 전에 청소 작업을 수행하는 데 사용되며, 이는 필터로 열린 리소스를 모두 닫을 수 있는 방법

destroy( ) 메소드는 필터의 수명 동안 한 번만 호출

 

 


3. web.xml 파일의 필터 구성

web.xml 파일에 필터를 설정

필터를 사용하려면 어떤 필터가 어떤 리소스에 대해 적용되는지 JSP 컨테이너에 알려주어야

<filter><filter-mapping> 요소를 사용

web.xml 파일에 여러 개의 필터가 설정되어 있으면 선언된 순서대로 실행

 


<filter> 요소

<filter> 요소는 웹 애플리케이션에서 자바 필터와 매개변수를 설정하는 데 사용


<init-param> 요소

설정된 매개변수와 값을 자바 또는 JSP 코드에서 접근

위의 예에서 <init-param> 요소에 설정된 매개변수와 값을 자바 클래스에서 접근하려면 다음과 같이 작성

 

 


<filter-mapping> 요소

특정 리소스에 대해 어떤 필터를 사용할지 설정하는 데 사용

 

예제

더보기

web.xml

 <!-- filter 인터페이스의 구현 클래스 -->
<filter>
    <filter-name>Filter01</filter-name>
    <filter-class>filter.AuthenFilter</filter-class>
 </filter>
 <!-- Filter01 로 연결된 필터를 사용할 요청 URL -->
 <filter-mapping>
    <filter-name>Filter01</filter-name>
    <url-pattern>/ch12/filter01_process.jsp</url-pattern>
 </filter-mapping>
 <filter>
    <filter-name>Filter02</filter-name>
    <filter-class>filter.initParamFilter</filter-class>
    <!-- param1=admin&param2=java -->
    <!-- 매개변수 = 매개변수값 ,
    InitParamFilter 클래스의 init메소드로 던져짐
    param1=admin&param2=java-->
    <init-param>
        <param-name>param1</param-name>
        <param-value>admin</param-value>
    </init-param>
    <init-param>
        <param-name>param2</param-name>
        <param-value>java</param-value>
    </init-param>
 </filter>
 <filter-mapping>
    <filter-name>Filter02</filter-name>
    <url-pattern>/ch12/filter02_process.jsp</url-pattern>
 </filter-mapping>

 

AuthenFilter.java

package filter;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

//Filter 인터페이스를 구현한 구현 클래스
public class AuthenFilter  implements Filter{

	//필터 시작. 초기화
	@Override
	public void init(FilterConfig arg0) throws ServletException{
		System.out.println("Filter01 초기화 완료...");
	}
	
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		request.setCharacterEncoding("UTF-8");
		System.out.println("filter01 수행");
		
		//request{name='개동이'}
		// 도는 request{namne=}
		//폼페이지에서 전송된 파라미터를 전달받음
		String name = request.getParameter("name"); //개똥이 or ""
		
		//응답 메시지를 담아서 서버에서 클라이언트로 전달해줌 (response 객체활용)
		if(name == null || name.equals("") ) {
			//문자 인코딩 
			response.setCharacterEncoding("UTF-8");
			//컨텐츠 유형
			response.setContentType("text/html;charset=utf-8");
			//메시지
			PrintWriter writer = response.getWriter();
			String message ="입력된 name값은 null입니다.";
			writer.println(message);
			return;
		}
		
		//필터가 여러개가 있을 때 request, response객체를 전달해주 
		chain.doFilter(request, response);
		
		
	}
	
	//필터 종료 하기 전에 호출 
	@Override
	public void destroy() {
		System.out.println("Filter01 해제..");
	}

}

 

initParamFilter.java

package filter;

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;

public class initParamFilter implements Filter {
	//프로퍼티
   private FilterConfig filterConfig = null;
   
   
   @Override
   public void init(FilterConfig filterConfig) throws ServletException {
      System.out.println("Filter02 초기화..");
      this.filterConfig = filterConfig; 
   }
   
   /*
	   요청URI : filter02_process.jsp
	   요청파라미터 : {id=admin,passwd=java}
	   요청방식 : post
    */
   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
         throws IOException, ServletException {
      System.out.println("filter02 수행..");
      
      String id = request.getParameter("id");
      String passwd = request.getParameter("passwd");
      
      System.out.println("id : " + id + ", passwd : " + passwd);

   }
   
   @Override 
   public void destroy() {
      System.out.println("Filter02 해제..");
   }

}

 

filter01.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>filter</title>
</head>
<body>
	<!-- 폼페이지 
	 요청URI : /ch12/filter01_process.jsp
 	 요청파라미터 : {name=개똥이}
   	 요청방식 : post
	-->
	<form action="/ch12/filter01_process.jsp" method="post">
		<p>이름 : <input type="text" name="name" placeholder="이름을 입력하세요"/>
		<p><input type="submit" value="전송"/></p>
	</form>

</body>
</html>

 

filter01_process.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
		<!-- 폼페이지 
	 요청URI : /ch12/filter01_process.jsp
 	 요청파라미터 : {name=개똥이}
   	 요청방식 : post
	-->
	<%
	 request.setCharacterEncoding("UTF-8");
	String name = request.getParameter("name");
		
	%>	
	
	<p>입력된 name 값 :<%=name%><p>
</body>
</html>

 

filter02.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Filter</title>
</head>
<body>
	<!-- 폼페이지 
	 요청URI : /ch12/filter02_process.jsp
 	 요청파라미터 : {id=admin, passwd=java}
   	 요청방식 : post
	-->
	<form action="/ch12/filter02_process.jsp" method="post">

		<p>아이디 : <input type="text" name="id" placeholder="아이디" required/></p>
		<p>비밀번호 : <input type="text" name="passwd" placeholder="비밀번호" required/></p>
		<p><input type="submit" value="전송"/></p>
	</form>

</body>
</html>

filter02_process.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
	
	<%
		request.setCharacterEncoding("UTF-8");
		/*
		   요청URI : filter02_process.jsp
		   요청파라미터 : {id=admin,passwd=java}
		   요청방식 : post
	 	*/
		String id= request.getParameter("id");  //admin
		String passwd = request.getParameter("passwd");	//java
	%>
	
	<p>입력된 id값 : <%=id %></p>
	<p>입력된 pw값 : <%=passwd%></p>

</body>
</html>

 

LogFileFilter.java

package filter;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;

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 LogFileFilter implements Filter {
	
	//파일로 만들어야 하므로 파일객체를 전역변수 형태로 선언
	PrintWriter writer;
	
	//초기화
   /*
	  <init-param>
	     <param-name>filename</param-name>
	     <param-value>c:\\logs\\webmarket.log</param-value>
	  </init-param>
	      알기쉽게 설명 : ?filename=c:\\logs\\webmarket.log
    */
	
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		String filename = 
				filterConfig.getInitParameter("filename"); //c:\\logs\\webmarket.log
		
		//로그를 파일로 저장하기 위해 초기화 작업 수행
		//filename => c:\\logs\\webmarket.log
//     		 String filename = "c:\\logs\\webmarket.log";
		try {
			//FileWriter(String fileName, boolean true/false)
		         //1) true : 기존 내용에 새로운 내용이 추가(append)
		         //2) false : 기존 내용을 지우고 덮어쓰기(overwrite)
			
	         //PrintWriter(출력대상, boolean true/false)
		         //1) true : Auto flush -> writer.flush()를 생략함
		         //2) false : Auto flush 안함
			this.writer = new PrintWriter(new FileWriter(filename,true),true);
			
			//monitor.log파일이 없으면 자동생성
			//이렇게 하겠다 라고 설계
			File file = new File(filename);
			if(!file.exists()) { // 설계상의 파일이 실제로는 없으면..
				//설계대로 파일을 생성 
				file.createNewFile();
				writer.println(file.getAbsolutePath() + "파일이 생성 되었습니다.");
				
			}else {// monitor.log 파일이 있다면..
				System.out.println(file.getAbsolutePath() + "파일이 생성되어 있습니다.");
			}
		} catch (IOException e) {
			throw new ServletException("로그 파일을 열 수 없습니다");
		}
		
	}
	
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		writer.println("접속한 클라이언트 IP : " + request.getRemoteAddr());
		//시스템 현재시간(시작시간)
		long start = System.currentTimeMillis();
		writer.println("접근 가능한 경로 : " + getURLPath(request));
		writer.println("요청 처리 시작 시각 : " + getCurrentTime());
		
		//필터가 연속적으로 있다면 다음 필터로 제어 및 요청 (request)/ 응답(reqponse) 정보를 넘겨줌 
		chain.doFilter(request, response);
		
		//시스쳄 현재 시간(종료시간)
		long end = System.currentTimeMillis();
		writer.println("요청 처리 종료 시각 : " + getCurrentTime());
		writer.println("요청 처리 소요시간 : " + (end - start) + "ms"); /// 1000분의 1초 
		writer.println("========================="); 
		
	}
	
	@Override
	public void destroy() {
		// 파일 객체를 닫아줌. 메모리에서 제거
		writer.close();
	}
	//접근한 URL 경로 리턴 메소드
   // http://localhost/ch11/readParameterNoErrorPage.jsp?name=개똥이
   private String getURLPath(ServletRequest request) {
      //HttpServletRequest 인터페이스 는 ServletRequest 인터페이스를 상속받음
      HttpServletRequest req;
      //currentPath : URL경로 => http://localhost/ch11/readParameterNoErrorPage.jsp
      String currentPath = "";
      //queryString : 요청파라미터 => name=개똥이
      String queryString = "";
      //instanceOf 연산자는 객체가 어떤 클래스인지, 어떤 클래스를 상속받았는지 확인하는 데 사용됨
      if(request instanceof HttpServletRequest) {
         //자식 = (cast)부모
         req = (HttpServletRequest)request;
         currentPath = req.getRequestURI();//http://localhost/ch11/readParameterNoErrorPage.jsp
         System.out.println("currentPath : " + currentPath);
         queryString = req.getQueryString();//name=개똥이         
         System.out.println("queryString : " + queryString);
         //삼항연산자
         queryString = queryString == null?"":"?"+queryString;
      }
      //http://localhost/ch11/readParameterNoErrorPage.jsp?name=개똥이
      return currentPath + queryString;
   }//end getURLPath()
   
   //현재 시간을 얻어오는 메소드
   private String getCurrentTime() {
      //2023/03/31 17:29:12
      DateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
      //캘린더 객체 생성(싱글톤 : 메모리에 1번 생성하고 전역변수처럼 사용)
      Calendar calendar = Calendar.getInstance();
      //톰켓서버에서 제공해주는 시스템 현재 시간을 구해서 캘린더 객체에 세팅
      calendar.setTimeInMillis(System.currentTimeMillis());
      //2023/03/31 17:29:12 이러한 포맷을 준수하면서 리턴
      return formatter.format(calendar.getTime());
   }


}

 

 

filter03.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Filter</title>
</head>
<body>
	<!-- 폼페이지 
	 요청URI : /ch12/filter03_process.jsp
 	 요청파라미터 : {id=admin, passwd=java}
   	 요청방식 : post
	-->
	<form action="/ch12/filter03_process.jsp" method="post">

		<p>아이디 : <input type="text" name="id" placeholder="아이디" required/></p>
		<p>비밀번호 : <input type="text" name="passwd" placeholder="비밀번호" required/></p>
		<p><input type="submit" value="전송"/></p>
	</form>

</body>
</html>

filter03_process.jsp

 

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
	
	<%
		request.setCharacterEncoding("UTF-8");
		/*
		   요청URI : filter03_process.jsp
		   요청파라미터 : {id=admin,passwd=java}
		   요청방식 : post
	 	*/
		String id= request.getParameter("id");  //admin
		String passwd = request.getParameter("passwd");	//java
	%>
	
	<p>입력된 id값 : <%=id %></p>
	<p>입력된 pw값 : <%=passwd%></p>

</body>
</html>

참고파일

Ch12 필터.pptx
2.05MB