티스토리 뷰
CHAPTER12. 필터 : 로그 기록하기
1. 필터의 개요
필터는 클라이언트와 서버 사이에서 request와 response 객체를 먼저 받아 사천/사후 작업 등 공통적으로 필요한 부분을 처리하는 것을 말한다.
필터는 클라이언트의 요청이 웹 서버의 정적 리소스(서블릿,HTML 등) 에 도달하기 전과 반대로 정적 리소스에서 클라이언트로 응답하기 전에 필요한 전처리를 가능하게 한다.
* 필터의 구조
필터는 선택적으로 동작한다. 그렇기 때문에 필터가 있으면 동작하고 없으면 동작하지 않는다. 즉, 필수적으로 거쳐야하는 것은 아니라는 뜻이다.
- 필터의 기능
필터 | 기능 |
Request 필터 | 인증(사용자 인증) 요청 정보를 로그 파일(=명단)로 작성 암호화 인코딩 작업 (java구현) |
Response 필터 | 응답 결과 데이터 압축 ( urlencoding,decoding같은 절차) 응답 결과에 내용 추가/수정 총 서비스 시간 측적 |
2. Filter 인터페이스의 구현 클래스
Filter 인터페이스는 필터 기능을 구현하는데 핵심적인 역할을 한다.
클라이언트와 서버의 리소스 사이에 우ㅟ치한 필터의 기능을 제공하기 위해 자바 클래스로 구현해야한다.
import javax.servlet.Filter;
public class 클래스 이름 implements Filter
{
(생략)
}
*import하지 않으려면 implements Filter 앞에 패키지명을 붙여주면 된다.
javax.servlet.Filter와 같이 사용
- Filter 인터페이스 메소드의 종류
메소드 | 설명 |
init(..) | 필터 인스턴스의 초기화 메소드이다. |
doFilter(..) | 필터 기능을 작성하는 메소드이다. |
destroy(...) | 필터 인스턴스의 종료 전에 호출되는 메소드이다. |
이 모든 것은 오버라이딩하여 사용할 수 있다.
(인터페이스 클래스 메소드이기 때문에 오버라이딩하지 않으면 사용할 수 없음)
2.1 init() 메소드
init() 메소드는 JSP 컨테이너(=톰캣)가 필터를 초기화 할 떄 호출되는 메소드이다.
init() 메소드는 JSP 컨테이너 내에서 초기화 작업을 수행할 필터 인스턴스를 생성한 후 한번만 호출된다.
init() 메소드는 JSP 컨테이너에 의해 호출되어 필터의 서비스가 시작되고 있다는 것을 나타낸다.
(내 생각 : 초기설정같이 하기 전에 필요한것을 초기화하여 설정..?)
public void init(FilterConfig filterconfig) throws ServletException
FilterConfig는 데이터타입이고 filterconfig는 참조 변수이고 이 값을 매개변수로 가진다.
- FilterConfig 인터페이스 메소드의 종류 : web.xml에서 필터 정보를 추출할 수 있다.
메소드 | 반환 유형 | 설명 |
getFilterName() | String | web.xml 파일에 설정된 필터 이름을 반환한다. |
getInitParameter(String name) | String | web.xml 파일에 설정된 매개변수에 대한 매개변수 값을 반환한다. 초기화 매개변수가 존재하지 않으면 null을 반환한다. |
getInitParameterNames() | Enumeration<String> (bof eof 하나씩) |
web.xml 파일에 설정된 모든 매개변수 이름을 포함하는 Enumeration 객체 타입을 반환한다. 초기화 매개변수가 존재하지 않으면 비어 있는 Enumeration을 반환한다. |
getServletContext() | ServletContext | ServletContext 객체를 반환한다. |
2.2 doFilter() 메소드
JSP 컨테이너가 필터를 리소스에 적용할 때마다 호출되는 메소드이다.
doFilter()은 init() 메소드 후에 호출된다.
필터가 어떤 기능을 수행할 필요가 있을 때마다 호출된다.
public coid doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, servletException
첫번째 매개변수인 ServletRequest 객체는 체인을 따라 전달하는 요청이다.
두번째 매개변수인 ServletREsponse 객체는 체인을 따라 전달할 응답이다.
세번째 매개변수 FilterChain 객체는 체인에서 다음 필터를 호출하는데 사용한다.
만약, 호출 필터가 체인의 마지막 필터이면 체인의 끝에서 리소스를 호출한다.
필터는 연속된 체인을 따라 다음에 존재하는 필터로 이동해 연속적으로 수행한다.
이때는 수행해야 할 필터 객체는 doFilter() 메소드의 매개변수 FilterChain 객체로 전달된다.
FilterChain 객체는 동기화를 위해서도 존재하지만 필터의 수행 과정을 연속적으로 하는 방법으로도 사용된다.
- FilterChain 인터페이스 메소드의 종류
메소드 | 반환 유형 | 설명 |
doFilter(ServletRequest request, ServletResponse response) | void | 체인의 다음 필터 또는 리소스로 제어를 전달한다. |
* 필터는 한번만 수행하는 것이 아니라 요청을 받았을 때 수행되고 filterChain.doFilter()를 통해 다음 부분으로 넘겨주고 그 다음이 모두 수앻되면 다시 필터로 완전한 응답 객체와 함께 저어권이 넘어온다.
filterChain.doFilter() 메소드를 기준으로 전처리, 후처리 부분으로 나뉜다.
* filterChain.doFilter() 메소드를 사용하여 다음 단계를 수행한 후 결과를 다시 받는 것이다.
2.3 destroy() 메소드
필터 인스턴스를 종료하기 전에 호출하는 메소드이다.
JSP 컨테이너가 필터 인스턴스를 삭제하기 전에 청소 작업을 수행하는데 사용된다.
끝날때 한번만 실행할 수 있다.
public void destory()
3. web.xml 파일의 필터
필터를 사용하려면 어떤 필터가 어떤 리소스(=대상)에 대해 잘 적용되는지 JSP 컨테이너에 알려주어야한다.
위의 행위들이 작동하기 위해서는 web.xml 파일을 통해 이루어진다. 그렇기때문에 web.xml 파일에 필터를 설정해야한다.
filter는 걸러주는 행위(=무엇을) mapping은 어떤 리소스를 실행하면 filter가 실행되는지(=누가)를 말한다.
사용법
<filter>
<filter-name>...</filter-name>
<filter-class>...</filter-class>
[<init-param>
<param-name>...</param-name>
<param-value>...</param-value>
</init-param>]
</filter>
<filter-mapping>
<filter-name>...</filter-name>
<url-pattern>...</url-pattern>
</filter-mapping>
filter 안에 init-param은 변수와 변수 값을 지정해준다.
filter 안의 filter-name과 filter-mapping 안의 filter-name 은 이름이 일치해야한다.
filter은 걸러주는 것을 말하고 (무엇을 거를지) mapping의 pattern에 입력된 리소스를 실행하면 filter로 걸러준다.
- <filter>를 구성하는 하위 요소
요소 | 설명 |
<filter-name> | 필터 이름을 설정한다. |
<filter-class> | 자바 클래스 이름을 설정한다. |
<init-papram> | 매개변수와 값을 설정한다. |
- <filter-mapping>을 구성하는 하위 요소
요소 | 설명 |
<filter-name> | 필터 이름을 설정한다. |
<url-pattern> | URL 패턴을 설정한다. |
3.1 <filter> 요소
웹 애플리케이션에서 자바 필터와 매개변수를 설정하는데 사용한다.
<filter>
<filter-name>필터 이름
<filter-class>클래스 이름
[<init-param>
<param-name>매개변수 이름
<param-value>매개변수 값
</init-param>]
</filter>
<init-param> 요소의 param-name은 변수를 param-value는 변수의 값을 지정한다.
<init-param> 요소에 설정된 매개변수와 값을 자바 또는 JSP 코드에서 접근한다.
매개변수에 담아 JSP 호출하는 것 (중요!!!!)
String value=getServletConfig().getInitParameter("매개변수 이름");
3.2 <filter-mapping> 요소
특정 리소스에 대해 어떤 필터를 사용할지 설정하는데 사용한다.
<filter-mapping>
<filter-name>필터 이름</filter-name>
<url-pattern>요청 URL 패턴</url-pattern>
</filter-mapping>
<filter-mapping> 요소를 이용하여 모든 리소스에 대해 필터 MyFilter를 적용하는 예시이다.
모든 리소스에 필터를 적용하기 위해URL 패턴을 /* 로 설정했는데 /*는 모든 요청 URL 과 일치하는 경로로 매핑한다는 것을 의미한다.
* 요청 URL 패턴의 유형
<URL-pattern> 요소에 설정할 수 있는 요청 URL 패턴이다.
/로 시작하고 /*로 끝나는 url-pattern은 경로 매핑에 사용된다.
*로 시작하는 urll-pattern 은 확장자에 대한 매핑을 할 떄 사용된다.
나머지 다른 문자열은 정확한 매핑을 하는데 사용된다.
URL 패턴의 예
URL 패턴 | 설명 |
*.do | .do 로 끝나는 모든 URL과 일치하는 파일 확장 패턴 |
/WebMarket/* | /webmarket/으로 시작하는 모든 URL과 일치하는 경로 패턴 |
/MyFilter.jsp | /MyFilter.jsp 로만 일치하는 특정 패턴 |
/WebMarket/cart.jsp | /WebMarket/cart.jsp 로만 일치하는 특정 패턴 |
폼 페이지에서 전송된 요청 파라미터를 필터로 처리하기
예제 12-1
web.xml
<filter>
<filter-name>filter01</filter-name>
<filter-class>filter.authenfilter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter01</filter-name>
<url-pattern>/filter01_process.jsp</url-pattern>
</filter-mapping>
</web-app>
filter01.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form method="post" action="filter01_process.jsp">
<p> 이름 : <input type="text" name="name">
<input type="submit" value="전송">
</form>
</body>
</html>
filter01_process.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
String name = request.getParameter("name");
%>
<p> 입력된 결과값 : <%=name %>
</body>
</html>
필터 처리로 매개변수와 값을 전달받아 로그인 인증 처리하기
예제 12-2
web.xml
<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>1234</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>filter02</filter-name>
<url-pattern>/filter02_process.jsp</url-pattern>
</filter-mapping>
</web-app>
initparamfilter.java
package filter;
import java.io.*;
import javax.servlet.*;
public class initparamfilter implements Filter{
private FilterConfig filterConfig = null;
@Override
public void destroy() {
// TODO Auto-generated method stub
System.out.println("Filter 해제...");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
// TODO Auto-generated method stub
System.out.println("Filter02 수행...");
String id = request.getParameter("id");
String passwd = request.getParameter("passwd");
String param1 = filterConfig.getInitParameter("param1");
String param2 = filterConfig.getInitParameter("param2");
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="로그인 실패했습니다.";
}
writer.println(message);
filterChain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
System.out.println("Filter02 초기화...");
this.filterConfig = filterConfig;
}
}
filter02.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form method="post" action="filter02_process.jsp">
<p> 아이디 : <input type="text" name="id">
<p> 비밀번호 : <input type="text" name="passwd">
<p> <input type="submit" value="전송">
</form>
</body>
</html>
filter02_process.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
String id = request.getParameter("id");
String passwd = request.getParameter("passwd");
%>
<p> 입력된 id 값 : <%=id %>
<p> 입력된 pw 값 : <%=passwd %>
</body>
</html>
[예제 12-2]의 웹 페이지를 이용하여 필터로 로그 기록하기 중요!!!!!!!
예제 12-3
web.xml 추가
<filter>
<filter-name>filter02</filter-name>
<filter-class>filter.logfilefilter</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>1234</param-value>
</init-param>
<init-param>
<param-name>filename</param-name>
<param-value>c:\\log\\monitor.log</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>filter02</filter-name>
<url-pattern>/filter02_process.jsp</url-pattern>
</filter-mapping>
</web-app>
<param-name>filename</ param-name>
<param-value> c:\\log\\monitor.log</ param-value> 부분 코드로 인해 filename 변수의 값에 경로를 만들어주었다.
그리고 java코드의 코드와 만나 자동으로 파일이 생성된다.(이때 log이름의 폴더는 가지고 있어야 monitor.log의 파일이 생성된다.
logfilefilter.java
package filter;
import java.util.*;
import javax.servlet.*;
import java.io.*;
import java.text.*;
public class logfilefilter implements Filter {
PrintWriter writer;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
String filename = filterConfig.getInitParameter("filename");
if(filename==null) throw new ServletException("로그 파일의 이름을 찾을 수 없습니다.");
try {
writer=new PrintWriter(new FileWriter(filename, true),true);
} catch (IOException e) {
// TODO Auto-generated catch block
throw new ServletException("로그 파일을 열 수 없습니다.");
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterchain)
throws IOException, ServletException {
// TODO Auto-generated method stub
writer.printf("현재일시 : %s %n", getCurrentTime());
String clientaddr = request.getRemoteAddr();
writer.printf("클라이언트 주소 : %s %n", clientaddr);
filterchain.doFilter(request, response);
String contenttype = response.getContentType();
writer.printf("문서의 콘텐츠 유형 : %s %n", contenttype);
writer.println("----------------------------------");
}
@Override
public void destroy() {
// TODO Auto-generated method stub
writer.close();
}
private String getCurrentTime() {
DateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
return formatter.format(calendar.getTime());
}
}
public void init() 구문을 살펴보면 filename이라는 파라미터를 getInitParameter을 사용하여 web.xml에서 가져와 변수에 저장한다.
if문을 실행하여 filename의 값이 null일 경우 로그 파일의 이름을 찾을 수 없습니다.를 출력하고
아닐 경우 FileWriter이라는 파일을 생성하는 메서드를 실행한다. 이때 메서드의 파라미터를 filename , true를 가지는데 true가 되면 파일이 생성된다. 그리고 생성된 파일을 PrintWrtier의 파라미터로 가진다.
PrinterWrtier은 출력 객체를 생성한다.(적을 수 있다는 말)
다음 dofilter로 이동한다.
wirter은 출력객체를 생성한 후 담은 참조변수이다.
writer.printf는 출력을 하는데 이때 getCurrentTime() 메서드를 사용하여 현재 시간을 출력한다.
request.getRemoteAddr()을 변수에 담았는데
request에는 라파미터와 헤더정보를 담고 있기때문에 getRemoteAddr()메소드를 사용하여 누가 요청했는지 요청한 주소를 가져온다.
다음 filterChain.doFilter(request, response); 구문이 실행되면 지금까지의 값들을 가지고 다음 doFilter로 이동한다.
만약 doFilter가 하나일 경우 갔다가 없기 때문에 다시 돌아와 다음 destory()를 이어서 실행한다.
결과
실행하기 전의 log 폴더의 모습이다.
log 폴더 안의 파일은 존재하지 않는다.
실행 후
설정한 비밀번호를 입력하여 로그인을 하여 실행하였다.
실행 후 log 폴더를 살펴보면 monitor.log라는 파일이 생성된 것을 볼 수 있다.
monitor.log 파일 안의 내용을 보면 dofilter가 실행되어 작성되어진 시간과 주소 유형 등이 출력된 것을 볼 수 있다.
'코딩 > JSP' 카테고리의 다른 글
[쉽게 배우는 JSP 웹 프로그래밍 연습문제] 1장 (0) | 2023.12.17 |
---|---|
[10주 4일차] 웹쇼핑몰 : 로그 기록하기 (0) | 2023.12.14 |
[10주 3일차] 예외 처리 (0) | 2023.12.13 |
[10주 3일차] 시큐리티 (2) (0) | 2023.12.13 |
웹 쇼핑몰 : 예외 처리 페이지 만들기 (0) | 2023.12.13 |
- Total
- Today
- Yesterday