1. 程式人生 > >壓縮響應問題---HttpServletResponse物件增強

壓縮響應問題---HttpServletResponse物件增強

在向瀏覽器傳送響應內容時,可以對響應內容進行壓縮,將壓縮後的內容傳送到瀏覽器,同時通知瀏覽器發過來的內容是使用何種演算法進行壓縮的,瀏覽器再顯示時,將以此中方法進行解碼。這樣可以節省傳輸頻寬,加快響應速度。這裡可以利用Filter來實現全站的響應內容壓縮問題。但是HttpServletResponse物件本身不具有壓縮響應內容的功能,因此可以對其進行功能增強。

HttpServletResponseWrapper是對HttpServletResonse的預設包裝類,MyCompressResponse是繼承了HttpServletResponseWrapper類的包裝類;由於response向瀏覽器上輸出顯示內容有兩個方法,一個是同通過getOutputStream獲取流物件,呼叫其write方法將資料寫入outputStream流中。另一種方法是通過獲取getWriter來獲取一個PrintWriter的物件,通過其write方法想瀏覽器寫入一個字串,一個是基於bit流的,一個是基於字元流的。但是response本身這兩中方法都是直接向瀏覽器輸出響應內容,本沒有對其進行壓縮,因此需要對其進行增強。其思想是增強後的方法,將會先把響應內容輸出到一個快取內,對快取內的內容進行壓縮處理,能夠後將壓縮後的內容輸出到瀏覽器中,同時通知瀏覽器,接受到的內容是通過什麼演算法壓縮的及內容的大小,這時,瀏覽器將會根據此來顯示響應內容。下面是增強的MyCompressResponse,具體如下:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;

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

public class MyCompressResponse extends HttpServletResponseWrapper {
	private HttpServletResponse response; //接受一個response物件,將對其進行增強
	private ByteArrayOutputStream bout = new ByteArrayOutputStream(); //快取流,所有響應內容將會被輸出到此
	private PrintWriter pw; 
	
	public MyCompressResponse(HttpServletResponse response) {
		super(response);
		// TODO Auto-generated constructor stub
		this.response = response;
	}

	/* (non-Javadoc)
	 * @see javax.servlet.ServletResponseWrapper#getOutputStream()
	 */
	@Override
	public ServletOutputStream getOutputStream() throws IOException {
		// TODO Auto-generated method stub
		return new MyOutputStream(bout); //重寫getOutputStream方法
	}


	@Override
	public PrintWriter getWriter() throws IOException {
		// TODO Auto-generated method stub
		pw =  new MyPrintWriter(bout, super.getCharacterEncoding()); //重寫getWriter方法,同時對其write方法進行增強,write方法可以指定編碼方式	
		return pw; 
	}
	
	public byte[] getBuffer(){
		if(pw!=null){
			pw.close();//將資料輸出到bout流中
			
		}
		if(bout!=null){
			return bout.toByteArray();//將快取返回
		}
		
		return null;
	}
	
}

class MyOutputStream extends ServletOutputStream{
	private ByteArrayOutputStream bout;
	
	
	@Override
	public void write(int b) throws IOException {
		// TODO Auto-generated method stub
		bout.write(b); //將響應內容寫到bout快取流中
	}
	
	public MyOutputStream(ByteArrayOutputStream bout){
		this.bout = bout;
		
	}
	
}

class MyPrintWriter extends PrintWriter{
	private  ByteArrayOutputStream bout;
	private String charset;
	
	public MyPrintWriter(ByteArrayOutputStream bout, String charset) {
		super(bout);
		// TODO Auto-generated constructor stub
		this.bout = bout;  //建立一個PrintWriter,指定字元編碼方式
		this.charset = charset;
	}

	/* (non-Javadoc)
	 * @see java.io.PrintWriter#write(java.lang.String)
	 */
	@Override
	public void write(String s) {
		// TODO Auto-generated method stub
		try {
			bout.write(s.getBytes(charset)); //根據指定的編碼方式,將響應內容寫入到bout快取
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
Filter:
public class MyCompressFilter implements Filter{
	private FilterConfig filterConfig;
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp,
			FilterChain chain) throws IOException, ServletException {
		// TODO Auto-generated method stub
		HttpServletRequest request = (HttpServletRequest)req;
		HttpServletResponse response = (HttpServletResponse)resp;
		
		MyCompressResponse gzipResp = new MyCompressResponse(response);
		//使用gzipResp進行放行
		chain.doFilter(request, gzipResp);
		
		byte[] out = gzipResp.getBuffer(); //獲取快取內容
		
			ByteArrayOutputStream bout = new ByteArrayOutputStream();
			GZIPOutputStream gout = new GZIPOutputStream(bout);
			gout.write(out);
			gout.close(); //將快取內容寫入到使用GZIP方式壓縮的流中
			
			byte[] gzip = bout.toByteArray();
			System.out.println("length:"+out.length);//通知瀏覽器響應內容的壓縮方式及內容長度
			response.setHeader("content-encoding", filterConfig.getInitParameter("encoding"));
			response.setContentLength(gzip.length);
			response.getOutputStream().write(gzip); //使用response將壓縮後的內容寫到瀏覽器中
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub
		this.filterConfig = filterConfig;
	}
	
}