일요일, 12월 22
Shadow

#043 필터와 랩퍼

막강 필터

전체 웹 애플리케이션 기능을 확장해보자
다양한 유스케이스가 산재한 시스템에서 그 기능을 확장해야 하는 경우가 더러있죠

필터를 한번 써보는 건 어떨까?
필터는 그냥 자바 컴포넌트 입니다. 서블릿과 비슷하죠

필터로 처리하면 좋은것들
Request 필터 :
ㅇ 보안 관련 내용을 체크합니다.
ㅇ 요청헤더와 바디 포맷팅을 수정합니다.
ㅇ 요청을 감시하건 기록으로 남깁니다.

Response 필터 :
ㅇ 응답 스트림을 압축합니다.
ㅇ 응답 스트림에 내용을 추가하거나 수정합니다.
ㅇ 완전히 다른 새로운 응답을 만듭니다.

필터는 모듈식으로 DD에 설정합니다.
필터는 체인속으로 이것 다음에 저것을 실행하세요 같이 연결해서 사용할수 있습니다. 필터는 그 자체로 하나의 오나전한 컴포넌트 입니다.

DD 설정 1
DD를 사용해서 다음과 같이 컨테이너한테 지시 할수 있죠. 이 URL에 대한 요청이 들어오면 필터1, 필터7, 필터3을 차례대로 실해아고 마지막으로 요청한 서블릿을 실행하세요

DD 설정 2
DD 서정을 조금만 바꾸면, 순서를 바꾼다든지, 필요없는 필터를 제거한다든지 하는 적업을 쉽게 할수 있죠. 이 URL에 대한 요청이 들어오면 필터3, 필터 7을 실행하고 곧바로 요청한 서블릿을 실행하도록

필터가 서블릿하고 비슷한 3가지 이유
1. 컨테이너가 이들의 API를 알고 있습니다.
2. 컨테이너가 생명주기를 관리합니다.
3. DD에 설정합니다.

누가 요청을 날렸는지 기록하는 필터를 만들어 봅시다.
package com.example.web;
import ajva.io.*;
import javax.servlet.*;
impor javax.servlet.http.HttpServerlRequest;

public class BeerRequestFilter implements Filter{
private FilterConfig fc;

public void init(FilterConfig config) throws ServletException{
this.fc = config;
}

public void doFilter(ServletRequest req, Servletresponse resp, FilterChain chain) throws ServletException, IOException{
HttpServeltRequest httpReq=(HttpServletRequest) req;
String name = httpReq.getRemoteUser();
if(name != null){
fc.getServletContext().log(“User ” + name + ” is updating”);
}
chain.doFilter(req,resp);
}

public void destory(){
}
}

필터 선언 및 순서 정하기
필터 고나련 다음 3가지 내용을 DD에 설정할수 있습니다.
ㅇ 필터를 정의합니다.
ㅇ 필터링해야 할 리소스와 필터를 매핑할수 있습니다.
ㅇ 순서대로 필터가 호출될수 있도록 정렬할수 있습니다.

필터 정의하기
<filter)
<filter-name>BeerRequest</filter-name>
<filter-class>com.example.web.BeerRequestFilter</filter-class>
<init-param>
<param-name>LogFileName</param-name>
</param-value>UserLog.txt</param-value>
</init-param>
</filter>

URL패턴과 필터 매핑 선언하기
<filter-mapping>
<filter-name>BeerRequest</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>

서블릿 이름에 필터 매핑 선언하기
<filter-mapping>
<filter-name>BeerRequest</filter-name>
</servlet-name>AdviceServlet</servlet-name>
</filter-mapping>

Response 출력을 압축하는 응답 필터
응답필터 구조
레이첼의 압축 필터에 대한 의사코드
class MycompressiongFilter implements Filter {
init();
Public void doFilter(request, response, chain){
//요청을 나름대로 처리하는 곳입니다.
chain.doFilter(request.response);
// 압축로직이 들어갈 자리입니다.
}
destroy();
}

응답을 압축한다는 것이 단지 서블릿이 끝날때 까지 기다렷다가 서블릿 응답 출력을 압축하기만 하면 될까요? 이론상으로는 필터의 doFilter() 메소드로 넘어간 응답객체가 서블릿으로 넘거나는 것과 동일한 것이기에 필터가 응답 객체 출력에 저금할수 있다는 것은 사실입니다.
1. 필터가 서블릿으로 request, response를 넘겨줍니다. 그리고 압출한 날만 손꼽아 기다고 있스니다.
2-1. 서블릿은 자기가 할일을 한뒤 출력을 만들겠죠 하지만 자신이 만든 출력이 압축될 줄은 꿈에도 모를걸요.
2-2. 출력에 대한 제어는 이제 컨테이너로 넘어가고 그리고
2-3. 이제 클라이언트로 넘어가겠죠 ㅎ필터는 출력이 클라이언트로 넘어가기 전에 압축해야 되기 때문에 이제나 저제나 하며 기다리고만 있습니다.
3. chain.doFilter() 호출이 끝나고 난 다음 필터는 나름대로 출력을 붙잡아 이를 압축하려는 기대에 부풀어 있을겁니다. 하지만 너무 늦었답니다. 출력은 이미 클라이언트로 넘어가 버렸으니까요. 컨테이너가 필터를 위해서 따로 출력 버퍼를 만들지 않기 때문이죠. 개념적으로 아직 필터의 doFilter() 메소드가 스택 제일 위에 있지만서도, 필터가 출력에 어떤 제어를 가하기에는 너무 늦었지요.

랩퍼의 기초
랩퍼 클래스는 원본 requset 또는 response 객체 내부에 감싸고 자신에게 들어오는 모든 메소드를 바로 이 객체로 위임하는 식으로 메소드를 구현하기 때문이죠 개발자가 할일이라곤 랩퍼클래스를 상속해서 필요한 메소드만 재 정이하면 그걸로 끝이죠

자 이제 랩퍼클래스를 추가해보죠
class CompressionResponseWrapper extends HttpServletResponseWrapper{
//커스터마이징 할 메소드를 역에 재정의하세요
}
class MyCompressionFilter implements Filter{
public void init(FilterCOnfig cfg){}
public void doFilter(request, response, chain){
CompressionResponseWrapper wrappedResp = new CompressionResponseWrapper(response);
chain.doFilter(request, wrappedResp);
// 압축로직이 들어갈 자리입니다.}
public void destroy(){}
}
}

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.