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