我的日常

登录/注册
您现在的位置:论坛 盖世程序员(我猜到了开头 却没有猜到结局) 运维优化 > 利用java过滤器实现压缩响应正文内容
总共48086条微博

动态微博

查看: 1870|回复: 0

利用java过滤器实现压缩响应正文内容

[复制链接]
admin    

1244

主题

544

听众

1万

金钱

管理员

  • TA的每日心情

    2021-2-2 11:21
  • 签到天数: 36 天

    [LV.5]常住居民I

    管理员

    跳转到指定楼层
    楼主
    发表于 2015-02-07 16:19:23 |只看该作者 |倒序浏览
    在前面的Response的相关内容中,就提到了把数据压缩然后传到浏览器上,通过压缩,能够提升网络文件的传输效率,在很多的场所都需要实用。
    如果我们需要在所有的页面都实现压缩,那么是不是把这个加在某一个地方就一起解决了呢?貌似我们能够在过滤器中加载很多的内容,那么是不是也可以把这个也加在过滤器中呢?答案是可以的。
    我们可以通过增强HttpServletResponseWrapper对象,压缩响应正文内容。
    1、 原理
    通过过滤器filter向目标页面传递一个自定义的response对象。在自定义的response对象中,重写getOutputStream方法和getWriter方法,使目标资源调用此方法输出页面内容时,获得的是我们自定义的ServletOutputStream对象。在我们自定义的ServletOuputStream对象中,重写write方法,使写出的数据写出到一个buffer中。当页面完成输出后,在filter中就可得到页面写出的数据,从而我们可以调用GzipOuputStream对数据进行压缩后再写出给浏览器,以此完成响应正文件压缩功能。可以设置Location响应头,实现请求重定向(可以查看HttpServletRequest相关内容);也可以设置Content-Encoding响应头,告诉浏览器数据的压缩格式;还可以设置content-type响应头,指定回送数据类型;也可以设置content-disposition响应头,让浏览器下载文件((可以查看HttpServletReonse相关内容))
    还可以利用它,做很多很多的事情。
    2、 用java过滤器实现压缩响应正文的源代码
    在带宽不够的时候,压缩是一种解决事情的好方法;现在的带宽是越来越大了,不过文件也越来越大,压缩还是有英雄用武之地的。其中百度等网站也是使用压缩的数据传递方式。
    package com.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;
    /**
    * 一个简单的响应正文压缩,过滤器实现
    * @author 范芳铭
    */
    public class EasyResponseGzipFilter implements Filter{
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("----过滤器初始化----");
        }

        @Override
        public void doFilter(ServletRequest req, ServletResponse resp,
                FilterChain chain) throws IOException, ServletException {

            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) resp;

            BufferResponse myresponse = new BufferResponse(response);
            chain.doFilter(request, myresponse);
            //拿出缓存中的数据,压缩后再打给浏览器
            byte out[] = myresponse.getBuffer();
            System.out.println("原始大小:" + out.length);

            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            //压缩输出流中的数据
            GZIPOutputStream gout = new GZIPOutputStream(bout);
            gout.write(out);
            gout.close();

            byte gzip[] = bout.toByteArray();
            System.out.println("压缩后的大小:" + gzip.length);

            response.setHeader("content-encoding", "gzip");
            response.setContentLength(gzip.length);
            response.getOutputStream().write(gzip);
        }

        @Override
        public void destroy() {
            System.out.println("----过滤器销毁----");
        }
    }

    class BufferResponse extends HttpServletResponseWrapper{
        private ByteArrayOutputStream bout = new ByteArrayOutputStream();
        private PrintWriter pw;
        private HttpServletResponse response;
        public BufferResponse(HttpServletResponse response) {
            super(response);
            this.response = response;
        }
        @Override
        public ServletOutputStream getOutputStream() throws IOException {
            return new MyServletOutputStream(bout);
        }
        @Override
        public PrintWriter getWriter() throws IOException {
            pw = new PrintWriter(new OutputStreamWriter(bout,this.response.getCharacterEncoding()));
            return pw;
        }

        public byte[] getBuffer(){
            try{
                if(pw!=null){
                    pw.close();
                }
                if(bout!=null){
                    bout.flush();
                    return bout.toByteArray();
                }


                return null;
            }catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    class MyServletOutputStream extends ServletOutputStream{

        private ByteArrayOutputStream bout;
        public MyServletOutputStream(ByteArrayOutputStream bout){
            this.bout = bout;
        }

        @Override
        public void write(int b) throws IOException {
            this.bout.write(b);
        }
    }
    3、 修改web.xml
    <filter>
          <description>配置压缩过滤器</description>
          <filter-name>GzipFilter</filter-name>
          <filter-class>com.filter.EasyResponseGzipFilter</filter-class>
      </filter>

      <!--jsp文件的输出的内容都经过压缩过滤器压缩后才输出 -->
      <filter-mapping>
          <filter-name>GzipFilter</filter-name>
          <url-pattern>*.jsp</url-pattern>
          <!-- 对重定向或者转向的jsp页面拦截,在Servlet中通过       request.getRequestDispatcher().forward()   -->
          <dispatcher>FORWARD</dispatcher>
          <!--对于直接以URL方式访问的jsp页面进行拦截,过滤器的拦截方式默认就是 REQUEST-->
          <dispatcher>REQUEST</dispatcher>
      </filter-mapping>
      <!--js文件的输出的内容都经过压缩过滤器压缩后才输出 -->
      <filter-mapping>
          <filter-name>GzipFilter</filter-name>
          <url-pattern>*.js</url-pattern>
      </filter-mapping>
      <!--css文件的输出的内容都经过压缩过滤器压缩后才输出 -->
      <filter-mapping>
          <filter-name>GzipFilter</filter-name>
          <url-pattern>*.css</url-pattern>
      </filter-mapping>
      <!--html文件的输出的内容都经过压缩过滤器压缩后才输出 -->
      <filter-mapping>
          <filter-name>GzipFilter</filter-name>
          <url-pattern>*.html</url-pattern>
      </filter-mapping>
    4、 最终运行结果
    输入url测试地址:
    Index.jsp是我通过myeclipse创建WEB应用自己创建的文件,没有做任何修改。
    运行结果如下:
    原始大小:625
    压缩后的大小:354


    科帮网 1、本主题所有言论和图片纯属会员个人意见,与本社区立场无关
    2、本站所有主题由该帖子作者发表,该帖子作者与科帮网享有帖子相关版权
    3、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和科帮网的同意
    4、帖子作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任
    5、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
    6、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意
    7、科帮网管理员和版主有权不事先通知发贴者而删除本文


    JAVA爱好者①群:JAVA爱好者① JAVA爱好者②群:JAVA爱好者② JAVA爱好者③ : JAVA爱好者③

    快速回复
    您需要登录后才可以回帖 登录 | 立即注册

       

    关闭

    站长推荐上一条 /1 下一条

    发布主题 快速回复 返回列表 联系我们 官方QQ群 科帮网手机客户端
    快速回复 返回顶部 返回列表