zoukankan      html  css  js  c++  java
  • Java Web总结二十Filter、装饰设计模式

    一、Filter的部署——注册Filter

    <filter>
             <filter-name>testFitler</filter-name>
             <filter-class>org.test.TestFiter</filter-class>
             <init-param>
               <param-name>word_file</param-name>    
               <param-value>/WEB-INF/word.txt</param-value>
             </init-param>
    </filter>

        1、<filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。

      2、<filter-class>元素用于指定过滤器的完整的限定类名。

      3、<init-param>元素用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名字,<param-value>指定参数的值。在过滤器中,可以使用FilterConfig接口对象来访问初始化参数。

    二、Filter的部署——映射Filter

      1、<filter-mapping>元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet名称和资源访问的请求路径。

      2、<filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字。

      3、<url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)

      4、<servlet-name>指定过滤器所拦截的Servlet名称。

      5、<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。

      6、<dispatcher> 子元素可以设置的值及其意义:

        (1)REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。

        (2)INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。

        (3)FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。

        (4)ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。注意:一定要在web.xml文件声明错误代码或类型

    <error-page>
          <error-code>500</error-code>
          <location>/sys_500.jsp</location>
    </error-page>    
     
    <filter-mapping>
        <filter-name>MappingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    
        <dispatcher>ERROR</dispatcher>
    </filter-mapping>

     三、装饰设计模式

      1、需求:当某个类的某个方法不适应当前业务的需要

      2、思路:(1)扩展父类的可供扩展的方法,可以使有,但不优;(2)装饰设计模式(推荐)

      3、开发步骤:

        (1)首先看需要被增强对象继承了什么接口或父类,编写一个类也去继承这些接口或父类或被增强对象本身。

        (2)在类中定义一个变量,变量类型即需增强对象的类型。

        (3)在类中定义一个构造函数,接收需增强的对象。

        (4)覆盖需增强的方法,编写增强的代码。

        (5)对于不想增强的方法,直接调用被增强对象的方法。

      4、案例:对BufferedReader进行装饰

    package com.gnnuit.web.decorator;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    
    //对BufferedReader进行装饰
    public class MyBufferedRead {
        private BufferedReader reader;
        private int no;
    
        public MyBufferedRead(BufferedReader reader) {
            this.reader = reader;
        }
    
        // 重写父对象的方法
        public String readLine() throws IOException {
            String line = reader.readLine();
            if (line != null) {
                no++;
                line = no + ":" + line;
            }
            return line;
        }
    
        // 真接使用父对象的方法
        public void close() throws Exception {
            reader.close();
        }
    }

    四、 request对象的增强案例

      1、使用Decorator模式包装request对象,完全解决get、post请求方式下的乱码问题。

      (1)MyRequest.java

    package com.gnnuit.web.decorator;
    
    import java.io.UnsupportedEncodingException;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    
    public class MyRequest extends HttpServletRequestWrapper {
        private HttpServletRequest request;
    
        public MyRequest(HttpServletRequest request) {
            super(request);
            this.request = request;
        }
    
        @Override
        public String getParameter(String name) {
            String value = null;
            String method = request.getMethod();
            if ("GET".equals(method)) {
                value = request.getParameter(name);
                byte[] buf;
                try {
                    buf = value.getBytes("ISO8859-1");
                    value = new String(buf, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            } else if ("POST".equals(method)) {
                try {
                    request.setCharacterEncoding("UTF-8");
                    value = request.getParameter(name);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
            return value;
        }
    
    }

      (2)EncodingFilter.java

    package com.gnnuit.web.filter;
    
    import java.io.IOException;
    
    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.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import com.gnnuit.web.decorator.MyRequest;
    
    public class EncodingFilter implements Filter {
    
        @Override
        public void destroy() {
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            HttpServletRequest servletRequest = (HttpServletRequest) request;
            HttpServletResponse servletResponse = (HttpServletResponse) response;
            MyRequest myRequest = new MyRequest(servletRequest);
            chain.doFilter(myRequest, servletResponse);        
        }
    
        @Override
        public void init(FilterConfig arg0) throws ServletException {
    
        }
    
    }

      2、使用Decorator模式包装request对象,实现html标签转义功能(Tomcat服务器中提供了转义html标签的工具类)。

      (1)MyRequest.java

    package cn.itcast.web.decorator;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    
    //对HttpServletRequest对象包装/装饰
    public class MyRequest extends HttpServletRequestWrapper{
        private HttpServletRequest request;
        public MyRequest(HttpServletRequest request) {
            super(request);
            this.request = request;
        }
        //重写父类的方法
        public String getParameter(String name) {//表单项的名字
            String value = null;
            //取得客户端的请求方式[GET/POST]
            String method = request.getMethod();
            if("GET".equals(method)){
                try {
                    value = request.getParameter(name);//乱码
                    byte[] buf = value.getBytes("ISO8859-1");
                    value = new String(buf,"UTF-8");//正码
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }else if("POST".equals(method)){
                try {
                    request.setCharacterEncoding("UTF-8");
                    value = request.getParameter(name);//正码
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            value = filter(value);
            return value;
        }
        //转义方法
        public String filter(String message) {
            if (message == null)
                return (null);
            char content[] = new char[message.length()];
            message.getChars(0, message.length(), content, 0);
            StringBuffer result = new StringBuffer(content.length + 50);
            for (int i = 0; i < content.length; i++) {
                switch (content[i]) {
                case '<':
                    result.append("&lt;");
                    break;
                case '>':
                    result.append("&gt;");
                    break;
                case '&':
                    result.append("&amp;");
                    break;
                case '"':
                    result.append("&quot;");
                    break;
                default:
                    result.append(content[i]);
                }
            }
            return (result.toString());
        }
    }

    五、response增强案例——压缩响应

      Servlet  API 中提供了response对象的Decorator设计模式的默认实现类HttpServletResponseWrapper , (HttpServletResponseWrapper类实现了response接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的 response对象的对应方法)以避免用户在对response对象进行增强时需要实现response接口中的所有方法。

      应用HttpServletResponseWrapper对象,压缩响应正文内容。思路:

      1、通过filter向目标页面传递一个自定义的response对象。

      2、在自定义的response对象中,重写getOutputStream方法和getWriter方法,使目标资源调用此方法输出页面内容时,获得的是我们自定义的ServletOutputStream对象。

      3、在我们自定义的ServletOuputStream对象中,重写write方法,使写出的数据写出到一个buffer中。

      4、当页面完成输出后,在filter中就可得到页面写出的数据,从而我们可以调用GzipOuputStream对数据进行压缩后再写出给浏览器,以此完成响应正文件压缩功能。

      5、完整代码:

      (1)ShowServlet.java

    package com.gnnuit.web.servlet;
    
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class ShowServlet extends HttpServlet {
    
        private static final long serialVersionUID = 1L;
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            ServletOutputStream sos = response.getOutputStream();
            sos.write("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
                    .getBytes());
        }
    
    }

      (2)MyResponse.java

    package com.gnnuit.web.decorator;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpServletResponseWrapper;
    
    //对response对象的装饰/包装
    public class MyResponse extends HttpServletResponseWrapper {
        private HttpServletResponse response;
        // 缓存
        private ByteArrayOutputStream bout = new ByteArrayOutputStream();
    
        public MyResponse(HttpServletResponse response) {
            super(response);
            this.response = response;
        }
    
        // 重写父类方法,目的是将字节输出到缓存中去[字节]
        @Override
        public ServletOutputStream getOutputStream() throws IOException {
            return new MyServletOutputStream(bout);
        }
    
        // 取得缓存中的数据
        public byte[] getBuffer() {
            return bout.toByteArray();
        }
    }
    
    // 带有缓存功能ServletOutputStream
    class MyServletOutputStream extends ServletOutputStream {
        private ByteArrayOutputStream bout;
    
        public MyServletOutputStream(ByteArrayOutputStream bout) {
            this.bout = bout;
        }
    
        @Override
        public void write(int b) throws IOException {
    
        }
    
        public void write(byte[] bytes) throws IOException {
            // 将字节数组的内容写入缓存
            bout.write(bytes);
            // 确保所有字节数组内容进入缓存
            bout.flush();
            bout.close();
        }
    }

      (3)GzipFilter.java

    package com.gnnuit.web.filter;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    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 com.gnnuit.web.decorator.MyResponse;
    
    public class GzipFilter implements Filter {
    
        @Override
        public void destroy() {
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            HttpServletResponse servletResponse = (HttpServletResponse) response;
            MyResponse myResponse = new MyResponse(servletResponse);
            chain.doFilter(request, myResponse);
            // 取得缓存中的内容
            byte[] data = myResponse.getBuffer();
            System.out.println("压缩前:" + data.length);
            // 进行压缩
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            GZIPOutputStream gout = new GZIPOutputStream(bout);
            gout.write(data);
            gout.flush();
            gout.close();
            data = bout.toByteArray();
            System.out.println("压缩后:" + data.length);
            // 通知浏览器接收的是一个压缩性数据和长度
            servletResponse.setHeader("content-encoding", "gzip");
            servletResponse.setHeader("content-length", data.length + "");
            // 以字节方式真正输出到浏览器
            response.getOutputStream().write(data);
        }
    
        @Override
        public void init(FilterConfig arg0) throws ServletException {
    
        }
    
    }

    六、实用案例——缓存数据到内存

      对于页面中很少更新的数据,例如商品分类,为避免每次都要从数据库查询分类数据,因此可把分类数据缓存在内存或文件中,以此来减轻数据库压力,提高系统响应速度。

      思路:

      1 得到用户访问资源的URI。

      2 检查缓存中是否有该页面。

      3 如果有则取出缓存中的数据显示给浏览器。

      4 否则让目标资源执行,并捕获目标资源的输出。

      5 将目标资源的数据以URI为关键字存到缓存中。

      6 向浏览器输出目标资源。

      代码如下:

      CacheFilter.java

    package com.gnnuit.web.filter;
    
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    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.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import com.gnnuit.web.decorator.MyResponse;
    
    public class CacheFilter implements Filter {
        private Map<String, byte[]> cache = new HashMap<String, byte[]>();
    
        @Override
        public void destroy() {
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            HttpServletResponse servletResponse = (HttpServletResponse) response;
            HttpServletRequest servletRequest = (HttpServletRequest) request;
            // NO1:取得客户端访问的资源路径
            String uri = servletRequest.getRequestURI();
            // 根据uri去缓存中查询对应的页面资源有没有
            byte[] data = cache.get(uri);
            // NO3:如果没有
            if (data == null) {
                // 将请求和响应放到web资源中
                MyResponse myResponse = new MyResponse(servletResponse);
                chain.doFilter(servletRequest, myResponse);
                // NO4:将刚取得的数据放入到缓存中,便于下次重用
                data = myResponse.getBuffer();
                cache.put(uri, data);
    
                System.out.println("从服务端取得资源");
                // NO5:如果有,直接从缓存中了得数据
            }
            // NO6:向浏览器输出数据
            servletResponse.getOutputStream().write(data);
        }
    
        @Override
        public void init(FilterConfig arg0) throws ServletException {
    
        }
    
    }

     七、总结Filter和Servlet

      1、Filter通常完成一些非核心的业务流程控制;Servlet通常完成一些核心的业务流程控制。

      2、Filter通常完成一些对Servlet的请求和响应的预先处理控制;Servlet却不行。

      3、Filter和Servlet是一个互补的技术,而不是替代技术。

  • 相关阅读:
    129 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 03 饿汉模式 VS 懒汉模式 02 懒汉式的代码实现
    128 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 03 饿汉模式 VS 懒汉模式 01 饿汉式的代码实现
    127 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 02 单例模式概述 01 单例模式的定义和作用
    126 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 01 设计模式概述 01 设计模式简介
    125 01 Android 零基础入门 02 Java面向对象 05 Java继承(下)05 Java继承(下)总结 01 Java继承(下)知识点总结
    leetcode-----121. 买卖股票的最佳时机
    leetcode-----104. 二叉树的最大深度
    Json串的字段如果和类中字段不一致,如何映射、转换?
    Mybatis-Plus的Service方法使用 之 泛型方法default <V> List<V> listObjs(Function<? super Object, V> mapper)
    模糊查询
  • 原文地址:https://www.cnblogs.com/FlySheep/p/3736189.html
Copyright © 2011-2022 走看看