在客户端访问数据时候,为了尽量高效率的传输,在传输的JSP网页的时候,能够采用GZIP压缩的方式,使得网页通过压缩后再去传输。在此,使用过滤器,对发送到的客户端的显示,都先进行一次压缩。而后再显示,具体流程能够参考下图:java
也就是说,当每得到一次请求是的时候,经过对getOutputStream的重写,不让其输出到客户端,而是 将其写入到内存字节数组中去。 而后,当须要输出的时候, 也就是过滤器的第二次执行从chain.doFilter(request,response)开始数组
再次充内存中取出缓存的数据,进行压缩,并用response进行输出。缓存
package cn.Filter; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.zip.GZIPOutputStream; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; public class FilterGZIP implements Filter { public void destroy() { // TODO Auto-generated method stub } public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest) req; HttpServletResponse response=(HttpServletResponse) res; //从新封装response ,来达到改写其已知方法的过程 MyResponse mresponse=new MyResponse(response); //以上为过滤器的请求时候的过滤过程; //当请求的时候,传入的response 的getOutPutStream方法已经被修改过了。 //所以,此时若是页面上调用getOutPutStream 方法的时候,其实调用的是本身写的。 chain.doFilter(request, mresponse); //请求接受, 开始响应,二次输出的时候,就是开始要将内存中的字节数组,通过压缩传输到客户端的过程了。 ByteArrayOutputStream baos =new ByteArrayOutputStream(); GZIPOutputStream gos=new GZIPOutputStream(baos); //从内存中获取到 原始为压缩的数据。 byte b[]= mresponse.getByte(); System.out.println("压缩前共有"+b.length+"字节"); gos.write(b); gos.flush(); gos.close(); b=baos.toByteArray(); System.out.println("压缩后共有"+b.length+"字节"); //设置客户端识别打开的方式。 response.setHeader("Content-Encoding", "GZIP"); response.setContentLength(b.length); response.getOutputStream().write(b); } public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub } }
以上就是Filter中的所有代码,而后 就是怎样从新封装response的问题了。J2EE中提供了,响应的包装类ServletResponseWrapper 只要继承这个类,重写相应的getOutPutStreaM方法,则目标即刻达成!app
class MyResponse extends HttpServletResponseWrapper { //这个是用来存放页面要输出信息的字节数组。 private ByteArrayOutputStream baos=new ByteArrayOutputStream(); //这个封装的字符流输出对象 private PrintWriter pw; public MyResponse(HttpServletResponse response) { super(response); } //这个方法,很重要,就是用来获取页面信息存放在内存中的字节数组。 也是压缩的目的 public byte[] getByte() { try { if(pw!=null){ pw.flush(); pw.close(); } baos.flush(); } catch (IOException e) { e.printStackTrace(); } return baos.toByteArray(); } //这个方法,就是咱们要重写的方法,可是这个方法,有个返回值ServletOutputStream,而这个类又是个抽象类,因此必须还要把这个类给实现了。能够参考下一个代码块 @Override public ServletOutputStream getOutputStream() throws IOException { return new MyServletOutputStream(baos); } @Override public PrintWriter getWriter() throws IOException { pw= new PrintWriter(new OutputStreamWriter(baos,super.getCharacterEncoding())); return pw; } }
//这个是应上面getOutPutStream 的邀请的返回值。 也是要 servlet中实际调用的方法。 不会输出到页面,只会将servlet中要写的内容放入到内存中去。 class MyServletOutputStream extends ServletOutputStream{ //缓冲页面数据存放区域 private ByteArrayOutputStream baos; public MyServletOutputStream(ByteArrayOutputStream baos){ this.baos=baos; } @Override public void write(int b) throws IOException { //将输出写入输出缓存 baos.write(b); } }
我本身的理解图形
ide