반응형

 

필터

 

: 클라이언트와 서버 사이에서 request와 response 객체를 먼저 받아 공통적으로 필요한 부분을 처리하는 것

요청, 응답할 때 각각의 전처리 기능을 함

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

ex) 한글 처리 필터, 로그 처리 필터, 시큐리티 필터 등

 

필터 구조

 

 

 

  • 필터의 기능
필터 기능
Request 필터 인증(사용자 인증)
요청 정보를 로그 파일로 작성
암호화 인코딩 작업
Response 필터 응답 결과 데이터 압축
응답 결과에 내용 추가/수정
총 서비스 시간 측정

 

 

 

Filter 인터페이스

 

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

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

 

import javax.servlet.Filter;

public class 클래스 이름 implements Filter
{
	생략
}

 

 

 

  • Filter 인터페이스 메소드의 종류
메소드 설명
init(값) 필터 인스턴스의 초기화 메소드
doFilter(값) 필터 기능 작성 메소드
destroy() 필터 인스턴스의 종료 전에 호출되는 메소드

 

 

 

web.xml (하단에 추가)

  <!-- Filter 인터페이스의 구현 클래스(필터)를 클라이언트와 서버 사이에 장착해보자 -->
  <!-- filter의 filter-name과 filter-mapping의 filter-name이 같아야 함 -->
  <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>

 

 

AuthenFilter.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 AuthenFilter implements Filter{
	
	// 필터 시작. 초기화
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("Filter01 초기화 완료");
	}

	// 요청파라미터 : {name=개똥이}
	// 필터 기능(서비스 로직) 수행
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("filter01.jsp 수행..");
		// 요청URI : /ch12/filter01_process.jsp?name=개똥이
		String name = request.getParameter("name"); // 개똥이
		
		// 객체/숫자 비교 : ==
		// 문자열 비교 : equals
		if(name==null || name.equals("")) {
			// 응답 메시지를 담아서 서버(톰켓)에서 클라이언트(크롬)로 전달해줌(response객체 활용)
			response.setCharacterEncoding("UTF-8");
			response.setContentType("text/html;charset=UTF-8");
			PrintWriter writer = response.getWriter();
			String message = "입력된 name 값은 null입니다.";
			writer.print(message);
			//1. return있으면 : message가 화면에 뜨고
			//2. return없으면 : filter01_process.jsp를 찾게됨
			return;
		}
		
		// 필터가 여러개 있을 때 필터 간에 전달해줌
		chain.doFilter(request, response);
	}

	// 필터 종료 전 호출
	@Override
	public void destroy() {
		System.out.println("filter01해제..");
	}
}

 

결과 화면1 : 해당 jsp가 없어도 그렇게 보이게 해줌

 

결과 화면2 : 초기화 > 수행 > 해제 순으로 진행 / init > doFilter > destroy

 

 

  • 파라미터에 값 넣을 때

filter01_process.jsp

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

 

결과 화면3 : 파라미터에 값을 보냄

 

 

  • post로 값 보내기

AuthenFilter.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 AuthenFilter implements Filter{
	
	// 필터 시작. 초기화
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("Filter01 초기화 완료");
	}

	// 요청파라미터 : {name=개똥이}
	// 필터 기능(서비스 로직) 수행
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// 한글 깨짐으로 인해 추가해줘야함!!!
		request.setCharacterEncoding("UTF-8");
		
		System.out.println("filter01.jsp 수행..");
		// 요청URI : /ch12/filter01_process.jsp?name=개똥이
		String name = request.getParameter("name"); // 개똥이
		
		// 객체/숫자 비교 : ==
		// 문자열 비교 : equals
		if(name==null || name.equals("")) {
			// 응답 메시지를 담아서 서버(톰켓)에서 클라이언트(크롬)로 전달해줌(response객체 활용)
			response.setCharacterEncoding("UTF-8");
			response.setContentType("text/html;charset=UTF-8");
			PrintWriter writer = response.getWriter();
			String message = "입력된 name 값은 null입니다.";
			writer.print(message);
			//1. return있으면 : message가 화면에 뜨고
			//2. return없으면 : filter01_process.jsp를 찾게됨
			return;
		}
		
		// 필터가 여러개 있을 때 필터 간에 전달해줌
		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 : filter01_process.jsp
	요청파라미터 : {name=개똥이}
	요청방식 : post
	 -->
	 <form action="filter01_process.jsp" method="post">
	 	<p>이름 : <input type="text" name="name" ></p>
	 	<p><input type="submit" value="전송"></p>
	 </form>
