zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    使用了Theme但是没有效果问题
    4.0 流量控制preference
    android sdk国内目录http://mirrors.neusoft.edu.cn/android/repository/
    xmpp push篇一 广播消息
    cursorfilter
    android 特效UI实现
    Android四大组件一----Activity
    net user命令
    sql2005如何附加数据库
    sql2005中如何启用SA账号
  • 原文地址:https://www.cnblogs.com/zfswff/p/3507994.html
Copyright © 2011-2022 走看看