zoukankan      html  css  js  c++  java
  • 使用filter过滤GZIP压缩(二)

    在代码之前,讲一下用filter实现GZIP压缩的原理:

            因为GZIP压缩之后,是从服务器端传输到浏览器端,从servlet到浏览器(从jsp到浏览器),其实是response带回内容,所以我们要在filter中对从servlet端响应回来的response进行操作,因为写内容是response中的writer或者outputStream来完成的,所以我们首先要把response中的writer或者outputStream中的内容取出来这里我选择了writer进行操作(writer和outputStream其实皆可),但是问题又来了,response.getWriter.write();直接就写出了内容(因为response内部的writer其实是PrintWriter),定位输出到浏览器页面显示上了,并没有缓存起来,那么我们该怎么解决这个问题呢?

            思路如下:

                        使用装饰者模式对response中的getWriter方法进行重写,以便提供一个带缓存的writer,让操作者得到的writer实际上write是定位在writer构造传入的缓存中的(这个缓存可以使用我们之前讲的ByteArrayOutputStream或者CharArrayWriter这类输出流的好处是,带有一个toByteArray和toCharArray的方法,可以直接获得流内部的内容发)重写HttpServletResponse,同样因为HttpServletResponse只是一个接口,所以要继承自HttpServletResponse的实现类:HttpServletResponseWrapper,(同之前讲过的这篇博文,request和response都是实现wrapper);然后在我们重写之后的response中提供直接获得内部缓存内容的方法,然后我们就可以在filter中正常压缩啦!奋斗

    servlet中的代码:

    package day04;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.util.zip.GZIPOutputStream;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class ContentTestGZIPFilterServlet extends HttpServlet {
    
    	private static final long serialVersionUID = 3505039773816640152L;
    
    	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		response.setContentType("text/html;charset=utf-8");
    		// 准备内容
    		StringBuffer sb = new StringBuffer();
    		for (int i=1; i<=3000; i++) {
    			sb.append("abcd");
    		}
    		System.out.println("压缩前的数据大小:"+sb.toString().getBytes().length);
    		// 输出到浏览器
    		response.getWriter().write(sb.toString());
    	}
    
    	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		request.setCharacterEncoding("utf-8");
    		response.setContentType("text/html;charset=utf-8");
    
    	}
    
    }

    web.xml中filter的配置:

      <filter>
      	<filter-name>GZIPFilter</filter-name>
      	<filter-class>day04.GZIPFilter</filter-class>
      </filter>
      <filter-mapping>
      	<filter-name>GZIPFilter</filter-name>
      	<url-pattern>/*</url-pattern>
      </filter-mapping>  

    filter的代码:

    package day04;
    
    import java.io.ByteArrayOutputStream;
    import java.io.CharArrayWriter;
    import java.io.IOException;
    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.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpServletResponseWrapper;
    
    public class GZIPFilter implements Filter {
    
    	public void destroy() {}
    	public void init(FilterConfig filterConfig) throws ServletException {}
    
    	
    	public void doFilter(ServletRequest request, ServletResponse response,
    			FilterChain chain) throws IOException, ServletException {
    		//1)过滤请求
    		
    		//创建一个response的装饰者对象
    		MyHttpResponse myResponse = new MyHttpResponse((HttpServletResponse)response);
    		/**
    		 * 放行
    		 */
    		chain.doFilter(request, myResponse);
    		
    		//3)过滤响应
    		//从缓存容器对象得到压缩前的内容
    		//注意:response对象中没有方法获取实体内容,怎么办?
    		char[] content = myResponse.getCharArray();
    
    		//gzip压缩
    		ByteArrayOutputStream buf = new ByteArrayOutputStream();
    		GZIPOutputStream gzip = new GZIPOutputStream(buf);
    		gzip.write(new String(content).getBytes());
    		gzip.finish();
    		byte[] result = buf.toByteArray();
    		
    		//告诉浏览器发送内容的压缩格式
    		myResponse.setHeader("content-encoding", "gzip");
    		
    		//输出:
    		/*
    		 * 注意:
    		 * 		这里的输出不能使用PrintWriter了
    		 *		因为PrintWriter的输出定位已经在了内部的流缓存中了,不能定位到界面输出了
    		 *		所以要使用OutputStream
    		 */
    		response.getOutputStream().write(result);
    		//myRresponse.getWriter().write(new String(result,0,result.length));
    	}
    }
    
    
    
    /**
     * HttpServletResponse的装饰者类
     */
    class MyHttpResponse extends HttpServletResponseWrapper{
    
    	private HttpServletResponse response;
    	
    	//定义一个缓存容器对象:必须是自带缓冲的流,不能是包装流:即构造方法还需要传入一个writer的流
    	CharArrayWriter charArray = new CharArrayWriter();
    	
    	/**
    	 * 提供一个获取charArray内容的方法
    	 */
    	public char[] getCharArray(){
    		return charArray.toCharArray();
    	}
    	
    	public MyHttpResponse(HttpServletResponse response) {
    		super(response);
    		this.response = response;
    	}
    	
    	/**
    	 * 重写getWriter()方法,让其返回一个带缓存功能的PrintWriter
    	 */
    	@Override
    	public PrintWriter getWriter() throws IOException {
    		/**
    		 * 现在已经创建了一个带CharArrayWriter缓存容器的PrintWriter了,
    		 * 如果我们调用带缓存PrintWriter对象的write()方法,那么内容会直接写入到CharrArrayWriter缓存容器中。
    		 */
    		return new PrintWriter(charArray);
    	}
    	
    	
    	
    }
    
    
    
    
    


  • 相关阅读:
    关于ArcMap中的地图文档单位
    洛谷—— P2983 [USACO10FEB]购买巧克力Chocolate Buying
    COGS——T 826. [Tyvj Feb11] GF打dota
    洛谷—— P1855 榨取kkksc03
    洛谷—— P2663 越越的组队
    COGS——T 1578. 次小生成树初级练习题
    Django中间件
    March 7 2017 Week 10 Tuesday
    March 6 2017 Week 10 Monday
    March 5 2017 Week 10 Sunday
  • 原文地址:https://www.cnblogs.com/mzywucai/p/11053413.html
Copyright © 2011-2022 走看看