在向浏览器发送响应内容时,可以对响应内容进行压缩,将压缩后的内容发送到浏览器,同时通知浏览器发过来的内容是使用何种算法进行压缩的,浏览器再显示时,将以此中方法进行解码。这样可以节省传输带宽,加快响应速度。这里可以利用Filter来实现全站的响应内容压缩问题。但是HttpServletResponse对象本身不具有压缩响应内容的功能,因此可以对其进行功能增强。
HttpServletResponseWrapper是对HttpServletResonse的默认包装类,MyCompressResponse是继承了HttpServletResponseWrapper类的包装类;由于response向浏览器上输出显示内容有两个方法,一个是同通过getOutputStream获取流对象,调用其write方法将数据写入outputStream流中。另一种方法是通过获取getWriter来获取一个PrintWriter的对象,通过其write方法想浏览器写入一个字符串,一个是基于bit流的,一个是基于字符流的。但是response本身这两中方法都是直接向浏览器输出响应内容,本没有对其进行压缩,因此需要对其进行增强。其思想是增强后的方法,将会先把响应内容输出到一个缓存内,对缓存内的内容进行压缩处理,能够后将压缩后的内容输出到浏览器中,同时通知浏览器,接受到的内容是通过什么算法压缩的及内容的大小,这时,浏览器将会根据此来显示响应内容。下面是增强的MyCompressResponse,具体如下:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
import javax.servlet.ServletResponseWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class MyCompressResponse extends HttpServletResponseWrapper {
private HttpServletResponse response; //接受一个response对象,将对其进行增强
private ByteArrayOutputStream bout = new ByteArrayOutputStream(); //缓存流,所有响应内容将会被输出到此
private PrintWriter pw;
public MyCompressResponse(HttpServletResponse response) {
super(response);
// TODO Auto-generated constructor stub
this.response = response;
}
/* (non-Javadoc)
* @see javax.servlet.ServletResponseWrapper#getOutputStream()
*/
@Override
public ServletOutputStream getOutputStream() throws IOException {
// TODO Auto-generated method stub
return new MyOutputStream(bout); //重写getOutputStream方法
}
@Override
public PrintWriter getWriter() throws IOException {
// TODO Auto-generated method stub
pw = new MyPrintWriter(bout, super.getCharacterEncoding()); //重写getWriter方法,同时对其write方法进行增强,write方法可以指定编码方式
return pw;
}
public byte[] getBuffer(){
if(pw!=null){
pw.close();//将数据输出到bout流中
}
if(bout!=null){
return bout.toByteArray();//将缓存返回
}
return null;
}
}
class MyOutputStream extends ServletOutputStream{
private ByteArrayOutputStream bout;
@Override
public void write(int b) throws IOException {
// TODO Auto-generated method stub
bout.write(b); //将响应内容写到bout缓存流中
}
public MyOutputStream(ByteArrayOutputStream bout){
this.bout = bout;
}
}
class MyPrintWriter extends PrintWriter{
private ByteArrayOutputStream bout;
private String charset;
public MyPrintWriter(ByteArrayOutputStream bout, String charset) {
super(bout);
// TODO Auto-generated constructor stub
this.bout = bout; //创建一个PrintWriter,指定字符编码方式
this.charset = charset;
}
/* (non-Javadoc)
* @see java.io.PrintWriter#write(java.lang.String)
*/
@Override
public void write(String s) {
// TODO Auto-generated method stub
try {
bout.write(s.getBytes(charset)); //根据指定的编码方式,将响应内容写入到bout缓存
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Filter:
public class MyCompressFilter implements Filter{
private FilterConfig filterConfig;
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
MyCompressResponse gzipResp = new MyCompressResponse(response);
//使用gzipResp进行放行
chain.doFilter(request, gzipResp);
byte[] out = gzipResp.getBuffer(); //获取缓存内容
ByteArrayOutputStream bout = new ByteArrayOutputStream();
GZIPOutputStream gout = new GZIPOutputStream(bout);
gout.write(out);
gout.close(); //将缓存内容写入到使用GZIP方式压缩的流中
byte[] gzip = bout.toByteArray();
System.out.println("length:"+out.length);//通知浏览器响应内容的压缩方式及内容长度
response.setHeader("content-encoding", filterConfig.getInitParameter("encoding"));
response.setContentLength(gzip.length);
response.getOutputStream().write(gzip); //使用response将压缩后的内容写到浏览器中
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
this.filterConfig = filterConfig;
}
}