本文来源于:
http://www.cnblogs.com/hemingwang0902/archive/2012/01/12/compression-filter.html
同类内容有:
设置站点黑名单的过滤器(BannedAccessFilter)
将响应数据进行压缩处理的过滤器(CompressionFilter)
替换禁用语(指定关键字)的过滤器(StopWordsFilter)
功能描述
如果浏览器支持 gzip 压缩格式的数据,则将响应的数据使用 gzip 压缩后再输出。
使用方法
在 java web 项目的 web.xml 文件中添加如下代码。
<!--压缩过滤器的配置 开始 -->
<filter>
<filter-name>CompressionFilter</filter-name>
<filter-class>com.hmw.filter.CompressionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CompressionFilter</filter-name>
<servlet-name>/LongServlet</servlet-name>
</filter-mapping>
<!--压缩过滤器的配置 结束 -->
过滤器源码
CompressionFilter.java
package com.hmw.filter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.zip.GZIPOutputStream;
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;
/**
* 压缩过滤器 <br>
* 如果浏览器支持 gzip 压缩格式的数据,则将响应的数据使用 gzip 压缩后再输出。
*
* @author <a href="mailto:hemingwang0902@126.com">何明旺</a>
*/
public class CompressionFilter implements Filter {
@Override
public void init(FilterConfig config) throws ServletException {
}
/**
* 如果浏览器不支持 gzip 压缩,则不做直接放行(不做压缩处理)<br>
* 反之,将HTTP响应头的编码设置为 <code>gzip</code>,然后将响应数据使用 gzip 进行压缩处理。
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (!isGzipSupported(req)) { // Invoke resource normally.
chain.doFilter(req, res);
return;
}
// 将响应头信息中的内容编码设置为 gzip
res.setHeader("Content-Encoding", "gzip");
// 调用资源,使用 CharArrayWrapper 包装输出
CharArrayWrapper responseWrapper = new CharArrayWrapper(res);
chain.doFilter(req, responseWrapper);
// 取得存放输出数据的 char 型数组
char[] responseChars = responseWrapper.toCharArray();
// 将响应数据压缩后存入一个 byte 型的数组,然后输出到
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
GZIPOutputStream zipOut = new GZIPOutputStream(byteStream);
OutputStreamWriter tempOut = new OutputStreamWriter(zipOut);
// 将原来的响应数据压缩后写入二字节输出流
tempOut.write(responseChars);
// 关闭输出流
tempOut.close();
// 更新响应头信息中 Content-Length 的值。
res.setContentLength(byteStream.size());
// 将压缩后的数据发送至客户端
OutputStream realOut = res.getOutputStream();
byteStream.writeTo(realOut);
}
@Override
public void destroy() {
}
/**
* 检测浏览器是否支持 Gzip 压缩
*
* @param req HTTP 请求对象
* @return 如果浏览器支持 Gzip 压缩,则返回 true,反之,则返回 false
*/
private boolean isGzipSupported(HttpServletRequest req) {
String browserEncodings = req.getHeader("Accept-Encoding");
return ((browserEncodings != null) && (browserEncodings.indexOf("gzip") != -1));
}
}
CharArrayWrapper.java
package com.hmw.filter;
import java.io.CharArrayWriter;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
/**
* A response wrapper that takes everything the client would normally output and
* saves it in one big character array.
*/
public class CharArrayWrapper extends HttpServletResponseWrapper {
private CharArrayWriter charWriter;
/**
* Initializes wrapper.
* <P>
* First, this constructor calls the parent constructor. That call is
* crucial so that the response is stored and thus setHeader, *setStatus,
* addCookie, and so forth work normally.
* <P>
* Second, this constructor creates a CharArrayWriter that will be used to
* accumulate the response.
*/
public CharArrayWrapper(HttpServletResponse response) {
super(response);
charWriter = new CharArrayWriter();
}
/**
* When servlets or JSP pages ask for the Writer, don't give them the real
* one. Instead, give them a version that writes into the character array.
* The filter needs to send the contents of the array to the client (perhaps
* after modifying it).
*/
@Override
public PrintWriter getWriter() {
return new PrintWriter(charWriter);
}
/**
* Get a String representation of the entire buffer.
* <P>
* Be sure <B>not</B> to call this method multiple times on the same
* wrapper. The API for CharArrayWriter does not guarantee that it
* "remembers" the previous value, so the call is likely to make a new
* String every time.
*/
@Override
public String toString() {
return charWriter.toString();
}
/** Get the underlying character array. */
public char[] toCharArray() {
return charWriter.toCharArray();
}
}