</body>
</html>

 

결과 화면4-1

 

결과 화면4-2

 

 

 

  • id와 password 입력 받기

filter02.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
	<!-- 
	요청URI : filter02_process.jsp
	요청파라미터 : {id=admin, passwd=java}
	요청방식 : post
	 -->
	 <form action="filter02_process.jsp" method="post">
	 	<p>아이디 : <input type="text" name="id" required placeholder="아이디"></p>
	 	<p>비밀번호 : <input type="password" name="passwd" required 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 : filter02_process.jsp
	요청파라미터 : {id=admin, passwd=java}
	요청방식 : post
	 -->
    <%	// 스크립틀릿
    	request.setCharacterEncoding("UTF-8");
    	// 지역변수
    	String id = request.getParameter("id");
    	String passwd = request.getParameter("passwd");
    %>
   <p>입력된 id 값 : <%=id%></p>
   <p>입력된 passwd 값 : <%=passwd%></p>
</body>
</html>

 

결과 화면5-1

 

결과 화면5-2

 

 

 

  • 로그인으로 변형 (필터 사용)

web.xml (하단에 추가)

  <!-- URI가 요청되면 해당 필터 서블릿이 실행됨 -->
  <filter>
  	<filter-name>Filter02</filter-name>
  	<filter-class>filter.InitParamFilter</filter-class>
  	<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;
	
	// filterConfig{param1=admin,param2=java}
	@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"); // admin
		String passwd = request.getParameter("passwd"); // java
		// web.xml 필터 파라미터 값
		String param1 = this.filterConfig.getInitParameter("param1"); // admin
		String param2 = this.filterConfig.getInitParameter("param2"); // java
		
		String message = "";
		
		response.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter writer = response.getWriter();
		
		if(id.equals(param1) && passwd.equals(param2)) {
			message = "로그인 성공!";
		} else {
			message = "로그인 실패";
		}
		// message 값이 response객체에 들어감
		writer.println(message);
		
		chain.doFilter(request, response);
	}
	
	@Override
	public void destroy() {
		System.out.println("Filter02 해제..");
	}

}

 

결과 화면6-1

 

결과 화면 6-2

 

 

 

쇼핑몰 로그인 필터 기능 추가

 

 

미리 위의 경로에 파일을 만들어 놔야함!

 

 

 

web.xml (하단에 추가해야 함)

  <filter>
  	<filter-name>LogFileFilter</filter-name>
  	<filter-class>filter.LogFileFilter</filter-class>
  	<init-param>
  		<param-name>filename</param-name>
  		<param-value>c:\\logs\\webmarket.log</param-value>
  	</init-param>
  </filter>
  <filter-mapping>
  	<filter-name>LogFileFilter</filter-name>
  	<!--  http://localhost/의 모든 하위 폴더 및 모든 url요청 시 작동 -->
  	<url-pattern>/*</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;
	
	/*
	filterConfig{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 안함 -> writer.flush()를 사용해야함
			writer = new PrintWriter(new FileWriter(filename,true),true); // doFilter에서도 쓰기 위해 전역으로 사용함
			
			//webmarket.log 파일이 없으면 자동 생성
	        //이렇게 하겠다라고 설계
	        File file = new File(filename);
	        
	        if(!file.exists()) {//설계상의 파일이 실제 없으면..
	           //설계대로 파일을 생성
	           file.createNewFile();
	           
	           writer.println(file.getAbsolutePath() + " 파일이 생성되었습니다."); // 파일 생성했음을 로그에 추가한다는 뜻
	        }else {//있으면..
	           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());
		
		//필터가 연속적으로 있다면 다음 필터로 제어 및 요청(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());
	}
}

 

결과 화면7

 

 

반응형

'스프링' 카테고리의 다른 글

[스프링] 21장 세션  (1) 2024.04.18
[스프링] 20장 과제  (0) 2024.04.17
[스프링] 18장 쇼핑몰 시스템6  (1) 2024.04.16
[스프링] 17장 예외 처리  (0) 2024.04.16
[스프링] 16.5장 과제  (0) 2024.04.15