在客戶端訪問數據時候,爲了儘量高效率的傳輸,在傳輸的JSP網頁的時候,能夠採用GZIP壓縮的方式,使得網頁通過壓縮後再去傳輸。在此,使用過濾器,對發送到的客戶端的顯示,都先進行一次壓縮。而後再顯示,具體流程能夠參考下圖:java
也就是說,當每得到一次請求是的時候,經過對getOutputStream的重寫,不讓其輸出到客戶端,而是 將其寫入到內存字節數組中去。 而後,當須要輸出的時候, 也就是過濾器的第二次執行從chain.doFilter(request,response)開始數組
再次充內存中取出緩存的數據,進行壓縮,並用response進行輸出。緩存
package cn.Filter; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.zip.GZIPOutputStream; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; public class FilterGZIP implements Filter { public void destroy() { // TODO Auto-generated method stub } public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest) req; HttpServletResponse response=(HttpServletResponse) res; //從新封裝response ,來達到改寫其已知方法的過程 MyResponse mresponse=new MyResponse(response); //以上爲過濾器的請求時候的過濾過程; //當請求的時候,傳入的response 的getOutPutStream方法已經被修改過了。 //所以,此時若是頁面上調用getOutPutStream 方法的時候,其實調用的是本身寫的。 chain.doFilter(request, mresponse); //請求接受, 開始響應,二次輸出的時候,就是開始要將內存中的字節數組,通過壓縮傳輸到客戶端的過程了。 ByteArrayOutputStream baos =new ByteArrayOutputStream(); GZIPOutputStream gos=new GZIPOutputStream(baos); //從內存中獲取到 原始爲壓縮的數據。 byte b[]= mresponse.getByte(); System.out.println("壓縮前共有"+b.length+"字節"); gos.write(b); gos.flush(); gos.close(); b=baos.toByteArray(); System.out.println("壓縮後共有"+b.length+"字節"); //設置客戶端識別打開的方式。 response.setHeader("Content-Encoding", "GZIP"); response.setContentLength(b.length); response.getOutputStream().write(b); } public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub } }
以上就是Filter中的所有代碼,而後 就是怎樣從新封裝response的問題了。J2EE中提供了,響應的包裝類ServletResponseWrapper 只要繼承這個類,重寫相應的getOutPutStreaM方法,則目標即刻達成!app
class MyResponse extends HttpServletResponseWrapper { //這個是用來存放頁面要輸出信息的字節數組。 private ByteArrayOutputStream baos=new ByteArrayOutputStream(); //這個封裝的字符流輸出對象 private PrintWriter pw; public MyResponse(HttpServletResponse response) { super(response); } //這個方法,很重要,就是用來獲取頁面信息存放在內存中的字節數組。 也是壓縮的目的 public byte[] getByte() { try { if(pw!=null){ pw.flush(); pw.close(); } baos.flush(); } catch (IOException e) { e.printStackTrace(); } return baos.toByteArray(); } //這個方法,就是咱們要重寫的方法,可是這個方法,有個返回值ServletOutputStream,而這個類又是個抽象類,因此必須還要把這個類給實現了。能夠參考下一個代碼塊 @Override public ServletOutputStream getOutputStream() throws IOException { return new MyServletOutputStream(baos); } @Override public PrintWriter getWriter() throws IOException { pw= new PrintWriter(new OutputStreamWriter(baos,super.getCharacterEncoding())); return pw; } }
//這個是應上面getOutPutStream 的邀請的返回值。 也是要 servlet中實際調用的方法。 不會輸出到頁面,只會將servlet中要寫的內容放入到內存中去。 class MyServletOutputStream extends ServletOutputStream{ //緩衝頁面數據存放區域 private ByteArrayOutputStream baos; public MyServletOutputStream(ByteArrayOutputStream baos){ this.baos=baos; } @Override public void write(int b) throws IOException { //將輸出寫入輸出緩存 baos.write(b); } }
我本身的理解圖形
ide