Chinaunix首页 | 论坛 | 博客
  • 博客访问: 26140790
  • 博文数量: 2065
  • 博客积分: 10377
  • 博客等级: 上将
  • 技术积分: 21525
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-04 17:50
文章分类

全部博文(2065)

文章存档

2012年(2)

2011年(19)

2010年(1160)

2009年(969)

2008年(153)

分类: Java

2010-02-07 13:21:06

jsp实现GZIP压缩输出过滤器

目前实现gzip压缩有2种办法:

一、是有的容器(服务器)提供的功能,但这个局限于特定容器。比如apache+tomcat或者resin-pro
二、是部署前手动gzip压缩,配合servlet过滤器使用,这个能实现gzip功能,但是降低了灵活性。

一、 介绍Resin容器中配置GZIP压缩方法

http://localhost:8080/MyProj/pdf/0.jpg 可以打开一张图片。用Httpwatch查看

Accept-Encoding: gzip, deflate

Sent   :   315

Received   43106

开始配置Resin

我按照这样的配置:

          

          

              true

          

          

        

          

             *.jpg

             /*

          

        

     

再测试发现不起作用!不清楚如何配置哦!

我再看了一下资料上面有讲说 需要resin的专业版即resin-pro

现在再看下我的resin Resin-3.2.1 (built Fri, 17 Oct 2008 04:11:01 PDT)

果然是我的版本不一致导致的。重新从网上下载一下专业版的RESIN下来再试!

以下是我再测试的过程:

测试发现还是不行呀!我昏~~~ 不过感觉专业版与普通版在配置上面还是有点差别的

待续未完!

 

二、 通过程序实现

采用gzip servlet filter实现

HTTP/1.1 开始,客户端就可以在请求头中添加

Accept-Encoding: gzip,deflate     (可以从HTTP WATCH中查看发现确实支持)

来向请求的服务器表明自己支持 Gzip 压缩的响应。Web 服务器则在响应头中添加

Content-Encoding: gzip
来向客户端表明响应体是经过 gzip 压缩的。

 

程序代码如下:

(在此非常感谢 http://tdcq.javaeye.com/blog/453644 提供代码)

具体代码如下:

package sh.blog.util.web.filter; 

import java.io.IOException; 

import java.util.zip.GZIPOutputStream; 

import javax.servlet.ServletOutputStream; 

public class CompressedStream extends ServletOutputStream { 

       private ServletOutputStream out; 

       private GZIPOutputStream    gzip; 

     /**

     * 指定压缩缓冲流

     * @param 输出流到压缩

     * @throws IOException if an error occurs with the {@link GZIPOutputStream}.

     */ 

       public CompressedStream(ServletOutputStream out) throws IOException { 

           this.out = out; 

           reset(); 

       } 

       /** @see ServletOutputStream * */ 

       public void close() throws IOException { 

           gzip.close(); 

       } 

       /** @see ServletOutputStream * */ 

       public void flush() throws IOException { 

          gzip.flush(); 

       } 

       /** @see ServletOutputStream * */ 

       public void write(byte[] b) throws IOException { 

           write(b, 0, b.length); 

       } 

       /** @see ServletOutputStream * */ 

       public void write(byte[] b, int off, int len) throws IOException { 

           gzip.write(b, off, len); 

       } 

       /** @see ServletOutputStream * */ 

       public void write(int b) throws IOException { 

           gzip.write(b); 

       } 

    

       public void reset() throws IOException { 

           gzip = new GZIPOutputStream(out); 

       } 

} 

 

package sh.blog.util.web.filter;

import java.io.IOException;

import java.io.PrintWriter;   

import javax.servlet.ServletOutputStream;   

import javax.servlet.http.HttpServletResponse;   

import javax.servlet.http.HttpServletResponseWrapper;   

 

public class CompressionResponse extends HttpServletResponseWrapper{

    protected HttpServletResponse response;   

    private ServletOutputStream out;   

