JSP Filter,GZIP压缩响应流

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

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

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

Java代码   收藏代码
  1. import java.io.IOException;  
  2. import java.io.OutputStream;  
  3. import java.util.zip.GZIPOutputStream;  
  4. import javax.servlet.ServletOutputStream;  
  5.   
  6. public class GZipStream extends ServletOutputStream {  
  7.   
  8.   private GZIPOutputStream zipStream;  
  9.   
  10.   public GZipStream(OutputStream out) throws IOException {  
  11.     zipStream = new GZIPOutputStream(out);  
  12.   }  
  13.   
  14.   @Override  
  15.   public void flush() throws IOException {  
  16.     zipStream.flush();  
  17.   }  
  18.   
  19.   @Override  
  20.   public void write(byte[] b, int off, int len) throws IOException {  
  21.     zipStream.write(b, off, len);  
  22.   }  
  23.   
  24.   @Override  
  25.   public void write(byte[] b) throws IOException {  
  26.     zipStream.write(b);  
  27.   }  
  28.   
  29.   @Override  
  30.   public void write(int arg0) throws IOException {  
  31.     zipStream.write(arg0);  
  32.   }  
  33.   
  34.   public void finish() throws IOException {  
  35.     zipStream.finish();  
  36.   }  
  37.   
  38.   public void close() throws IOException {  
  39.     zipStream.close();  
  40.   }  
  41.   
  42. }   


GZipResponse.java 

Java代码   收藏代码
  1. import java.io.IOException;  
  2. import java.io.OutputStreamWriter;  
  3. import java.io.PrintWriter;  
  4.   
  5. import javax.servlet.ServletOutputStream;  
  6. import javax.servlet.http.HttpServletResponse;  
  7. import javax.servlet.http.HttpServletResponseWrapper;  
  8.   
  9. public class GZipResponse extends HttpServletResponseWrapper {  
  10.   private GZipStream stream;  
  11.   private PrintWriter writer;  
  12.   public GZipResponse(HttpServletResponse response) throws IOException{  
  13.     super(response);  
  14.     stream=new GZipStream(response.getOutputStream());  
  15.   }  
  16.     
  17.   @Override  
  18.   public ServletOutputStream getOutputStream() throws IOException {  
  19.     return stream;  
  20.   }  
  21.   
  22.   @Override  
  23.   public PrintWriter getWriter() throws IOException {  
  24.     if (writer == null) {  
  25.       writer = new PrintWriter(new OutputStreamWriter(  
  26.           getOutputStream(), getCharacterEncoding()));  
  27.     }  
  28.     return writer;  
  29.   }  
  30.   
  31.   public void flush() throws IOException {  
  32.     if (writer != null) {  
  33.       writer.flush();  
  34.     }  
  35.     stream.finish();  
  36.   }  
  37.   
  38. }   


GZipFilter.java 


Java代码   收藏代码
  1. import java.io.IOException;  
  2. import javax.servlet.Filter;  
  3. import javax.servlet.FilterChain;  
  4. import javax.servlet.FilterConfig;  
  5. import javax.servlet.ServletException;  
  6. import javax.servlet.ServletRequest;  
  7. import javax.servlet.ServletResponse;  
  8. import javax.servlet.http.HttpServletRequest;  
  9. import javax.servlet.http.HttpServletResponse;  
  10.   
  11. public class GZipFilter implements Filter {  
  12.   
  13.   public void destroy() {  
  14.   }  
  15.   
  16.   public void init(FilterConfig fConfig) throws ServletException {  
  17.   }  
  18.   
  19.   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)   
  20.   throws IOException, ServletException {  
  21.     HttpServletRequest req=(HttpServletRequest)request;  
  22.     HttpServletResponse res=(HttpServletResponse)response;  
  23.     if(isGZipEncoding(req)){  
  24.       GZipResponse zipResponse=new GZipResponse(res);  
  25.       res.setHeader("Content-Encoding""gzip");  
  26.       chain.doFilter(request, zipResponse);  
  27.       zipResponse.flush();  
  28.     } else {  
  29.       chain.doFilter(request, response);  
  30.     }  
  31.   }  
  32.     
  33.   /** 
  34.    * 判断浏览器是否支持GZIP 
  35.    * @param request 
  36.    * @return 
  37.    */  
  38.   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.   }  
  46.   
  47. }   

