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解壓。
1 String str = "我是個測試"; 2 //1\獲取字節數組 3 byte[] bytes = str.getBytes() ; 4 5 System.out.println("壓縮前的長度:" + bytes.length); 6 //2\ 7 ByteArrayOutputStream baos = new ByteArrayOutputStream() ; 8 GZIPOutputStream gzip = new GZIPOutputStream(baos) ; 9 10 gzip.write(bytes) ; 11 gzip.close() ; 12 //3\ 13 bytes = baos.toByteArray() ; 14 System.out.println("壓縮後的長度:" + bytes.length);
數據較小是,壓縮的效果不是很明顯,不過數據越大,壓縮效果越明顯。因此,GZIP壓縮通常只處理文本內容,對圖片、已經壓縮過的文件則不進行壓縮。這時就要在配置文件時,配置要過濾的資源。
3、GZIPFilter
1 import itheima.decorator.MyHttpServletResponse; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.IOException; 5 import java.util.zip.GZIPOutputStream; 6 7 import javax.servlet.Filter; 8 import javax.servlet.FilterChain; 9 import javax.servlet.FilterConfig; 10 import javax.servlet.ServletException; 11 import javax.servlet.ServletRequest; 12 import javax.servlet.ServletResponse; 13 import javax.servlet.http.HttpServletRequest; 14 import javax.servlet.http.HttpServletResponse; 15 /** 16 * Gzip壓縮過濾器 17 * @author 賀佐安 18 * 19 */ 20 public class GZIPFilter implements Filter{ 21 22 public void init(FilterConfig filterConfig) throws ServletException { 23 } 24 25 public void doFilter(ServletRequest req , ServletResponse resp , 26 FilterChain chain) throws IOException, ServletException { 27 HttpServletResponse response = (HttpServletResponse) resp ; 28 HttpServletRequest request = (HttpServletRequest) req ; 29 //建立HttpServletResponse 包裝類的實例 30 MyHttpServletResponse myResponse = new MyHttpServletResponse(response) ; 31 32 chain.doFilter(request, myResponse) ; 33 34 //GZIP壓縮: 35 byte[] buff = myResponse.getBufferedBytes() ; 36 //建立緩存容器: 37 ByteArrayOutputStream baos = new ByteArrayOutputStream() ; 38 39 GZIPOutputStream gzip = new GZIPOutputStream(baos) ; 40 41 gzip.write(buff) ; 42 43 gzip.close() ; 44 45 buff = baos.toByteArray() ; 46 47 //設置響應頭; 48 response.setHeader("Content-Encoding", "gzip"); 49 response.setContentLength(buff.length) ; 50 response.getOutputStream().write( buff) ; 51 } 52 53 public void destroy() { 54 } 55 56 }
步驟:
一、對HttpServletResponse 進行包裝 :改寫getOutputStream()、getWriter() 方法,而且設置一個臨時容器,存儲Serlvet處理後要輸出的數據。 這裏是重點。
1 import java.io.ByteArrayOutputStream; 2 import java.io.IOException; 3 import java.io.OutputStreamWriter; 4 import java.io.PrintWriter; 5 6 import javax.servlet.ServletOutputStream; 7 import javax.servlet.http.HttpServletResponse; 8 import javax.servlet.http.HttpServletResponseWrapper; 9 /** 10 * 對HttpServletResponse 進行包裝 11 * @author 賀佐安 12 * 13 */ 14 public class MyHttpServletResponse extends HttpServletResponseWrapper { 15 //定義一個容器,用來存儲Serlvet 處理完後response 寫出的數據 16 private ByteArrayOutputStream bos = new ByteArrayOutputStream() ; 17 private PrintWriter printWriter = null; 18 public MyHttpServletResponse(HttpServletResponse response) { 19 super(response) ; 20 } 21 //處理字節流輸出的狀況 22 public ServletOutputStream getOutputStream() throws IOException { 23 return new MyServletOutputStream(bos); 24 } 25 26 //處理字符流輸出的狀況:用字符流時要注意亂碼:字節轉字符要查碼錶,字符轉字節也要查碼錶 27 public PrintWriter getWriter() throws IOException { 28 printWriter = new PrintWriter(new OutputStreamWriter(bos, super.getCharacterEncoding())) ; 29 return printWriter; 30 } 31 //獲取response 寫出的數據 32 public byte[] getBufferedBytes(){ 33 try { 34 if (printWriter != null) 35 printWriter.close() ; 36 bos.flush() ; 37 } catch (IOException e) { 38 e.printStackTrace(); 39 } 40 byte[] byteArray = bos.toByteArray() ; 41 return byteArray; 42 } 43 }
二、改寫getOutputStream 方法時,要返回一個SerlvetOutputStream 類實例,由於SerlvetOutputStream是抽象類,不能建立實例,因此要重寫SerlvetOutputStream 類:
1 import java.io.ByteArrayOutputStream; 2 import java.io.IOException; 3 4 import javax.servlet.ServletOutputStream; 5 /** 6 * 包裝ServletOutputStream ,改寫write 方法。 7 * @author 賀佐安 8 * 9 */ 10 public class MyServletOutputStream extends ServletOutputStream { 11 private ByteArrayOutputStream bos = null ; 12 public MyServletOutputStream (ByteArrayOutputStream bos) { 13 this.bos = bos ; 14 } 15 public void write(int b) throws IOException { 16 bos.write(b) ; 17 } 18 }
三、將包裝過的HttpServletResponse 類的實例放行。
四、而後獲取Servlet 處理事後的數據,而後進行Gzip壓縮。
五、調用ServletResponse 的實例,將壓縮後的數據寫出去。
1 //GZIP壓縮: 2 byte[] buff = myResponse.getBufferedBytes() ; 3 //建立緩存容器: 4 ByteArrayOutputStream baos = new ByteArrayOutputStream() ; 5 6 GZIPOutputStream gzip = new GZIPOutputStream(baos) ; 7 8 gzip.write(buff) ; 9 10 gzip.close() ; 11 12 buff = baos.toByteArray() ; 13 14 //設置響應頭; 15 response.setHeader("Content-Encoding", "gzip"); 16 response.setContentLength(buff.length) ; 17 response.getOutputStream().write( buff) ;
以上即是用Filter 對一些文本資源進行GIZP壓縮的步驟。重點就是第二步,如何獲取Servlet 返回的數據。更細一點的流程以下圖:
--------------------------------------------------------------------------------------------更新:2013年7月21日 22:34:54