JAVA/JSP

[JSP] 필터

아잠만_ 2024. 7. 15. 15:07

필터 (Filter)

  • 클라이언트와 서버 사이에서 request와 response 객체를 먼저 받아 사전/사후 작업 등 공통적으로 필요한 부분을 처리하는 것
  • 클라이언트의 요청이 웹 서버의 서블릿, JSP, HTML 페이지 같은 정적 리소스에 도달하기 전과, 반대로 정적 리소스에서 클라이언트로 응답하기 전에 필요한 전처리를 가능하게 함
  • 필터는 HTTP요청과 응답을 변경할 수 있는 코드로 재사용 가능
  • 클라이언트와 정적 리소스 사이에 여러 개의 필터로 이루어진 필터 체인을 제공하기도 함

web.xml

  • <filter>
    • <filter-name> 이름 설정
    • <filter-class> 자바 클래스 이름 설정
    • <init-param> 매개변수와 값을 설정
      • 자바에서 파라미터 값 가져올 때
      • this.filterConfig.getInitParameter("파라미터이름");
  • <filter-mapping>
    • <filer-name> 필터이름 설정
    • <url-pattern> URL 패턴을 설정
.
.

<!-- Filter 인터페이스의 구현 클래스 -->
      <filter>
      	<filter-name>Filter01</filter-name>
      	<filter-class>filter.AuthenFilter</filter-class>
      </filter>
      <filter-mapping>
      	<filter-name>Filter01</filter-name>
      	<url-pattern>/ch12/filter01_process.jsp</url-pattern>
      </filter-mapping>
.
.

AuthenFilter.java

  • 필터 인터페이스
    • init()
    • doFilter()
    • destory()
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 AuthenFilter implements Filter {
	
	// 필터 시작 초기화
	@Override
	public void init(FilterConfig filterConfig) 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, response 객체를 전달해줌
		chain.doFilter(request, response);
	}
	
	// 필터 종료하기 전에 호출
	@Override
	public void destroy() {
		System.out.println("Filter01 해제..");
	}

}

filter01.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
    -->
	<form action="/ch12/filter01_process.jsp">
		<p>이름 : <input type="text" name="name" placeholder="이름"></p>
		<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");
%>
<h3>입력된 name 값 : <%=name %></h3>
</body>
</html>

필터 처리로 매개변수와 값을 전달 - param

web.xml

	<filter>
      	<filter-name>Filter02</filter-name>
      	<filter-class>filter.InitParamFilter</filter-class>
      	<!-- 
      	매개변수=매개변수 값
      	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>

InitParamFilter.java

package filter;

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

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;
	}
	
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		request.setCharacterEncoding("UTF-8");
		System.out.println("Filter02 수행");
		
		String id = request.getParameter("id");
		String pw = request.getParameter("pw");
		System.out.println(id+" "+pw);
		
		String param1 = this.filterConfig.getInitParameter("param1");
		String param2 = this.filterConfig.getInitParameter("param2");
		
		String message = "";
		
		response.setCharacterEncoding("UTF-8");
		response.setContentType("text/html; charset=UTF-8");
		PrintWriter out = response.getWriter();
		if(id.equals(param1)&&pw.equals(param2)) {
			message = "로그인 성공!";
		} else {
			message = "로그인 실패!!!!";
		}
		out.println(message);
		// 연속적으로 필터가 있으면 다음 필터로 제어를 넘겨줌(request, response)
		chain.doFilter(request, response);
	}
	
	@Override
	public void destroy() {
		System.out.println("Filter02 해제..");
	}
}

filter02.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
    -->
	<form action="/ch12/filter02_process.jsp">
		<p>아이디 : <input type="text" name="id" placeholder="아이디"></p>
		<p>비밀번호 : <input type="password" name="pw" placeholder="비밀번호"></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>
	<!-- 폼페이지  -->
	<!-- 
   요청URI : /ch12/filter01_process.jsp
   요청파라미터 : {name=개똥이}
   요청방식 : post
    -->
<%
	request.setCharacterEncoding("UTF-8");
	String id = request.getParameter("id");
	String pw = request.getParameter("pw");
%>
<h3>입력된 id 값 : <%=id %></h3>
<h3>입력된 pw 값 : <%=pw %></h3>
</body>
</html>

필터로 로그 기록

web.xml

      <filter>
      	<filter-name>Filter03</filter-name>
      	<filter-class>filter.LogFileFilter</filter-class>
      	<!-- 
      	매개변수=매개변수 값
      	InitParamFilter 클래스의 init 메서드로 던져짐
      	param1=admin&param2=java -->
      	<init-param>
      		<param-name>filename</param-name>
      		<param-value>c:\\logs\\monitor.log</param-value>
      	</init-param>
      </filter>
      <filter-mapping>
      	<filter-name>Filter03</filter-name>
      	<url-pattern>/ch12/filter03_process.jsp</url-pattern>
      </filter-mapping>

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\\monitor.log</param-value>
   	</init-param>
   	알기쉽게 설명 : ?filename=c:\\logs\\monitor.log
	 */
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		String filename = 
		filterConfig.getInitParameter("filename");//c:\\logs\\monitor.log
		
		//로그를 파일로 저장하기 위해 초기화 작업 수행
		//filename => c:\\logs\\webmarket.log
//				String filename = "c:\\logs\\monitor.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("접근한 URL 경로 : " + getURLPath(request));
		writer.println("요청 처리 시작 시각 : " + getCurrentTime());//2024/07/15 17:23:27
		
		//필터가 연속적으로 있다면 다음 필터로 제어 및 요청(request)/응답(response) 정보를 넘겨줌
		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></title>
</head>
<body>
	<!-- 폼페이지  -->
	<!-- 
   요청URI : /ch12/filter01_process.jsp
   요청파라미터 : {name=개똥이}
   요청방식 : post
    -->
	<form action="/ch12/filter03_process.jsp">
		<p>아이디 : <input type="text" name="id" placeholder="아이디"></p>
		<p>비밀번호 : <input type="password" name="pw" placeholder="비밀번호"></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>
	<!-- 폼페이지  -->
	<!-- 
   요청URI : /ch12/filter01_process.jsp
   요청파라미터 : {name=개똥이}
   요청방식 : post
    -->
<%
	request.setCharacterEncoding("UTF-8");
	String id = request.getParameter("id");
	String pw = request.getParameter("pw");
%>
<h3>입력된 id 값 : <%=id %></h3>
<h3>입력된 pw 값 : <%=pw %></h3>
</body>
</html>