[Servlet] 서블릿 필터
서블릿 필터
서블릿은 웹에서 실행되는 프로그램이기 때문에 네트워크 통신의 사이 사이에서 특별한 동작을 만들어 낼 수 있다.
예를 들면, 홈페이지에 접속하기 직전에 이벤트 창을 띄운다든지 아니면 데이터를 입력한 후 실제 저장하는 페이지로 넘어가지 전에 넘겨지는 데이터들에 대하여 한글 처리를 한다든지 등의 작업을 할 수 있다.
또한, 세션이 만들어지거나 삭제될 때 이것을 감지하는 작업도 할 수 있다.
이렇게 여러가지 동작에 있어서 사이 사이에 끼워져서 실행되는 서블릿의 클래스를 필터라 부르고 동작이 발생할 때 감지하는 것을 이벤트라 부른다.
1. 서블릿 필터
필터는 말 그대로 여과 기능을 수행한다. 웹 프로그램에서도 하나의 페이지에서 다른 페이지로 전달되는 데이터가 필터를 지나 가공되거나 걸러지게 된다.
일반적으로 웹 프로그램은 A->B라는 식으로 실행 흐름이 있다. 그러나 기존의 흐름에 C라는 작업을 끼워 넣을 수 있다면 도움이 될 것이다.
예를 들어 A에서 B로 넘겨지는 데이터에 인코딩을 한다든지 데이터에 세션을 확인해서 B 페이지를 보여 줄지 작업 등을 할 수 있다.
(1) 본문
필터는 데이터를 가로채서 처리를 한다고 생각하면 된다. 하나의 작업에서 다른 작업으로 넘어갈 때나 어떤 작업이 또 다른 작업으로 넘어갈 때 데이터를 가로채서 처리를 할 수 있다.
요청이나 세션에 담긴 데이터뿐 아니라 헤더에도 필터가 적용될 수 있다. 기존 작업이 일어나기 직전(전처리)이나 일어나 직후(후처리) 모두 필터가 적용되는 시점이다.
웹 관련 클래스가 모두 그러하듯이 필터 클래스의 메서드도 요청 객체와 응답 객체를 매개변수로 가진다.
여기에 추가적으로 FilterChain 객체를 매개 변수로 갖는데, 이유는 필터 기능 자체가 페이지의 분기점에 있기 때문이다.
따라서, FilterChain 객체는 필터 기능이 완료되고 다음 페이지로 연결하는 기능에 사용된다. 또한, 서블릿의 일반 클래스처럼 web.xml 파일에 등록해야 한다.
당연하겠지만, 일반 클래스가 아니므로 <servlet> 태그가 아니라, <filter> 태그를 사용한다.
필터 관련 클래스로 javax.servlet.Filter, javax.servlet.FilterConfig, javax.servlet.FilterChain 등이 있다.
(2) 필터가 웹 프로그램에서 사용되는 경우
- 전달받은 데이터를 인코딩하는 경우
- 세션 데이터를 인증하는 경우
- 이벤트나 공지 등 팝업을 추가 하는 경우
(3) 예제(전달받은 데이터를 인코딩하는 경우)
<filter> <!--<filter> 태그는 <servlet> 태그보다 앞에 놓여야 한다./ 필터를 지정하는 역할-->
<filter-name>My_Ft_01</filter-name> <!--getFilterName()-->
<filter-class>Round18_01_Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>My_Ft_01</filter-name>
<url-pattern>/Servlet_01</url-pattern> /Servlet_01 서블릿에 접근하기 전에 필터를 거는 것이다.
<!--<url-pattern>/*</url-pattern>--> URL 패턴에서 '/*' 와 같이 적으면 모든 페이지에 접근하기 전에 해당 필터 클래스가 실행된다.
</filter-mapping>
<servlet>
<servlet-name>My_01</servlet-name>
<servlet-class>Round18_01_Servlet</servlet-class>
</servlet>
2) 자바코드
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class Round18_01_Filter implements Filter {
// 필터는 Filter 인터페이스를 구현해야 한다.
public void init(FilterConfig fc) throws ServletException { } // 필터 초기화 작업
// init() 메서드의 매개변수는 FilterConfig 객체이다.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 1. request 파라미터를 이용하여 요청의 필터 작업 수행
// doFilter() 메서드를 사용하고, 매개 변수로는 반드시 ServletRequest, ServletResponse, FilterChain 세 가지를 사용한다.
HttpServletRequest h_request = (HttpServletRequest)request;
String method = h_request.getMethod();
if(method.equalsIgnoreCase("POST")) {
request.setCharacterEncoding("euc-kr");
}
chain.doFilter(request, response);
// 2. 체인의 다음 필터 처리
// 3. response를 이용하여 응답의 필터링 작업 수행
// 필터 메서드 내용부의 마지막 코드는 현재까지 작업한 내용을 적용하고 연결된 페이지로 이동하도록 만들어 준다. 이런 역할을 하는 메서드가 chain 객체의 doFilter()이다.
// 세번째 매개변수인 FilterChain 클래스의 객체인 chain을 이용해서 다른 필터나 서블릿과 연결하는 코드를 반드시 작성해야 한다.
}
public void destroy() {
// 4. 주로 필터가 사용한 자원을 반납
}
}
메서드 | 리턴 타입 | 설명 |
getFilterName() | String | 설정파일에서 <filter-name>에서 지정한 필터의 이름을 리턴한다. |
getInitParameter(String name) | String | 설정파일의 <init-param>에서 지정한 초기화 파라미터의 값을 읽어온 다. 존재하지 않을 경우 null을 리턴한다. |
getInitParameterNames() | Enumeration<String> | 초기화 파라미터의 이름 목록을 구한다. |
getServletContext() | ServletContext | 서블릿 컨텍스트 객체를 구한다. |
3. 요청 및 응답 래퍼 클래스
필터가 필터로서의 제기능을 하기 위해서는 클라이언트의 요청을 변경하고, 또한 클라이언트로 가는 응답을 변경할 수 있어야 할 것이다.
이러한 변경을 할 수 있도록 해주는 것이 바로 ServletRequestWrapper와 ServletResponseWrapper이다.
서블릿 요청/응답 래퍼 클래스를 이용함으로써 클라이언트의 요청 정보를 변경하여 최종 자원인 서블릿/JSP/HTML/기타 자원에 전달할 수 있고, 또한 최종 자원으로부터의 응답 결과를 변경하여 새로운 응답 정보를 클라이언트에 보낼 수 있게 된다.
서블릿 요청/응답 래퍼 클래스로서의 역할을 수행하기 위해서는 javax.servlet 패키지에 정의되어 있는 ServletRequestWrapper 클래스와 ServletResponseWrapper 클래스를 상속받으면 된다.
하지만, 대부분의 경우 HTTP 프로토콜에 대한 요청/응답을 필터링 하기 때문에 이 두 클래스를 상속받아 알맞게 구현한 HttpServletRequestWrapper 클래스와HttpServletResponseWrapper 클래스를 상속받는 경우가 대부분일 것이다.
HttpServletRequestWrapper 클래스와 HttpServletResponseWrapper 클래스는 모두 javax.servlet.http 패키지에 정의되어 있으며, 이 두 클래스는 각각 HttpServletRequest 인터페이스와 HttpServletResponse 인터페이스에 정의되어 있는 모든 메소드를 이미 구현해 놓고 있다. 필터를 통해서 변경하고 싶은 정보가 있을 경우 그 정보를 추출하는 메소드를 알맞게 오버라이딩하여 필터의 doFilter() 메소드에 넘겨주기만 하면 된다. 예를 들어, 클라이언트가 전송한 "company" 파리머터의 값을 무조건 "JavaCan.com"으로 변경하는 요청 래퍼 클래스는 다음과 같이 HttpServletRequestWrapper 클래스를 상속받은 후에 getParameter() 메소드를 알맞게 구현하면 된다.
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
// 요청 레퍼 클래스로 동작하기 위해 HttpServletRequestWrapper 클래스를 상속받는다.
public class NullParameterRequestWrapper extends HttpServletRequestWrapper {
private Map<String, String[]> parameterMap = null;
public NullParameterRequestWrapper(HttpServletRequest request) {
super(request);
// 생성자는 전달받은 request의 파라미터의 정보를 parameterMap에 저장한다.
parameterMap = new HashMap<String, String[]>(request.getParameterMap());
}
// checkNull() 메서드는 검사할 파라미터의 이름 목록을 인자로 전달받는다. 인자로 전달받은 각각의 이름을 검사해서 해당 이름의 파라미터가 존재하지 않으면
// 기본값으로 빈 문자열을 저장한다.
public void checkNull(String[] parameterNames) {
for (int i = 0; i < parameterNames.length; i++) {
if (!parameterMap.containsKey(parameterNames[i])) {
String[] values = new String[] { "" };
parameterMap.put(parameterNames[i], values);
}
}
}
@Override
public String getParameter(String name) {
String[] values = getParameterValues(name);
if (values != null && values.length > 0)
return values[0];
return null;
}
@Override
public Map<String, String[]> getParameterMap() {
return parameterMap;
// 파라미터와 관련된 메서드를 구현해서 parameterMap으로부터 파라미터값을 읽어오도록 한다.
}
@Override
public Enumeration<String> getParameterNames() {
return Collections.enumeration(parameterMap.keySet());
}
@Override
public String[] getParameterValues(String name) {
return (String[]) parameterMap.get(name);
}
}
출처: https://devbox.tistory.com/entry/Servlet-서블릿-필터와-이벤트-1?category=574550 [장인개발자를 꿈꾸는 :: 기록하는 공간]
'Java 관련 > JSP,Servlet' 카테고리의 다른 글
[Java] 서블릿(servlet)과 서블릿 컨테이너(servlet container) (0) | 2021.03.29 |
---|---|
[JSP] HTTP 헤더 (0) | 2020.06.10 |
[JSP] 커넥션 풀 (0) | 2020.06.10 |
[Servlet] 서블릿 이벤트 (0) | 2020.06.10 |
[Servlet] 서블릿 기초 (0) | 2020.06.10 |
[Servlet] 데이터 저장 영역 (0) | 2020.06.10 |
[Servlet] 초기화 파라미터 (0) | 2020.06.10 |
[Servlet] web.xml 주요 태그 (0) | 2020.06.10 |