gzip和介绍和回想方式,可以参考我的这篇博客 gzip的介绍以及web服务器对文件压缩的支持。本文介绍如何借助j2ee的过滤器Filter自己实现gzip对网页文件的压缩。
将该过滤器配置在web.xml中的第一个,实现对*.js文件拦截
package net.aty;
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
{
@Override
public void destroy()
{
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException
{
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String ac = httpRequest.getHeader("accept-encoding");
// 检查浏览器是否支持gzip格式
if (ac != null && ac.contains("gzip"))
{
httpResponse.setHeader("Content-Encoding", "gzip");
//对原始的response进行封装
GZIPResponseWrapper wrappedResponse = new GZIPResponseWrapper(httpResponse);
chain.doFilter(httpRequest, wrappedResponse);
// 完成gzip压缩,将压缩后的数据写入web服务器创建的原始输出流中
// 一定要手动关闭wrappedResponse,否则httpResponse中数据是空,服务器不能正确的将数据传给浏览器
wrappedResponse.finishCompress();
}
else
{
chain.doFilter(request, httpResponse);
}
}
@Override
public void init(FilterConfig config) throws ServletException
{
}
}
package net.aty;
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 GZIPResponseWrapper extends HttpServletResponseWrapper
{
private HttpServletResponse origResponse = null;
private GZIPResponseStream stream = null;
private PrintWriter writer = null;
public GZIPResponseWrapper(HttpServletResponse response) throws IOException
{
super(response);
this.origResponse = response;
}
public ServletOutputStream getOutputStream() throws IOException
{
if (this.writer != null)
{
throw new IllegalStateException("getWriter() has already been called!");
}
if (this.stream == null)
{
this.stream = this.createOutputStream();
}
return this.stream;
}
public PrintWriter getWriter() throws IOException
{
if (this.writer != null)
{
return this.writer;
}
if (this.stream != null)
{
throw new IllegalStateException("getOutputStream() has already been called!");
}
this.stream = this.createOutputStream();
this.writer = new PrintWriter(new OutputStreamWriter(this.stream, "UTF-8"));
return this.writer;
}
public void finishCompress() throws IOException
{
if (this.writer != null)
{
this.writer.close();
}
else if (this.stream != null)
{
this.stream.close();
}
}
public long getContentBytes()
{
return stream.getWriteBytes();
}
private GZIPResponseStream createOutputStream() throws IOException
{
return new GZIPResponseStream(origResponse.getOutputStream());
}
}
GZIPResponseStream 实现对GZIP的封装
package net.aty;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletOutputStream;
// 封装web服务器原始的httpResponse.getOutputStream().服务器会将原本应该写入httpResponse.getOutputStream()
// 中数据,写入到GZIPOutputStream实现数据压缩
public class GZIPResponseStream extends ServletOutputStream
{
private long writeBytes = 0;
private GZIPOutputStream gzipStream = null;
// outputStream是输出目的地。如果在构建gzipStream之前,已经有数据写入outputStream,那么这些数据不会压缩
public GZIPResponseStream(ServletOutputStream outputStream) throws IOException
{
this.gzipStream = new GZIPOutputStream(outputStream);
}
@Override
public void write(int asciiValue) throws IOException
{
this.gzipStream.write((byte) asciiValue);
writeBytes++;
}
@Override
public void write(byte bytesArray[]) throws IOException
{
this.write(bytesArray, 0, bytesArray.length);
}
@Override
public void write(byte bytesArray[], int offset, int length) throws IOException
{
this.gzipStream.write(bytesArray, offset, length);
writeBytes += length;
}
@Override
public void flush() throws IOException
{
this.gzipStream.flush();
}
@Override
public void close() throws IOException
{
this.gzipStream.finish();
this.gzipStream.flush();
this.gzipStream.close();
}
public long getWriteBytes()
{
return writeBytes;
}
}
自己通过调试,得出以下几个结论
1、response对象由web服务器创建,当第一个filter拿到response的时候,内容是空的,这个时候还没有谁向response响应流中写入数据。
当走完最后个filter或servlet的时候,服务器会将静态的html或者动态的jsp写入的reponse的响应流中。
2、GZIPFilter应该放在web.xml中作为第一个过滤器,这样才可以保证所有写入到response中的数据都经过gzip压缩。
本文讲述了如何利用j2ee的Filter来实现gzip对网页文件的压缩。配置过滤器在web.xml的第一个位置,拦截*.js文件,确保所有数据在写入response响应流前经过gzip压缩。
43万+

被折叠的 条评论
为什么被折叠?



