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