zoukankan      html  css  js  c++  java
  • filter修改response学习笔记

    前言:这个是我自己学习《Java Web 整合开发 王者归来》的学习笔记,对你们可能没有参考价值。这是filter那一章中,关于内容替换的filterGZIP压缩Filter的学习总结。
            这两个Filter中对response进行了修改,把这两个例子的代码都重新实现之后,弄懂了基本原理,但是也出现了一些困惑。
            大家可以下载《Java Web 整合开发 王者归来》的源代码,查阅filter压缩文件。
    内容替换Filter的学习心得
            内容替换的原理是,在Servlet将内容输出到response时,response将内容缓存起来,在Filter中进行替换,然后再输出到客户端浏览器,由于默认的response不能严格地将内容缓存起来,因此需要自定义一个具备缓存功能的response。
            如果response输出的的内容为字符类内容,则会调用getWrite()方法;如果是二进制内容则会调用getOutputStream()方法;
            通过扩展javax.servlet.http.HttpServletResponseWrapper类覆盖其中的getWrite()方法。
    package helloJava.respone;
    
    import java.io.CharArrayWriter;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpServletResponseWrapper;
    
    public class HttpCharacterResponseWrapper extends HttpServletResponseWrapper
    {
        private CharArrayWriter ref_charArrayWriter = new CharArrayWriter();
    
        public HttpCharacterResponseWrapper(HttpServletResponse response)
        {
            super(response);
            // TODO Auto-generated constructor stub
        }
        
        @Override
        public PrintWriter getWriter() throws IOException {
            return new PrintWriter(ref_charArrayWriter);
        }
        public CharArrayWriter getCharArrayWriter() {
            return ref_charArrayWriter;
        }
    
    }
    HttpServletResponseWrapper代码

        在Filter中将自定义的response传进Servlet中代码如下:

    package helloJava.filter;
    
    import helloJava.respone.HttpCharacterResponseWrapper;
    
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.Properties;
    
    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;
    
    public class OutputReplaceFilter implements Filter{
    
        //属性集合,敏感词集合
        private Properties pp=new Properties();
        @Override
        public void destroy()
        {
            // TODO Auto-generated method stub        
        }
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException
        {
            // TODO Auto-generated method stub
            //自定义的 Response
            HttpCharacterResponseWrapper ref_charResponse=new HttpCharacterResponseWrapper(
                                                (HttpServletResponse)response);
            chain.doFilter(request,ref_charResponse);
            
            String output=ref_charResponse.getCharArrayWriter().toString();
            for(Object obj:pp.keySet())
            {
                String key=(String) obj;
                output=output.replace(key,pp.getProperty(key));
            }
            //这部分不是特别明白,response是入口参数传递过来的
            PrintWriter out =response.getWriter();
            out.write(output);
            out.println("<!--Generated at "+new java.util.Date()+"-->");
        }
        @Override
        public void init(FilterConfig filterConfig) throws ServletException
        {
            // TODO Auto-generated method stub
            String file=filterConfig.getInitParameter("file");
            String realPath=filterConfig.getServletContext().getRealPath(file);
            try
            {
                pp.load(new FileInputStream(realPath));
            }
            catch(IOException e)
            {
    
            }
        }
    }
    OutputReplaceFilter 代码

        这段代码的主要功能是,在初始化阶段init方法读取敏感词的配置文件doFilter方法根据敏感词去进行替换;

    我理解的执行顺序
            1生成自己定义的response带缓存的,
            2然后chain.doFilter(request,ref_charResponse),这部分代表的FilterChain继续执行,当它调用结束时代表response已经是经过服务器处理过之后要返回给客户端浏览器的内容了,ref_charResponse代表服务器返回的处理结果。
            3 由于ref_charResponse是我们自己处理的,它缓存了服务器要返回去的内容,这个时候就可以对缓存中的内容进行内容替换了。
            4利用如果参数传递过来的response,把替换的内容(也就是ref_charResponse的内容)存入到response中,然后返回。
    问题:我对第3,4步理解的是否正确
    GZIP压缩Filter学习心得
            网站常使用GZIP压缩算法对网页内容进行压缩,然后传给浏览器。首先需要根据Http的Header查看浏览器是否支持GZIP编码方式相关代码如下:
      
    ....
            HttpServletRequest request=(HttpServletRequest)req;
            HttpServletResponse response=(HttpServletResponse)res;
            
            String acceptEncoding=request.getHeader("Accept-Encoding");
            System.out.println("Accept-Encoding: "+acceptEncoding);
        
            if(acceptEncoding!=null
                    &&acceptEncoding.toLowerCase().indexOf("gzip")!=-1){....}
         为了压缩,需要重新定义一个继承自HttpServletResponseWrapper的类,与上一个内容替换Filter定义的response不同的是,这个response不仅处理文本类,还要处理二进制类,因此需要覆盖getOutputStream()和getWriter()方法。处理二进制和文本通过两个类完成GZipResponseWrapperGZipOutputStream;其中GZipOutputStream完成对二进制流的压缩。
            对于二进制内容,当调用GZipOutputStream的close方法时,会通过response的相关方法传递到到客户端浏览器,类似于内容替换Filte的下见源代码。  
    package helloJava.gzip;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.util.zip.GZIPOutputStream;
    
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServletResponse;
    
    
    public class GZipOutputStream extends ServletOutputStream
    {
        private HttpServletResponse ref_http_response;
        
        private GZIPOutputStream ref_gzipOutputStream;
        
        private ByteArrayOutputStream ref_byteArrayOutputStream;
        
        public GZipOutputStream(HttpServletResponse response)throws IOException
        {
            this.ref_http_response=response;
            ref_byteArrayOutputStream=new ByteArrayOutputStream();
            ref_gzipOutputStream=new GZIPOutputStream(ref_byteArrayOutputStream);
        }
        @Override
        public void write(int b) throws IOException
        {
            // TODO Auto-generated method stub
            ref_gzipOutputStream.write(b);
        }
        public void close()throws IOException
        {
            //压缩完毕一定要调用该方法
            ref_gzipOutputStream.finish();
            //将压缩后的数据输出到客户端
            byte [] content=ref_byteArrayOutputStream.toByteArray();
            
            //设定压缩方式为GZIP,客户端会自动将压缩数据解压
            ref_http_response.addHeader("Content-Encoding", "gzip");
            ref_http_response.addHeader("Content-Length", Integer.toString(content.length));
            
            //输出
            ServletOutputStream out=ref_http_response.getOutputStream();
            out.write(content);
            out.close();
        }
        public void flush()throws IOException
        {
            ref_gzipOutputStream.flush();
        }
    
    }
    GZipOutputStream代码
      
    package helloJava.gzip;
    
    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;
    
    import helloJava.gzip.GZipOutputStream;
    
    public class GZipResponseWrapper extends HttpServletResponseWrapper
    {
    
        private HttpServletResponse ref_response;
        
        //自定义的outputStream,执行close()的时候对数据压缩,并输出
        private GZipOutputStream ref_gzipOutputStream;
        //自定义printWriter,将内容输出到GZipOutputStream中
        private PrintWriter ref_writer;
        public GZipResponseWrapper(HttpServletResponse response)
        {
            super(response);
            // TODO Auto-generated constructor stub
            this.ref_response=response;
        }
        
        public ServletOutputStream getOutputStream()throws IOException
        {
            if(ref_gzipOutputStream==null)
                ref_gzipOutputStream=new GZipOutputStream(ref_response);
            return ref_gzipOutputStream;
        }
        
        public PrintWriter getWriter() throws IOException {
            if (ref_writer == null)
                ref_writer = new PrintWriter(new OutputStreamWriter(
                        new GZipOutputStream(ref_response), "UTF-8"));
            return ref_writer;
        }
        // 压缩后数据长度会发生变化 因此将该方法内容置空
        public void setContentLength(int contentLength) {
        }
        public void flushBuffer()throws IOException
        {
            ref_gzipOutputStream.flush();
        }
        public void finishResponse()throws IOException
        {
            if(ref_gzipOutputStream!=null)
                ref_gzipOutputStream.close();
            if(ref_writer!=null)
                ref_writer.close();
        }
    }
    GZipResponseWrapper
      我困惑的是对于文本文件的压缩是怎么完成的
      对于getWriter()的源代码覆盖代码,中有GZipOutputStream部分,结合GZipResponseWrapper中的Close方法代码,我认为文本类的压缩也是通过GZipOutputStream完成的,而且PrintWriter的write方法可以接受byte[]的参数。 
    public PrintWriter getWriter() throws IOException {
            if (ref_writer == null)
                ref_writer = new PrintWriter(new OutputStreamWriter(
                        new GZipOutputStream(ref_response), "UTF-8"));
            return ref_writer;
        }

                                                                           菜包子

                                                                       2013年6月5日22:45:00  于宿舍

  • 相关阅读:
    mysql binlog参数设置
    poj 2774 最长公共子--弦hash或后缀数组或后缀自己主动机
    Base64编码和解码算法
    怎样给你的Android 安装文件(APK)减肥
    JAXB 注解
    编程获取linux的CPU使用的内存使用情况
    那么温暖http合约,入门。
    什么是关账?
    经营活动现金净流量与总股本之比和经营活动现金净流量与净资产之比
    P2P风险淮安样本:5000万连锁漩涡牵出银行内案
  • 原文地址:https://www.cnblogs.com/CaiBaoZi/p/3120091.html
Copyright © 2011-2022 走看看