zoukankan      html  css  js  c++  java
  • Filter之——GZIP全站压缩

         GZIP压缩:将压缩后的文本文件,发送给浏览器,减少流量。

    一、进行gzip压缩条件:

      1、请求头:Accept-Encoding : gzip  告诉服务器,该浏览器支持gzip压缩。

      2、响应头:Content-Encoding : gzip.  告诉浏览器,输出信息用gzip进行压缩了。

      3、两个主要类:

        ByteArrayOutputStream : 内存输出流,还有缓存。

        GZIPOutputStream 包装流;

    二、gzip 压缩步骤:

        1、获取字符的字节数组 byte[] buf = str.getBytes() ;

        2、通过GZIPOutputStream 包装流进行输入:

           创建 GZIPOutputStream 输出流时,需要传一个带有缓冲区的输出流,所以我们ByteArrayOutputStream 输出流。而且,ByteArrayOutputStream还可以获取byte[];

        3、将ByteArrayOutputStream 流中的缓存数据,转换成字节数组。

        4、将 压缩后的字节数组通过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压缩一般只处理文本内容,对图片、已经压缩过的文件则不进行压缩。这时就要在配置文件时,配置要过滤的资源

      

    三、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 }

      步骤:

        1、对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 }

        2、改写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 }

        3、将包装过的HttpServletResponse 类的实例放行。

        4、然后获取Servlet 处理过后的数据,然后进行Gzip压缩。

        5、调用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

  • 相关阅读:
    在Android studio中,测试输出数组中最大子数组的和
    我所理解的软件开发模式
    java实现随机输出300题四则运算
    Demo(3月28日)
    关于构建之法中小飞问题的个人看法
    对搭档代码的一些意见
    项目复审
    安卓UI测试(基于android studio环境 espresso框架)
    读构建之法后的一些个人感受
    思考题
  • 原文地址:https://www.cnblogs.com/jbelial/p/3204415.html
Copyright © 2011-2022 走看看