    private CompressedStream compressedOut;  

    private PrintWriter writer;   

    protected int contentLength;   

    public CompressionResponse(HttpServletResponse response) throws IOException {   

       super(response);

       this.response = response;   

       compressedOut = new CompressedStream(response.getOutputStream()); 

    }

    public void setContentLength(int len) { 

       contentLength = len;   

    }

    public ServletOutputStream getOutputStream() throws IOException {   

       if (null == out) {   

           if (null != writer) {  

              throw new IllegalStateException("getWriter() has already been called on this response.");   

           }

           out = compressedOut;   

       }

       return out; 

    }

    public PrintWriter getWriter() throws IOException {   

       if (null == writer) {   

           if (null != out) {   

              throw new IllegalStateException("getOutputStream() has already been called on this response.");

           }

           writer = new PrintWriter(compressedOut);  

       }

       return writer;   

    }

    public void flushBuffer() {   

       try {   

           if (writer != null) {

              writer.flush();

           }else if (out != null) {  

              out.flush();   

           }

       }catch (IOException e) {  

           e.printStackTrace();   

       }

    }

    public void reset() {

       super.reset();   

       try {   

           compressedOut.reset();   

       }catch (IOException e) {  

           throw new RuntimeException(e);   

       }

    }

    public void resetBuffer() {   

       super.resetBuffer();   

       try {   

           compressedOut.reset();   

       }catch (IOException e) {  

           throw new RuntimeException(e);

       }

    }

    public void close() throws IOException {   

       compressedOut.close();   

    }

 

}

 

package sh.blog.util.web.filter;

 

import java.io.IOException;   

import java.util.Enumeration;   

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;   

import org.apache.commons.logging.Log;   

import org.apache.commons.logging.LogFactory;   

public class CompressionFilter implements Filter {   

     protected Log log = LogFactory.getFactory().getInstance(this.getClass().getName());   

     @SuppressWarnings("unchecked")   

     public void doFilter(ServletRequest request, ServletResponse response,   

             FilterChain chain) throws IOException, ServletException {   

         boolean compress = false;   

         if (request instanceof HttpServletRequest){   

             HttpServletRequest httpRequest = (HttpServletRequest) request;   

             Enumeration headers = httpRequest.getHeaders("Accept-Encoding");   

            while (headers.hasMoreElements()){   

                 String value = (String) headers.nextElement();   

                 if (value.indexOf("gzip") != -1){   

                     compress = true;   

                 }   

             }   

         }   

         if (compress){//如果浏览器支持则压缩   

             HttpServletResponse httpResponse = (HttpServletResponse) response;   

             httpResponse.addHeader("Content-Encoding", "gzip");   

             CompressionResponse compressionResponse= new CompressionResponse(httpResponse);   

             chain.doFilter(request, compressionResponse);   

             compressionResponse.close();   

         }   

         else{//如果浏览器不支持则不压缩   

             chain.doFilter(request, response);   

         }   

     }   

     public void init(FilterConfig config) throws ServletException {   

     }   

    

     public void destroy(){   

     }   

 }   

 

一共有三个CLASS文件!实现GZIP压缩输出响应

 

2.1 对图片输出做压缩处理测试

建立目录pdf里面存储图片

第一步:不配置过滤器用HTTP WATCHE发现

image/jpeg : 42891 bytes, 670 x 446 pixels

 

第二步:配置Web.xml配置过滤器

<filter>

<filter-name>gzipfilter-name>

<filter-class>sh.blog.util.web.filter.CompressionFilterfilter-class>

filter>

<filter-mapping>

<filter-name>gzipfilter-name>

