Chapter.13
필터와 랩터
필터
- 전체 웹 애플리케이션 기능을 확장. 예) 보안, 혹은 , 요청에 대한 로그
- 일반 자바 컴포넌트, 서블릿으로 요청 처리전 , 클라이언트에게 넘겨가기전 응답을 가로채어 처리 할 수 있다.
- Request 필터로 처리 할만것들
- 보안 관련 내용을 체크
- 요청 헤더와 바디 포맷팅을 수정
- 요청을 감시하거나 기록으로 남김
- Response 필터로 처리 할만것들
- 응답스트림을 압축
- 응답스트림에 내용을 추가하거나 수정함.
- 완전 다른 새로운 응답을 만듬.
- 필터 인터페이스는 Filter 하나 임.
- 모듈식으로 DD에서 설정
- Servlet와 비슷한 3 가지
- 컨테이너가 이들 API를 알고 있음.
- 컨테이너가 생명주기를 관리함.
- DD에 설정함.
- 필터는 누가 자신을 불렀는지 자기 다음에 누구인지 모름
- 필터의 생명주기
- 제일 먼저 init() : FilterConfig 객체를 저장하는 역할이 주
- doFiler() 처리할 것이 많음.
- 마지막으로 destroy() : 필터 삭제전에 할 작업
- 필터는 컨테이너에 의해서 stack 처럼 처리 된다.
- DD에서 필터 설정으로 할 수 3가지 내용
- 필터의 정의
- 필터링해야 할 리소스와 필터를 맵핑 할수 있음.
- 순서대로 필터가 호출될 수 있도록 정렬 할 수 있음.
DD에서 필터 설정
필터 정의
<filter>
<filter-name>BeerRequest</filter-name>
--------------------------------------
필수 - 필터 이름
<filter-class>com.example.web.BeerRequestFilter</filter-class>
-------------------------------------------------------------
필수 - 필터 클래스 이름(패키지명 포함)
<dispatcher>REQUEST | INCLUDE | FORWARD | ERROR </dispatcher>
-------------------------------------------------------------
2.4 부터 가능함. (0..4) 포함 가능함.
<init-param>
<param-name>LogFileName</param-name>
<param-value>UserLog.txt</param-value>
</init-param>
-------------
선택 - 여러개 존재해도 됨.
</filter>
URL 패턴과 필터 맵핑 선언하기
<filter-mapping>
<filter-name>BeerRequest</filter-name>
--------------------------------------
필수 - filter의 <filter-name>에 존재해야 함.
<url-pattern>*.do</url-pattern>
-------------------------------
필수 - <url-pattern> 혹은 <servlet-name> 중 하나는 존재해야 함.
</filter-mapping>
서블릿 이름에 필터 맵핑 선언하기
<filter-mapping>
<filter-name>BeerRequest</filter-name>
<servlet-name>AdviceServlet</servlet-name>
</filter-mapping>
|
중요 컨테이너가 필터 순서를 정하는 규칙 : 하나의 리소스에 대한 여러 개의 필터가 적용되는 경우
- URL 패턴으로 적용되는 필터가 제일 먼저 옴.DD에 정의된 순서대로 체인에 하나씩 들어간 다음 실행됨.
- URL 패턴이후에 <servlet-name>으로 정의된 필터를 찾아 정의된 순서대로 체인에 등록함.
버젼 2.4 부터 요청 디스패처로 들어오는 것도 필터에 적용할 수 있음.
forward, include , request , dispatch ,error
압축필터에 대한 의사 코드(응답필터)
class MyCommpressionFilter implement Filter{
init();
public void doFilter(request, response,chain){
// 요청에 대한 처리가 들어감.
chain.doFilter(request,response); //서블릿이 자기 한일을 함.
// 압축로직이 들어갈 자리
}
}
|
새로운 응답 객체를 만들어 하는 이유
- 클라이언트로 넘어가는 것을 제어 하기 위해서
- Wrapper 클래스를 사용하는 새로운 Response 객체를 생성한다.
Wrapper Basic
- 원본 request, response 객체를 내부에 감싸고, 자신에게 들어오는 모든 메소드를 바로 이 객체로 위임하는 식으로 메소드를 구현함.
- 개발자의 역할은 랩퍼 클래스를 상속하고 필요한 메소드를 재정의 함.
- 대표적인 랩퍼 클래스들 : AWT의 Event Listener Adapter 클래스들
- 서블릿에서 제공하는 4개의 랩퍼 클래스
- ServletRequestWrapper
- HttpServletRequestWrapper
- ServletResponseWraper
- HttpServletResponseWraper
실제 압축 필터 코드
압축 필터 코드 예제)
... 생략 패키지 구문 및 import 구문
public classs CompressionFilter implements Filter{
private ServletContext ctx;
private FilterConfig cfg;
public void init(FilterConfig cfg) throws ServletException{
this.cfg = cfg;
ctx = cfg.getServletContext();
ctx.log(cfg.getFiltername() + “ initialized.”);
}
public void doFilter(ServletRequest req,ServletResponse resp,FilterChain fc) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
String valid_encodings = request.getHeader(“Accept-Encoding”);
if( valid_encodings.indexOf(“gzip”) > -1){
CompressionResponseWrapper wrappedResp =
new CompressionResponseWrapper(response);
-------------------------------------------
압축 랩퍼 클래스 생성
wrappedResp.setHeader(“Content-Encoding”,”gzip”);
-------------------------------------------------
응답 컨덴츠가 gzip으로 인코딩됨을 선언하는 부분
fc.doFilter(request,wrappedResp);
---------------------------------
체인에 있는 다음 컴포넌트를 호출합니다.
GZIPOutputStream gzos = wrappedResp.getGZIPOutputStream();
gzos.flush();
-------------
원본 스트림으로 모든 테이터를 전송합니다.
ctx.log(cfg.getFilterName() + “: finished the request.”);
}else{
ctx.log(cfg.getFilterName() + “: no encoding performed.”);
}
}
public void destroy(){
// 인스턴스 변수들을 null 처리 한다.
cfg = null; ctx = null;
}
}
|
압축이 HTTP를 만났을 때
- 브라우저가 보내는 헤더 중 하나인 “Accept-Endcoing:gzip”은 서버에게 이런 컨덴츠를 다룰 수 있다고 할려 주는 것입.
- 브라우저가 압축 데이터를 처리할 수 있으면 서버는 헤더에 “Content-Encoding:gzip”을 추가해서 컨덴츠가 압축되었음. 알려 주어야 한다.
- 브라우저를 위 정보를 확인 하고 화면을 출력하면 압축을 풀어야 함을 알게된다.