`

JSP Filter,GZIP压缩响应流

阅读更多
url:http://hi.baidu.com/xhftx/blog/item/fbc11d3012648711ebc4af59.html
关键词:JSP,Filter,Servlet,GZIP

现在主流浏览器都是支持gzip的。服务器压缩网页后进行传输,可减少传输数据的大小使用户感觉访问速度更快。当然,压缩也会消耗一部分服务器处理时间。

用Filter实现对返回信息的压缩,代码参考Tomcat examples里面的
compressionFilters:
GZipStream.java

import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletOutputStream;

public class GZipStream extends ServletOutputStream {

  private GZIPOutputStream zipStream;

  public GZipStream(OutputStream out) throws IOException {
    zipStream = new GZIPOutputStream(out);
  }

  @Override
  public void flush() throws IOException {
    zipStream.flush();
  }

  @Override
  public void write(byte[] b, int off, int len) throws IOException {
    zipStream.write(b, off, len);
  }

  @Override
  public void write(byte[] b) throws IOException {
    zipStream.write(b);
  }

  @Override
  public void write(int arg0) throws IOException {
    zipStream.write(arg0);
  }

  public void finish() throws IOException {
    zipStream.finish();
  }

  public void close() throws IOException {
    zipStream.close();
  }

} 


GZipResponse.java

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;

public class GZipResponse extends HttpServletResponseWrapper {
  private GZipStream stream;
  private PrintWriter writer;
  public GZipResponse(HttpServletResponse response) throws IOException{
    super(response);
    stream=new GZipStream(response.getOutputStream());
  }
  
  @Override
  public ServletOutputStream getOutputStream() throws IOException {
    return stream;
  }

  @Override
  public PrintWriter getWriter() throws IOException {
    if (writer == null) {
      writer = new PrintWriter(new OutputStreamWriter(
          getOutputStream(), getCharacterEncoding()));
    }
    return writer;
  }

  public void flush() throws IOException {
    if (writer != null) {
      writer.flush();
    }
    stream.finish();
  }

} 


GZipFilter.java


import java.io.IOException;
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;

public class GZipFilter implements Filter {

  public void destroy() {
  }

  public void init(FilterConfig fConfig) throws ServletException {
  }

  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
  throws IOException, ServletException {
    HttpServletRequest req=(HttpServletRequest)request;
    HttpServletResponse res=(HttpServletResponse)response;
    if(isGZipEncoding(req)){
      GZipResponse zipResponse=new GZipResponse(res);
      res.setHeader("Content-Encoding", "gzip");
      chain.doFilter(request, zipResponse);
      zipResponse.flush();
    } else {
      chain.doFilter(request, response);
    }
  }
  
  /**
   * 判断浏览器是否支持GZIP
   * @param request
   * @return
   */
  private static boolean isGZipEncoding(HttpServletRequest request){
    boolean flag=false;
    String encoding=request.getHeader("Accept-Encoding");
    if(encoding.indexOf("gzip")!=-1){
      flag=true;
    }
    return flag;
  }

} 

web.xml配置
<filter>
   <description>
   </description>
   <display-name>GZipFilter</display-name>
   <filter-name>GZipFilter</filter-name>
   <filter-class>GZipFilter</filter-class>
</filter>
<filter-mapping>
   <filter-name>GZipFilter</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>


这个配置是对所有的资源都进行压缩传输,对于图片,flash等本身已经压缩过的文件就没有必要再进行压缩了,可以根据自己的需要更改<url-pattern>已提高WEB访问速度。

tomcat自带源码剖析:
url:http://hi.baidu.com/springfieldx/blog/item/9faa88dfd5760414495403b6.html
在响应请求的时候对response进行封装,替换他的输出流为 GZipOutputStream 压缩输出流


package compressionFilters;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;


public class CompressionResponseStream extends ServletOutputStream {

//是否启用压缩的临界值
protected int compressThreshold = 0;

//临时容纳写入的数据缓冲区
protected byte[] buffer = null;

//缓冲区实际写入的数据量
protected int bufferCount = 0;

protected GZIPOutputStream gzipstream = null;

//当前流对象是否处于关闭状态
protected boolean closed = false;

protected int length = -1;

//用于返回数据的 Response对象
protected HttpServletResponse response = null;

protected ServletOutputStream output = null;



public CompressionResponseStream(HttpServletResponse response) throws IOException{
   super();
   closed = false;
   this.response = response;
   this.output = response.getOutputStream();
}

//设置启用压缩的临界值,并初始化输出缓冲区
public void setBuffer(int threshold){
   compressThreshold = threshold;
   buffer = new byte[threshold];
}

/**
* 关闭流对象
*/
public void close() throws IOException{
   if(closed){
    throw new IOException("This output stream has already been closed");
   }
  
   //如果当前启用的是压缩流,用压缩流刷新缓冲区
   if(gzipstream != null){
    flushToGZip();
    gzipstream.close();
    gzipstream = null;
   }else{
    //如果未开启压缩,则用response的默认输出流刷新缓冲区
    if(bufferCount > 0){
     output.write(buffer, 0, bufferCount);
     bufferCount = 0;
    }
   }
}

/**
* 刷新输出缓冲区
*/
public void flush() throws IOException{
   if(closed){
    throw new IOException("Cannot flush a closed output stream");
   }
   if(gzipstream != null){
    gzipstream.flush();
   }
}

public void write(int b) throws IOException {
  
   if(closed){
    throw new IOException("Cannot write to a closed output stream");
   }
  
   //如果数据超出了缓冲区(启用压缩的临界值),则启用压缩模式
   if(bufferCount >= buffer.length){
    flushToGZip();
   }
   //如果没有超出缓冲区,则将数据写入缓冲区
   buffer[bufferCount++] = (byte)b;
  
}

public void write(byte[] b,int off,int len) throws IOException{
   if(closed){
    throw new IOException("Cannot write to a closed output stream");
   }
  
   if(len == 0){
    return;
   }
   //如果缓冲区能容纳这些数据则写入缓冲区
   if(len <= buffer.length - bufferCount){
    System.arraycopy(b, off, buffer, bufferCount, len);
    bufferCount += len;
    return;
   }
  
   //如果缓冲区剩余空间不住足,则开启压缩流对象
   flushToGZip();
  
   //如果清空后的缓冲区能够容纳传送过来的数据,则将数据写入缓冲区
   if(len <= buffer.length - bufferCount){
    System.arraycopy(b, off, buffer, bufferCount, len);
    bufferCount += len;
    return;
   }
  
   //如果缓冲区不能容纳传送进来的数据,则直接将数据写入压缩流对象
   writeToGZip(b, off, len);
}


//刷新压缩流对象的缓冲区
public void flushToGZip() throws IOException{
   if(bufferCount > 0){
    writeToGZip(buffer, 0, bufferCount);
    bufferCount = 0;
   }
}

public void writeToGZip(byte b[],int off,int len)throws IOException{
  
   //如果压缩流对象为空,这里初始化它
   if(gzipstream == null){
    response.addHeader("Content-Encoding", "gzip");
    gzipstream = new GZIPOutputStream(output);
   }
  
   //将数据听过压缩流对象输出到response的输出流
   gzipstream.write(b,off,len);
}



public boolean closed(){
   return closed;
}

}



package compressionFilters;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;


public class CompressionResponseStream extends ServletOutputStream {

//是否启用压缩的临界值
protected int compressThreshold = 0;

//临时容纳写入的数据缓冲区
protected byte[] buffer = null;

//缓冲区实际写入的数据量
protected int bufferCount = 0;

protected GZIPOutputStream gzipstream = null;

//当前流对象是否处于关闭状态
protected boolean closed = false;

protected int length = -1;

//用于返回数据的 Response对象
protected HttpServletResponse response = null;

protected ServletOutputStream output = null;



public CompressionResponseStream(HttpServletResponse response) throws IOException{
   super();
   closed = false;
   this.response = response;
   this.output = response.getOutputStream();
}

//设置启用压缩的临界值,并初始化输出缓冲区
public void setBuffer(int threshold){
   compressThreshold = threshold;
   buffer = new byte[threshold];
}

/**
* 关闭流对象
*/
public void close() throws IOException{
   if(closed){
    throw new IOException("This output stream has already been closed");
   }
  
   //如果当前启用的是压缩流,用压缩流刷新缓冲区
   if(gzipstream != null){
    flushToGZip();
    gzipstream.close();
    gzipstream = null;
   }else{
    //如果未开启压缩,则用response的默认输出流刷新缓冲区
    if(bufferCount > 0){
     output.write(buffer, 0, bufferCount);
     bufferCount = 0;
    }
   }
}

/**
* 刷新输出缓冲区
*/
public void flush() throws IOException{
   if(closed){
    throw new IOException("Cannot flush a closed output stream");
   }
   if(gzipstream != null){
    gzipstream.flush();
   }
}

public void write(int b) throws IOException {
  
   if(closed){
    throw new IOException("Cannot write to a closed output stream");
   }
  
   //如果数据超出了缓冲区(启用压缩的临界值),则启用压缩模式
   if(bufferCount >= buffer.length){
    flushToGZip();
   }
   //如果没有超出缓冲区,则将数据写入缓冲区
   buffer[bufferCount++] = (byte)b;
  
}

public void write(byte[] b,int off,int len) throws IOException{
   if(closed){
    throw new IOException("Cannot write to a closed output stream");
   }
  
   if(len == 0){
    return;
   }
   //如果缓冲区能容纳这些数据则写入缓冲区
   if(len <= buffer.length - bufferCount){
    System.arraycopy(b, off, buffer, bufferCount, len);
    bufferCount += len;
    return;
   }
  
   //如果缓冲区剩余空间不住足,则开启压缩流对象
   flushToGZip();
  
   //如果清空后的缓冲区能够容纳传送过来的数据,则将数据写入缓冲区
   if(len <= buffer.length - bufferCount){
    System.arraycopy(b, off, buffer, bufferCount, len);
    bufferCount += len;
    return;
   }
  
   //如果缓冲区不能容纳传送进来的数据,则直接将数据写入压缩流对象
   writeToGZip(b, off, len);
}


//刷新压缩流对象的缓冲区
public void flushToGZip() throws IOException{
   if(bufferCount > 0){
    writeToGZip(buffer, 0, bufferCount);
    bufferCount = 0;
   }
}

public void writeToGZip(byte b[],int off,int len)throws IOException{
  
   //如果压缩流对象为空,这里初始化它
   if(gzipstream == null){
    response.addHeader("Content-Encoding", "gzip");
    gzipstream = new GZIPOutputStream(output);
   }
  
   //将数据听过压缩流对象输出到response的输出流
   gzipstream.write(b,off,len);
}



public boolean closed(){
   return closed;
}

}



package compressionFilters;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class CompressionServletResponseWrapper extends
   HttpServletResponseWrapper {

/**
* 原始的response对象
*/
protected HttpServletResponse origResponse = null;

protected static final String info = "CompressionServletResponseWrapper";

/**
* response对象的输出流
*/
protected ServletOutputStream stream = null;

/**
* response
*/
protected PrintWriter writer = null;

protected int threshold = 0;

protected String contentType = null;

public CompressionServletResponseWrapper(HttpServletResponse response) {
   super(response);
   origResponse = response;
}

/**
* 设置实体类型
*/
public void setContentType(String contentType){
   this.contentType = contentType;
   origResponse.setContentType(contentType);  
}

/**
* 设置启用压缩的临界值
* @param threshold 临界值
*/
public void setCompressionThreshold(int threshold){
   this.threshold = threshold;
}


public ServletOutputStream createOutputStream() throws IOException{
   CompressionResponseStream stream = new CompressionResponseStream(origResponse);
   stream.setBuffer(threshold);
   return stream;
}

//关闭输出对象
public void finishResponse(){
   try {
    if(writer != null){
     writer.close();
    }else{
     if(stream != null){
      stream.close();
     }
    }
   } catch (IOException e) {

   }
}

public void flushBuffer() throws IOException{
   ((CompressionResponseStream)stream).flush();
}

public ServletOutputStream getOutputStream() throws IOException{
  
   //如果字符流打开,则抛出异常
   if(writer != null)
    throw new IllegalStateException("getWriter() has already been called for this response");
  
   if(stream == null) stream = createOutputStream();
   return stream;
}

public PrintWriter getWriter() throws IOException{
   if(writer != null){
    return (writer);
   }
   if(stream != null)
    throw new IllegalStateException("getOutputStream() has already been called for this response");
  
   stream = createOutputStream();
   String charEnc = origResponse.getCharacterEncoding();
   if(charEnc != null){
    writer = new PrintWriter(new OutputStreamWriter(stream,charEnc));
   }else{
    writer = new PrintWriter(stream);
   }
  
   return writer;
}


private static String getCharsetFromContentType(String type){
   if(type == null){
    return null;
   }
  
   int semi = type.indexOf(":");
   if(semi == -1){
    return null;
   }
  
   String afterSemi = type.substring(semi + 1);
   int charsetLocation = afterSemi.indexOf("charset=");
   if(charsetLocation == -1){
    return null;
   }else{
    String afterCharset = afterSemi.substring(charsetLocation + 8);
    String encoding = afterCharset.trim();
    return encoding;
   }
}
}



reference:
1.http://onjava.com/pub/a/onjava/2003/11/19/filters.html
2.java filter 过滤机制详解 http://hi.baidu.com/linfengtingyu1/blog/item/e14a1af20de0505b352accda.html
3.java.servlet.Filter的应用http://yuhaining.spaces.live.com/Blog/cns!5BBD70DF0F6F839C!307.entry
4.使用filter机制来GZIP压缩网页http://www.javamilk.cn/article/notes/624.htm
  • 大小: 17.5 KB
分享到:
评论
1 楼 wangxiangliao 2013-10-09  
private static boolean isGZipEncoding(HttpServletRequest request){  
39.    boolean flag=false;  
40.    String encoding=request.getHeader("Accept-Encoding");  
41.    if(encoding.indexOf("gzip")!=-1){  
42.      flag=true;  
43.    }  
44.    return flag;  
45.  }  



上面的encoding 没有判断是否为Null ,会抛异常。
最近项目的百度统计代码无法验证,弄了好久,百度的HTTP请求中Accept-Encoding没有设置,获取为null 作死的无法验证,到处找原因。才发现代码中的前任从这里copy的代码。。。。

相关推荐

    web容器文件压缩 tk-filter tk-filter js,jsp,css,文件压缩包含源代码

    5. 将压缩后的数据写入响应流,发送到客户端。 `tk-filter` 包含源代码这一特点意味着用户可以深入理解其工作方式,根据自身项目的需求进行定制,例如调整压缩级别、添加新的文件类型支持或者优化性能。源代码的...

    JSP-Filter的简单练习

    4. **性能优化**: 如GZIP压缩、缓存控制等。 5. **字符集转换**: 自动将请求和响应的字符集转换为服务器支持的格式。 **五、Filter的级联与多Filter处理** 在实际应用中,可能需要多个Filter协同工作。通过`...

    jsp,servlet,filter温故知新

    - **Filter**:在请求和响应之间添加额外的处理逻辑,如登录检查、GZIP压缩、字符编码转换等。 结合这三个技术,开发者可以构建出高效、可维护的Java Web应用。理解它们的工作原理和协同方式,对于提升Web开发技能...

    tomcat GZIP源码

    在Tomcat中,GZIP压缩通常通过一个过滤器(Filter)实现,该过滤器会在HTTP响应发送到客户端之前对内容进行压缩。 描述中的“TKGZIP”可能是用户提到的一个特定的GZIP实现,与Tomcat默认的GZIP处理方式相比,它可能...

    (四)Jsp filter的简单使用

    4. **性能优化**:例如,使用GZIP Filter对响应内容进行压缩,减少网络传输量。 在实际开发中,Filter可以极大地提高应用的灵活性和可维护性,通过合理的Filter设计,可以解耦业务逻辑,使代码结构更加清晰。 以上...

    通过filter实现对输出内容的压缩处理

    4. **压缩响应**:在doFilter方法中,将原始的响应输出流替换为GZIPOutputStream,然后调用Chain.doFilter()传递请求到下一个Filter或目标资源。 5. **释放资源**:在doFilter方法结束时,记得关闭GZIPOutputStream...

    使用filter拦截servlet和jsp页面的内容,进行过滤后输出

    - **性能优化**:如GZIP压缩,减少网络传输的数据量。 - **日志记录**:记录请求和响应的信息,便于调试和监控。 - **缓存控制**:控制静态资源的缓存策略,提高页面加载速度。 5. **使用工具**: 在实际开发中...

    Java--数据的压缩[借鉴].pdf

    `GZIPOutputStream`是GZIP压缩的标准输出流,它接受一个已经存在的输出流作为参数,这里是`destByte`。 5. 调用`zip.write(src)`将原始数据写入压缩流。 6. 关闭`zip`以完成压缩过程,释放资源。 7. 获取压缩后的...

    Java-filter测试程序

    例如,我们可以通过Filter实现权限控制、日志记录、数据转换、GZIP压缩等多种功能。以下是对Filter生命周期和核心方法的详细解释: 1. **生命周期**:Filter的生命周期由容器(如Tomcat)管理,包括初始化、过滤和...

    jsp中的过滤器(含例子)

    除了字符编码,过滤器还可以用于其他场景,比如登录检查、权限控制、GZIP压缩等。通过组合多个过滤器,我们可以构建出强大的中间件层,提高Web应用程序的灵活性和可维护性。 总的来说,`JSP`中的过滤器是一个强大的...

    jsp过滤器的使用(含一个project实例说明)

    - **GZIP压缩**:对响应内容进行压缩,减少网络传输的数据量。 总结,JSP过滤器是Java Web开发中的重要工具,它允许我们在请求到达目标资源之前进行干预,实现各种定制化功能。通过实际项目练习,我们可以更好地...

    Java Filter相关资料

    这个技术被广泛用于实现各种功能,比如权限控制、日志记录、数据过滤、GZIP压缩等。本资料包可能包含了关于Java Filter的详细使用方法和生命周期管理的文档或示例代码。 1. **Filter的基本概念** - Java Filter是...

    java filter 执行过程例子

    通过巧妙地使用Filter,我们可以实现如登录验证、GZIP压缩、性能监控、安全控制等多种功能,提高应用的可维护性和扩展性。在实际项目中,经常可以看到Filter与其他Java Web技术(如Servlet、JSP、Spring MVC)协同...

    用 Filter 作为控制器的 MVC

    通过实现javax.servlet.Filter接口,我们可以定义过滤规则,比如登录检查、GZIP压缩、字符编码转换等。 在Struts2中,Filter可以作为应用程序的入口点,负责拦截所有请求,并根据配置决定是否转发到Struts2的Action...

    Filter在MyEclipse中的创建方法

    在Java Web开发中,Filter(过滤...Filter在Web开发中的应用广泛,它们可以用来实现权限控制、字符编码转换、日志记录、GZIP压缩等多种功能。熟练掌握Filter的创建和使用,能够提升你的Web应用程序的灵活性和可维护性。

    jsp-api.jar和servlet-api依赖包

    6. **过滤器(Filter)**:允许在请求到达Servlet之前对其进行拦截和处理,如GZIP压缩、字符编码转换等。 7. **监听器(Listener)**:监听特定事件,如会话创建、销毁、上下文初始化等,可以进行相应的操作。 ### ...

    jsp+servlet模板

    4. **Filter**:过滤器用于在请求处理前后执行特定的操作,如登录验证、GZIP压缩等。 5. **Listener**:监听器可以监听Web应用中特定事件,如会话创建、销毁等,以便进行相应处理。 总之,“jsp+servlet模板”为Web...

    Filter过滤

    4. GZIP压缩:提高传输效率,通过检测请求头并启用GZIP压缩。 五、Filter链与执行顺序 当一个请求到达Web应用时,所有匹配的Filter会按照它们在`&lt;filter-mapping&gt;`中的顺序依次执行。`doFilter()`方法会传递请求和...

    JavaWeb开发技术-Filter链.pptx

    在JavaWeb开发中,...在实际开发中,Filter链的应用场景非常广泛,包括但不限于:登录验证、数据加密解密、GZIP压缩、字符编码转换、日志记录等。熟练掌握Filter链的使用,能有效提高JavaWeb应用的功能性和安全性。

    简单使用Filter模拟Servlet中的过滤器

    在实际项目中,Filter的应用非常广泛,例如实现登录验证、字符集编码转换、GZIP压缩、安全控制等。通过理解和熟练使用Filter,开发者可以更好地控制和优化Web应用程序的行为。 由于提供的压缩包文件名为`webfilter`...

Global site tag (gtag.js) - Google Analytics