<url-pattern>/pdf/*url-pattern>

filter-mapping>

再用HTTP WATCH查看发现

image/jpeg : 42891 bytes, gzip compressed to 42712 bytes ( 0.417 % saving ), 670 x 446 pixels

实现了一次压缩处理输出!

PS:我再用png格式的图片做过一次测试发现一次可以实现GZIP压缩输出

结论:通过上面的过滤器能够实现对图片的压缩处理,提高响应速度!

 

2.2 对音乐的压缩处理以MP3的输出 为测试对象

建立目录music里面存储音乐

第一步:不配置过滤器发现

audio/mpeg : 9001 bytes of binary data

第二步:配置过滤器

   <filter>

    <filter-name>gzipfilter-name>

    <filter-class>sh.blog.util.web.filter.CompressionFilterfilter-class>

  filter>

  <filter-mapping>

    <filter-name>gzipfilter-name>

    <url-pattern>/music/*url-pattern>   

  filter-mapping>

再次查看发现:

audio/mpeg : , gzip compressed to 0 bytes ( 0 % saving )

结论:上面的算法对音乐文件不起压缩作用。感觉这种GZIP的算法应该是不同的格式算法不一样

 

2.3 JS文件压缩输出

第一步:不做压缩

4864

第二步:配置压缩

<filter>

<filter-name>gzipfilter-name>

<filter-class>sh.blog.util.web.filter.CompressionFilterfilter-class>

filter>

<filter-mapping>

<filter-name>gzipfilter-name>

<url-pattern>/scripts/*.jsurl-pattern>   

filter-mapping>

输出:

application/x-javascript : 4636 bytes, gzip compressed to 69 bytes ( 98.5 % saving )

查看发现JS的压缩是相当高的了!

结论:将JS存入指定的目录然后直接对此目录做GZIP压缩输出。可以看到效果是显著的!

通过做GZIP压缩输出之后可以减少网络带宽流量从而加快下载速度!

 

2.4 CSS文件压缩输出

第一步:没有压缩输出

text/css : 413 bytes

第二步:压缩

配置:

<filter>

<filter-name>gzipfilter-name>

<filter-class>sh.blog.util.web.filter.CompressionFilterfilter-class>

filter>

<filter-mapping>

<filter-name>gzipfilter-name>

<url-pattern>/scripts/*.jsurl-pattern>   

<url-pattern>/style/*.cssurl-pattern>

filter-mapping>

结果:

text/css : 413 bytes, gzip compressed to 101 bytes ( 75.5 % saving )

结论:对CSS的压缩效果也是非常明显的哦!

 

2.5 HTML页面压缩输出

第一步:不压缩

text/html : 2272 bytes

第二步;压缩

   <filter>

    <filter-name>gzipfilter-name>

<filter-class>sh.blog.util.web.filter.CompressionFilterfilter-class>

  filter>

  <filter-mapping>

    <filter-name>gzipfilter-name>

    <url-pattern>/scripts/*.jsurl-pattern>   

    <url-pattern>/style/*.cssurl-pattern>

    <url-pattern>*.htmlurl-pattern>

  filter-mapping>

结果:

text/html : 2272 bytes, gzip compressed to 240 bytes ( 89.4 % saving )

 

结论:对HTML的压缩效果也是非常明显的哦!

 

2.6 JSP页面的压缩

第一步:未做压缩

text/html; charset=iso-8859-1 : 1008 bytes

第二步:压缩输出

   <filter>

    <filter-name>gzipfilter-name>

    <filter-class>sh.blog.util.web.filter.CompressionFilterfilter-class>

  filter>

  <filter-mapping>

    <filter-name>gzipfilter-name>

    <url-pattern>/scripts/*.jsurl-pattern>   

    <url-pattern>/style/*.cssurl-pattern>

    <url-pattern>*.htmlurl-pattern>

    <url-pattern>*.jspurl-pattern>

  filter-mapping>

结果:页面 无输出!

 

结论:

    以上的算法可以应用于 图片、HTMLCSSJSGZIP压缩输出。对于JSP页面无效!

应用:

    将来可以在站点中编写此类过滤器,将页面内容尽可能地做GZIP输出提高下载的速度!

 

 

阅读(1876) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~