web.xml配置 
Java代码   收藏代码
  1. <filter>  
  2.    <description>  
  3.    </description>  
  4.    <display-name>GZipFilter</display-name>  
  5.    <filter-name>GZipFilter</filter-name>  
  6.    <filter-class>GZipFilter</filter-class>  
  7. </filter>  
  8. <filter-mapping>  
  9.    <filter-name>GZipFilter</filter-name>  
  10.    <url-pattern>/*</url-pattern>  
  11. </filter-mapping>  


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

tomcat自带源码剖析: 
url: http://hi.baidu.com/springfieldx/blog/item/9faa88dfd5760414495403b6.html  
在响应请求的时候对response进行封装,替换他的输出流为 GZipOutputStream 压缩输出流  
Java代码   收藏代码
  1. package compressionFilters;  
  2. import java.io.IOException;  
  3. import java.util.zip.GZIPOutputStream;  
  4.   
  5. import javax.servlet.ServletOutputStream;  
  6. import javax.servlet.http.HttpServletResponse;  
  7.   
  8.   
  9. public class CompressionResponseStream extends ServletOutputStream {  
  10.   
  11. //是否启用压缩的临界值  
  12. protected int compressThreshold = 0;  
  13.   
  14. //临时容纳写入的数据缓冲区  
  15. protected byte[] buffer = null;  
  16.   
  17. //缓冲区实际写入的数据量  
  18. protected int bufferCount = 0;  
  19.   
  20. protected GZIPOutputStream gzipstream = null;  
  21.   
  22. //当前流对象是否处于关闭状态  
  23. protected boolean closed = false;  
  24.   
  25. protected int length = -1;  
  26.   
  27. //用于返回数据的 Response对象  
  28. protected HttpServletResponse response = null;  
  29.   
  30. protected ServletOutputStream output = null;  
  31.   
  32.   
  33.   
  34. public CompressionResponseStream(HttpServletResponse response) throws IOException{  
  35.    super();  
  36.    closed = false;  
  37.    this.response = response;  
  38.    this.output = response.getOutputStream();  
  39. }  
  40.   
  41. //设置启用压缩的临界值,并初始化输出缓冲区  
  42. public void setBuffer(int threshold){  
  43.    compressThreshold = threshold;  
  44.    buffer = new byte[threshold];  
  45. }  
  46.   
  47. /** 
  48. * 关闭流对象 
  49. */  
  50. public void close() throws IOException{  
  51.    if(closed){  
  52.     throw new IOException("This output stream has already been closed");  
  53.    }  
  54.     
  55.    //如果当前启用的是压缩流,用压缩流刷新缓冲区  
  56.    if(gzipstream != null){  
  57.     flushToGZip();  
  58.     gzipstream.close();  
  59.     gzipstream = null;  
  60.    }else{  
  61.     //如果未开启压缩,则用response的默认输出流刷新缓冲区  
  62.     if(bufferCount > 0){  
  63.      output.write(buffer, 0, bufferCount);  
  64.      bufferCount = 0;  
  65.     }  
  66.    }  
  67. }  
  68.   
  69. /** 
  70. * 刷新输出缓冲区 
  71. */  
  72. public void flush() throws IOException{  
  73.    if(closed){  
  74.     throw new IOException("Cannot flush a closed output stream");  
  75.    }  
  76.    if(gzipstream != null){  
  77.     gzipstream.flush();  
  78.    }  
  79. }  
  80.   
  81. public void write(int b) throws IOException {  
  82.     
  83.    if(closed){  
  84.     throw new IOException("Cannot write to a closed output stream");  
  85.    }  
  86.     
  87.    //如果数据超出了缓冲区(启用压缩的临界值),则启用压缩模式  
  88.    if(bufferCount >= buffer.length){  
  89.     flushToGZip();  
  90.    }  
  91.    //如果没有超出缓冲区,则将数据写入缓冲区  
  92.    buffer[bufferCount++] = (byte)b;  
  93.     
  94. }  
  95.   
  96. public void write(byte[] b,int off,int len) throws IOException{  
  97.    if(closed){  
  98.     throw new IOException("Cannot write to a closed output stream");  
  99.    }  
  100.     
  101.    if(len == 0){  
  102.     return;  
  103.    }  
  104.    //如果缓冲区能容纳这些数据则写入缓冲区  
  105.    if(len <= buffer.length - bufferCount){  
  106.     System.arraycopy(b, off, buffer, bufferCount, len);  
  107.     bufferCount += len;  
  108.     return;  
  109.    }  
  110.     
  111.    //如果缓冲区剩余空间不住足,则开启压缩流对象  
  112.    flushToGZip();  
  113.     
  114.    //如果清空后的缓冲区能够容纳传送过来的数据,则将数据写入缓冲区  
  115.    if(len <= buffer.length - bufferCount){  
  116.     System.arraycopy(b, off, buffer, bufferCount, len);  
  117.     bufferCount += len;  
  118.     return;  
  119.    }  
  120.     
  121.    //如果缓冲区不能容纳传送进来的数据,则直接将数据写入压缩流对象  
  122.    writeToGZip(b, off, len);  
  123. }  
  124.   
  125.   
  126. //刷新压缩流对象的缓冲区  
  127. public void flushToGZip() throws IOException{  
  128.    if(bufferCount > 0){  
  129.     writeToGZip(buffer, 0, bufferCount);  
  130.     bufferCount = 0;  
  131.    }  
  132. }  
  133.   
  134. public void writeToGZip(byte b[],int off,int len)throws IOException{  
  135.     
  136.    //如果压缩流对象为空,这里初始化它  
  137.    if(gzipstream == null){  
  138.     response.addHeader("Content-Encoding""gzip");  
  139.     gzipstream = new GZIPOutputStream(output);  
  140.    }  
  141.     
  142.    //将数据听过压缩流对象输出到response的输出流  
  143.    gzipstream.write(b,off,len);  
  144. }  
  145.   
  146.   
  147.   
  148. public boolean closed(){  
  149.    return closed;  
  150. }  
  151.   
  152. }  
  153.   
  154.   
  155.   
  156. package compressionFilters;  
  157. import java.io.IOException;  
  158. import java.util.zip.GZIPOutputStream;  
  159.   
  160. import javax.servlet.ServletOutputStream;  
  161. import javax.servlet.http.HttpServletResponse;  
  162.   
  163.   
  164. public class CompressionResponseStream extends ServletOutputStream {  
  165.   
  166. //是否启用压缩的临界值  
  167. protected int compressThreshold = 0;  
  168.   
  169. //临时容纳写入的数据缓冲区  
  170. protected byte[] buffer = null;  
  171.   
  172. //缓冲区实际写入的数据量  
  173. protected int bufferCount = 0;  
  174.   
  175. protected GZIPOutputStream gzipstream = null;  
  176.   
  177. //当前流对象是否处于关闭状态  
  178. protected boolean closed = false;  
  179.   
  180. protected int length = -1;  
  181.   
  182. //用于返回数据的 Response对象  
  183. protected HttpServletResponse response = null;  
  184.   
  185. protected ServletOutputStream output = null;  
  186.   
  187.   
  188.   
  189. public CompressionResponseStream(HttpServletResponse response) throws IOException{  
  190.    super();  
  191.    closed = false;  
  192.    this.response = response;  
  193.    this.output = response.getOutputStream();  
  194. }  
  195.   
  196. //设置启用压缩的临界值,并初始化输出缓冲区  
  197. public void setBuffer(int threshold){  
  198.    compressThreshold = threshold;  
  199.    buffer = new byte[threshold];  
  200. }  
  201.   
  202. /** 
  203. * 关闭流对象 
  204. */  
  205. public void close() throws IOException{  
  206.    if(closed){  
  207.     throw new IOException("This output stream has already been closed");  
  208.    }  
  209.     
  210.    //如果当前启用的是压缩流,用压缩流刷新缓冲区  
  211.    if(gzipstream != null){  
  212.     flushToGZip();  
  213.     gzipstream.close();  
  214.     gzipstream = null;  
  215.    }else{  
  216.     //如果未开启压缩,则用response的默认输出流刷新缓冲区  
  217.     if(bufferCount > 0){  
  218.      output.write(buffer, 0, bufferCount);  
  219.      bufferCount = 0;  
  220.     }  
  221.    }  
  222. }  
  223.   
  224. /** 
  225. * 刷新输出缓冲区 
  226. */  
  227. public void flush() throws IOException{  
  228.    if(closed){  
  229.     throw new IOException("Cannot flush a closed output stream");  
  230.    }  
  231.    if(gzipstream != null){  
  232.     gzipstream.flush();  
  233.    }  
  234. }  
  235.   
  236. public void write(int b) throws IOException {  
  237.     
  238.    if(closed){  
  239.     throw new IOException("Cannot write to a closed output stream");  
  240.    }  
  241.     
  242.    //如果数据超出了缓冲区(启用压缩的临界值),则启用压缩模式  
  243.    if(bufferCount >= buffer.length){  
  244.     flushToGZip();  
  245.    }  
  246.    //如果没有超出缓冲区,则将数据写入缓冲区  
  247.    buffer[bufferCount++] = (byte)b;  
  248.     
  249. }  
  250.   
  251. public void write(byte[] b,int off,int len) throws IOException{  
  252.    if(closed){  
  253.     throw new IOException("Cannot write to a closed output stream");  
  254.    }  
  255.     
  256.    if(len == 0){  
  257.     return;  
  258.    }  
  259.    //如果缓冲区能容纳这些数据则写入缓冲区  
  260.    if(len <= buffer.length - bufferCount){  
  261.     System.arraycopy(b, off, buffer, bufferCount, len);  
  262.     bufferCount += len;  
  263.     return;  
  264.    }  
  265.     
  266.    //如果缓冲区剩余空间不住足,则开启压缩流对象  
  267.    flushToGZip();  
  268.     
  269.    //如果清空后的缓冲区能够容纳传送过来的数据,则将数据写入缓冲区  
  270.    if(len <= buffer.length - bufferCount){  
  271.     System.arraycopy(b, off, buffer, bufferCount, len);  
  272.     bufferCount += len;  
  273.     return;  
  274.    }  
  275.     
  276.    //如果缓冲区不能容纳传送进来的数据,则直接将数据写入压缩流对象  
  277.    writeToGZip(b, off, len);  
  278. }  
  279.   
  280.   
  281. //刷新压缩流对象的缓冲区  
  282. public void flushToGZip() throws IOException{  
  283.    if(bufferCount > 0){  
  284.     writeToGZip(buffer, 0, bufferCount);  
  285.     bufferCount = 0;  
  286.    }  
  287. }  
  288.   
  289. public void writeToGZip(byte b[],int off,int len)throws IOException{  
  290.     
  291.    //如果压缩流对象为空,这里初始化它  
  292.    if(gzipstream == null){  
  293.     response.addHeader("Content-Encoding""gzip");  
  294.     gzipstream = new GZIPOutputStream(output);  
  295.    }  
  296.     
  297.    //将数据听过压缩流对象输出到response的输出流  
  298.    gzipstream.write(b,off,len);  
  299. }  
  300.   
  301.   
  302.   
  303. public boolean closed(){  
  304.    return closed;  
  305. }  
  306.   
  307. }  
  308.   
  309.   
  310.   
  311. package compressionFilters;  
  312.   
  313. import java.io.IOException;  
  314. import java.io.OutputStream;  
  315. import java.io.OutputStreamWriter;  
  316. import java.io.PrintWriter;  
  317.   
  318. import javax.servlet.ServletOutputStream;  
  319. import javax.servlet.http.HttpServletResponse;  
  320. import javax.servlet.http.HttpServletResponseWrapper;  
  321.   
  322. public class CompressionServletResponseWrapper extends  
  323.    HttpServletResponseWrapper {  
  324.   
  325. /** 
  326. * 原始的response对象 
  327. */  
  328. protected HttpServletResponse origResponse = null;  
  329.   
  330. protected static final String info = "CompressionServletResponseWrapper";  
  331.   
  332. /** 
  333. * response对象的输出流 
  334. */  
  335. protected ServletOutputStream stream = null;  
  336.   
  337. /** 
  338. * response 
  339. */  
  340. protected PrintWriter writer = null;  
  341.   
  342. protected int threshold = 0;  
  343.   
  344. protected String contentType = null;  
  345.   
  346. public CompressionServletResponseWrapper(HttpServletResponse response) {  
  347.    super(response);  
  348.    origResponse = response;  
  349. }  
  350.   
  351. /** 
  352. * 设置实体类型 
  353. */  
  354. public void setContentType(String contentType){  
  355.    this.contentType = contentType;  
  356.    origResponse.setContentType(contentType);    
  357. }  
  358.   
  359. /** 
  360. * 设置启用压缩的临界值 
  361. * @param threshold 临界值 
  362. */  
  363. public void setCompressionThreshold(int threshold){  
  364.    this.threshold = threshold;  
  365. }  
  366.   
  367.   
  368. public ServletOutputStream createOutputStream() throws IOException{  
  369.    CompressionResponseStream stream = new CompressionResponseStream(origResponse);  
  370.    stream.setBuffer(threshold);  
  371.    return stream;  
  372. }  
  373.   
  374. //关闭输出对象  
  375. public void finishResponse(){  
  376.    try {  
  377.     if(writer != null){  
  378.      writer.close();  
  379.     }else{  
  380.      if(stream != null){  
  381.       stream.close();  
  382.      }  
  383.     }  
  384.    } catch (IOException e) {  
  385.   
  386.    }  
  387. }  
  388.   
  389. public void flushBuffer() throws IOException{  
  390.    ((CompressionResponseStream)stream).flush();  
  391. }  
  392.   
  393. public ServletOutputStream getOutputStream() throws IOException{  
  394.     
  395.    //如果字符流打开,则抛出异常  
  396.    if(writer != null)  
  397.     throw new IllegalStateException("getWriter() has already been called for this response");  
  398.     
  399.    if(stream == null) stream = createOutputStream();  
  400.    return stream;  
  401. }  
  402.   
  403. public PrintWriter getWriter() throws IOException{  
  404.    if(writer != null){  
  405.     return (writer);  
  406.    }  
  407.    if(stream != null)  
  408.     throw new IllegalStateException("getOutputStream() has already been called for this response");  
  409.     
  410.    stream = createOutputStream();  
  411.    String charEnc = origResponse.getCharacterEncoding();  
  412.    if(charEnc != null){  
  413.     writer = new PrintWriter(new OutputStreamWriter(stream,charEnc));  
  414.    }else{  
  415.     writer = new PrintWriter(stream);  
  416.    }  
  417.     
  418.    return writer;  
  419. }  
  420.   
  421.   
  422. private static String getCharsetFromContentType(String type){  
  423.    if(type == null){  
  424.     return null;  
  425.    }  
  426.     
  427.    int semi = type.indexOf(":");  
  428.    if(semi == -1){  
  429.     return null;  
  430.    }  
  431.     
  432.    String afterSemi = type.substring(semi + 1);  
  433.    int charsetLocation = afterSemi.indexOf("charset=");  
  434.    if(charsetLocation == -1){  
  435.     return null;  
  436.    }else{  
  437.     String afterCharset = afterSemi.substring(charsetLocation + 8);  
  438.     String encoding = afterCharset.trim();  
  439.     return encoding;  
  440.    }  
  441. }  
  442. }  


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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值