Filter-全站GZIP壓縮

GZIP壓縮:將壓縮後的文本文件,發送給瀏覽器,減小流量。java

 

1、進行gzip壓縮條件:數組

  一、請求頭:Accept-Encoding : gzip  告訴服務器,該瀏覽器支持gzip壓縮。瀏覽器

  二、響應頭:Content-Encoding : gzip.  告訴瀏覽器,輸出信息用gzip進行壓縮了。緩存

  三、兩個主要類:服務器

    ByteArrayOutputStream : 內存輸出流,還有緩存。app

    GZIPOutputStream 包裝流;測試

 

2、gzip 壓縮步驟:this

    一、獲取字符的字節數組 byte[] buf = str.getBytes() ;spa

    二、經過GZIPOutputStream 包裝流進行輸入:code

       建立 GZIPOutputStream 輸出流時,須要傳一個帶有緩衝區的輸出流,因此咱們ByteArrayOutputStream 輸出流。並且,ByteArrayOutputStream還能夠獲取byte[];

    三、將ByteArrayOutputStream 流中的緩存數據,轉換成字節數組。

    四、將 壓縮後的字節數組經過response 進行輸出。不過輸出以前要設置Content-Encoding 響應頭,value爲gzip。告訴瀏覽器數據進行了gzip壓縮,要使用gzip解壓

String str = "我是個測試";
            //1\獲取字節數組
            byte[] bytes = str.getBytes() ;
            
            System.out.println("壓縮前的長度:" + bytes.length); 
            //2\
            ByteArrayOutputStream baos = new ByteArrayOutputStream() ; 
            GZIPOutputStream  gzip = new GZIPOutputStream(baos) ;
            
            gzip.write(bytes) ; 
            gzip.close() ;
            //3\
            bytes = baos.toByteArray() ;
            System.out.println("壓縮後的長度:" + bytes.length);


    數據較小是,壓縮的效果不是很明顯,不過數據越大,壓縮效果越明顯。因此,GZIP壓縮通常只處理文本內容,對圖片、已經壓縮過的文件則不進行壓縮。這時就要在配置文件時,配置要過濾的資源

  

 

 

3、GZIPFilter

複製代碼

 import itheima.decorator.MyHttpServletResponse;

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

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * Gzip壓縮過濾器
 * @author 賀佐安
 *
 */
public class GZIPFilter implements Filter{

    public void init(FilterConfig filterConfig) throws ServletException {
    }

    public void doFilter(ServletRequest req , ServletResponse resp ,
            FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) resp ; 
        HttpServletRequest request = (HttpServletRequest) req ;
        //建立HttpServletResponse 包裝類的實例
        MyHttpServletResponse myResponse = new MyHttpServletResponse(response) ;
        
        chain.doFilter(request, myResponse) ;
        
        //GZIP壓縮:
        byte[] buff = myResponse.getBufferedBytes() ;  
        //建立緩存容器:
        ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
        
        GZIPOutputStream gzip = new GZIPOutputStream(baos) ;
        
        gzip.write(buff) ;
        
        gzip.close() ;
        
        buff = baos.toByteArray() ;
         
        //設置響應頭;
        response.setHeader("Content-Encoding", "gzip");
        response.setContentLength(buff.length) ;  
        response.getOutputStream().write( buff) ;
    }

    public void destroy() {
    }

}

複製代碼

 

  步驟:

    一、對HttpServletResponse 進行包裝 :改寫getOutputStream()、getWriter() 方法,而且設置一個臨時容器,存儲Serlvet處理後要輸出的數據。 這裏是重點。

複製代碼

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
/**
 * 對HttpServletResponse 進行包裝
 * @author 賀佐安
 *
 */
public class MyHttpServletResponse extends HttpServletResponseWrapper {
    //定義一個容器,用來存儲Serlvet 處理完後response 寫出的數據
    private ByteArrayOutputStream bos = new ByteArrayOutputStream()  ;
    private PrintWriter printWriter = null;
    public MyHttpServletResponse(HttpServletResponse  response) {
        super(response) ;
    }
    //處理字節流輸出的狀況
    public ServletOutputStream getOutputStream() throws IOException {
        return new MyServletOutputStream(bos); 
    } 

    //處理字符流輸出的狀況:用字符流時要注意亂碼:字節轉字符要查碼錶,字符轉字節也要查碼錶
    public PrintWriter getWriter() throws IOException {
        printWriter  = new PrintWriter(new OutputStreamWriter(bos, super.getCharacterEncoding())) ;
        return printWriter;
    }
    //獲取response 寫出的數據
    public byte[] getBufferedBytes(){
        try {
            if (printWriter != null) 
                printWriter.close() ;
            bos.flush() ;
        } catch (IOException e) {
            e.printStackTrace(); 
        }
        byte[] byteArray = bos.toByteArray() ;
        return  byteArray;
    }
}

複製代碼

 

    二、改寫getOutputStream 方法時,要返回一個SerlvetOutputStream 類實例,由於SerlvetOutputStream是抽象類,不能建立實例,因此要重寫SerlvetOutputStream 類:

複製代碼

 import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.servlet.ServletOutputStream;
/**
 * 包裝ServletOutputStream ,改寫write 方法。
 * @author 賀佐安
 *
 */
public class MyServletOutputStream extends ServletOutputStream {
    private ByteArrayOutputStream bos = null ; 
    public MyServletOutputStream (ByteArrayOutputStream bos) {
        this.bos = bos ;
    }
    public void write(int b) throws IOException {
        bos.write(b) ;
    }
}

複製代碼

 

    三、將包裝過的HttpServletResponse 類的實例放行。

    四、而後獲取Servlet 處理事後的數據,而後進行Gzip壓縮。

    五、調用ServletResponse 的實例,將壓縮後的數據寫出去。

複製代碼

 //GZIP壓縮:
        byte[] buff = myResponse.getBufferedBytes() ;  
        //建立緩存容器:
        ByteArrayOutputStream baos = new ByteArrayOutputStream() ;
        
        GZIPOutputStream gzip = new GZIPOutputStream(baos) ;
        
        gzip.write(buff) ;
        
        gzip.close() ;
        
        buff = baos.toByteArray() ;
         
        //設置響應頭;
        response.setHeader("Content-Encoding", "gzip");
        response.setContentLength(buff.length) ;  
        response.getOutputStream().write( buff) ;

複製代碼

  

  以上即是用Filter 對一些文本資源進行GIZP壓縮的步驟。重點就是第二步,如何獲取Servlet 返回的數據。更細一點的流程以下圖:

    

    

 

 --------------------------------------------------------------------------------------------更新:2013年7月21日 22:34:54

相關文章
相關標籤/搜索