레이블이 filter인 게시물을 표시합니다. 모든 게시물 표시
레이블이 filter인 게시물을 표시합니다. 모든 게시물 표시

2013년 9월 10일 화요일

[Head First]Servlets & JSP 내용정리-13장

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) 포함 가능함.
  • REQUEST : 클라이언트의 요청 (기본값 : 항목이 없는 경우)
  • INCLUDE : include에 적용
  • FORWARD : 클라이언트의 요청을 다른 곳으로 넘길때(forward)
  • ERROR   : error 핸들러를 호출하였을 때
 <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>



중요 컨테이너가 필터 순서를 정하는 규칙 : 하나의 리소스에 대한 여러 개의 필터가 적용되는 경우
  1. URL 패턴으로 적용되는 필터가 제일 먼저 옴.DD에 정의된 순서대로 체인에 하나씩 들어간 다음 실행됨.
  2. 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”을 추가해서 컨덴츠가 압축되었음. 알려 주어야 한다.
  • 브라우저를 위 정보를 확인 하고 화면을 출력하면 압축을 풀어야 함을 알게된다.