GZIP压缩过滤器
功能:对于web服务器响应给浏览器的数据进行gzip压缩返回,以减少数据量,提高服务器响应速度;
实现说明:要对response对象的输出数据进行gzip压缩,首先得拿到后面servlet(controller)进行业务处理后往response对象里写入的数据,要想实现截获输出数据,可以通过重写response对象来实现,具体方法是修改response对象内部的输出流,使该流写出数据时写出到给定的字节数组缓冲流当中,并在重写后的response对象内部提供一个获取该字节数组缓冲流的方法,这样就可以截获响应数据;拿到响应数据之后就可以对截获的响应数据通过Gzip输出流进行压缩输出即可;因为响应数据是gzip压缩格式,不是普通的文本格式,所以需要通过response对象(响应头)告知浏览器响应的数据类型,这样浏览器才可以正常解析。
代码示例:
package filters;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.*;
import java.util.zip.GZIPOutputStream;
/**
* 压缩过滤器
*
* 功能:对于返回给客户端的数据进行gzip压缩,提高响应速度
* 实现说明:
* 要对response对象的输出数据进行gzip压缩,首先得拿到后面servlet(controller)进行业务处理后往response对象里写入的数据
* 可以通过重写response对象,修改该对象内部的输出流,使该流写出数据时写出到给定的字节数组缓冲流当中,
* 并在重写后的response对象内部提供一个获取该字节数组缓冲流的方法,这样就可以截获响应数据
* 然后就可以对截获的响应数据通过Gzip输出流进行压缩输出即可;
* 因为响应数据是gzip压缩格式,不是普通的文本格式所以需要通过response对象(响应头)告知浏览器响应的数据类型
*/
@WebFilter(filterName = "GzipFilter", urlPatterns = {"/*"})
public class GzipFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("==========gzip filter");
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
MyHttpServletResponse myresponse = new MyHttpServletResponse(response);
//pass the customized response object to controller to capture the output data
chain.doFilter(request, myresponse);
//get captured data
byte[] data = myresponse.getOutputData();
System.out.println("============截获到数据:" + data.length + " bytes");
//get gzip data
ByteArrayOutputStream gzipBuffer = new ByteArrayOutputStream();
GZIPOutputStream gzipOut = new GZIPOutputStream(gzipBuffer);
gzipOut.write(data);
gzipOut.flush();
gzipOut.close();
byte[] gzipData = gzipBuffer.toByteArray();
System.out.println("==========压缩后数据:" + gzipData.length + " bytes");
//set response header and output
response.setHeader("Content-Encoding", "gzip");
response.getOutputStream().write(gzipData);
}
public void init(FilterConfig config) throws ServletException {
}
private static class MyHttpServletResponse extends HttpServletResponseWrapper {
/**
* 字节数组缓冲流,用来保存截获到的输出数据
*/
private ByteArrayOutputStream buffer;
/**
* 重新定义servlet输出流,改变输出目的地
* 将响应内容输出到给定的字节数组缓冲流中
*/
private MyServletOutputStream servletOutputStream;
/**
* 同上
*/
private PrintWriter writer;
public MyHttpServletResponse(HttpServletResponse response) {
super(response);
//original HttpServletResponse object
buffer = new ByteArrayOutputStream();
servletOutputStream = new MyServletOutputStream(buffer);
try {
writer = new PrintWriter(new OutputStreamWriter(buffer, response.getCharacterEncoding()), true);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return servletOutputStream;
}
@Override
public PrintWriter getWriter() throws IOException {
return writer;
}
@Override
public void flushBuffer() throws IOException {
if (servletOutputStream != null) {
servletOutputStream.flush();
}
if (writer != null) {
writer.flush();
}
}
/**
* 向外部提供一个获取截获数据的方法
* @return 从response输出流中截获的响应数据
*/
public byte[] getOutputData() throws IOException {
flushBuffer();
return buffer.toByteArray();
}
}
private static class MyServletOutputStream extends ServletOutputStream {
/**
* 字节数组缓冲流,用来保存截获到的输出数据
*/
private ByteArrayOutputStream buffer;
public MyServletOutputStream(ByteArrayOutputStream buffer) {
this.buffer = buffer;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setWriteListener(WriteListener listener) {
}
/**
* 重写输出流相关的方法
* 将输出数据写出到给定的ByteArrayOutputStream缓冲流中保存起来
* @param b 输出的数据
* @throws IOException
*/
@Override
public void write(int b) throws IOException {
buffer.write(b);
}
}
}