Java/Servlet & JSP

필터 - RESPONSE

체리필터 2009. 4. 28. 14:34
728x90
반응형
필터를 통해 서블릿이 실행되기 전에 특정 액션을 하게 만들 수 있다고 했다.
그런데 서블릿이 실행되고 나서 특정 액션을 하게 만들려면 어떻게 해야 할까?
간단하게 생각해 보면 필터의 doFilter()메소드 안에 있는 chain.doFilter(request, response) 를 마치고 나서 작업하면 될 것 같다.
하지만, 서블릿에 넘겨주는 response 객체를 서블릿이 사용하게 되면, 필터를 거치지 않고 바로 클라이언트로 response 하게 된다.
따라서 doFilter를 통해 response를 넘길 때 새로운 응답 객체(HttpServletResponse를 구현한 객체)를 만들어 넘기는 방법을 써야 한다.

하지만, HttpServletResponse는 간단한 클래스가 아니므로, 썬에서 구현해 둔 다음 4가지를 이용하면 된다.

ServletRequestWrapper
HttpServletRequestWrapper
ServletResponseWrapper
HttpServletResponseWrapper

위 4가지 클래스를 상속한 후 필요한 메소드만 재정의 해서 사용하면 된다.

response를 할 때 내용을 압축해서 보내주는 예제를 통해서 Response Filter를 어떻게 사용하는지 확인해 볼 수 있다.

package com.example.web;

import java.io.IOException;
import java.util.zip.GZIPOutputStream;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CompressionFilter implements Filter {
    private ServletContext ctx;
    private FilterConfig cfg;
   
    @Override
    public void init(FilterConfig cfg) throws ServletException {
        // TODO Auto-generated method stub
        this.cfg = cfg;
        ctx = cfg.getServletContext();
        ctx.log(cfg.getFilterName() + " initialized.");
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
            FilterChain fc) throws IOException, ServletException {
        // TODO Auto-generated method stub
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
       
        String valid_encodings = request.getHeader("Accept-Encoding");
        if(valid_encodings.indexOf("gzip") > -1) {
            CompressionResponseWrapper wrappedResp
                        = new CompressionResponseWrapper(response);
            wrappedResp.setHeader("Content-Encoding", "gzip");
            ctx.log("before chain...");
            fc.doFilter(request, wrappedResp);
           
            GZIPOutputStream gzos = wrappedResp.getGZIPOutputStream();
            gzos.finish();
           
            ctx.log(cfg.getFilterName() + ": finished the request.");
        } else {
            ctx.log(cfg.getFilterName() + ": no encoding performed.");
        }
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        cfg = null;
        ctx = null;
    }
}


package com.example.web;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.zip.GZIPOutputStream;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class CompressionResponseWrapper extends HttpServletResponseWrapper {
    private GZIPServletOutputStream servletGzipOS = null;
    private PrintWriter pw = null;

    public CompressionResponseWrapper(HttpServletResponse response) {
        super(response);
    }
   
    public void setContentLength(int len) {}
   
    public GZIPOutputStream getGZIPOutputStream() {
        return this.servletGzipOS.internalGzipOS;
    }
   
    private Object streamUsed = null;
   
    public ServletOutputStream getOutputStream() throws IOException {
        if((streamUsed != null) && (streamUsed != pw)) {
            throw new IllegalStateException();
        }
       
        if(servletGzipOS == null) {
            servletGzipOS = new GZIPServletOutputStream(getResponse().getOutputStream());
            streamUsed = servletGzipOS;
        }
        return servletGzipOS;
    }
   
    public PrintWriter getWriter() throws IOException {
        if((streamUsed != null) && (streamUsed != servletGzipOS)) {
            throw new IllegalStateException();
        }
       
        if(pw == null) {
            servletGzipOS = new GZIPServletOutputStream(getResponse().getOutputStream());
            OutputStreamWriter osw = new OutputStreamWriter(servletGzipOS, getResponse().getCharacterEncoding());
           
            pw = new PrintWriter(osw);
            streamUsed = pw;
        }
        return pw;
    }
}


package com.example.web;

import java.io.IOException;
import java.util.zip.GZIPOutputStream;

import javax.servlet.ServletOutputStream;

public class GZIPServletOutputStream extends ServletOutputStream {
    GZIPOutputStream internalGzipOS;
   
    GZIPServletOutputStream(ServletOutputStream sos) throws IOException {
        // TODO Auto-generated constructor stub
        this.internalGzipOS = new GZIPOutputStream(sos);
    }
   
    @Override
    public void write(int param) throws IOException {
        // TODO Auto-generated method stub
        internalGzipOS.write(param);
    }

}

압축과 관련된 부분은 다루고자 하는 범위를 넘어서는 듯 하며, Response를 어떻게 변형하여 넘겨주는지를 확인해 보면 된다.
CompressionResponseWrapper wrappedResp = new CompressionResponseWrapper(response); 와 같이 HttpServletResponseWrapper를 확장한 클래스를 통해 만들어진 랩퍼 클래스로부터 변경된 response 객체를 리턴받아 사용한다.
response 객체는 super(response);와 같이 상위 클래스에서 알아서 처리하도록 하며, 나머지 압축 관련 부분만 처리해 준다.


728x90
반응형

'Java > Servlet & JSP' 카테고리의 다른 글

필터 - REQUEST  (1) 2009.04.16
웹 애플리케이션 보안  (4) 2009.04.10
웹 애플리케이션 배포하기  (0) 2009.04.07
부모 자식 태그간의 통신  (0) 2009.03.26
클래식 커스텀 태그  (0) 2009.03.26