zoukankan      html  css  js  c++  java
  • 过滤器 & 装饰者模式

    一.过滤器概述
        ------------------------------------------------
        1.1.什么是过滤器?
            Servlet技术规范中, 定义了Servlet、Filter、Listener三门技术, 其中Filter也叫做过滤器,通过过滤器技术,开发人员可以实现用户在访问某个资源之前或之后,对访问的请求和响应进行拦截,从而做一些相关的处理。

            过滤器:
                ◇ 所谓的过滤器, 就是拦截用户对资源的访问
                ◇ 一个过滤器可以拦截多个资源, 一个资源也可以配置多个过滤器进行拦截
                ◇ 其实所谓的拦截, 就是将代表请求的request对象和代表响应的response对象拦截下来, 拦截下来后:
                    ◇ 控制是否允许访问 -- 用户登陆之后才能查看自己的订单页面
                    ◇ 在访问资源之前或之后做一些处理 比如: 全站乱码解决
                    ...
             
    ===================================================  
    二.开发过滤器
        ------------------------------------------------
        2.1.开发过滤器的步骤
            Servlet API中提供了一个Filter接口, 开发web应用时, 如果编写一个类实现了这个接口, 则这个类就是一个过滤器
            (1) 写一个类实现Filter接口, 并实现其中的方法
            (2) 在web应用的web.xml中配置过滤器
            
        ------------------------------------------------
        ~~2.2.Filter生命周期:
            当服务器启动时, web应用加载后会立即创建出当前web应用中的所有的Filter对象, 创建出来后, 立即调用init方法进行初始化出操作. 从此以后这个Filter对象一直驻留在内存中为后续所拦截的请求服务, 每次过滤到对资源的访问时, 都会执行doFilter这个方法进行拦截处理, 直到服务器关闭或者web应用移出容器为止, 随着web应用的销毁, 过滤器也跟着销毁, 在销毁之前会调用destroy方法执行善后的处理.
            
        ------------------------------------------------
        2.3.配置过滤器
            <filter> -- 配置一个过滤器
                <filter-name>FilterDemo1</filter-name>
                       -- 过滤器的名字
                <filter-class>cn.tedu.FilterDemo1</filter-class> -- 过滤器处理类的全路径名
            </filter>
            
            <filter-mapping> -- 为指定的过滤器配置要拦截的路径, 一个过滤器可以配置多个<filter-mapping>
                <filter-name>FilterDemo1</filter-name> -- 过滤器的名字
                <servlet-name>ServletDemo1</servlet-name> -- 拦截哪个名字的Servlet, 可以配置多个
                <url-pattern>/servlet/*</url-pattern> -- 要拦截的路径, 路径的写法和Servlet的<url-pattern>写法一致, 可以配置多个
                <dispatcher>REQUEST</dispatcher> -- 配置拦截哪种方式的对资源的访问, 可以取值为REQUEST/FORWARD/INCLUDE/ERROR
                    REQUEST:默认,普通请求,最常用
                    FORWARD:所拦截的资源是通过请求转发访问的
                    INCLUDE:所拦截的资源是通过页面包含访问的
                    ERROR:所拦截的资源通过异常机制访问的
            </filter-mapping>
            
        ------------------------------------------------
        2.4.Filter中的方法介绍
            --------------------------------------------
            init(FilterConfig filterConfig)
                FilterConfig -- 代表当前Filter在web.xml中配置信息的对象
                    通过这一对象可以获取当前过滤器在web.xml配置的初始化参数
                    通过这一对象可以获取代表当前web应用的ServletContext对象
                    获取初始化参数:
                        getInitParameter(String name);
                        getInitParameterNames()
                    获取ServletContext对象
                        getServletContext();
                        
            --------------------------------------------
            doFilter(request, response, FilterChian filterChian)
                  FilterChian -- 过滤器链
                      一个web资源可以被多个过滤器所拦截, 多个过滤器拦截的顺序是按照Filter在web.xml中配置的<filter-mapping>的顺序执行的.这多个过滤器按照拦截的顺序就组成了一个拦截器链, 用FilterChian表示.

                      如果一个过滤器处理完所拦截的请求后, 想要执行后面的拦截器, 则可以调用FilterChian上doFilter方法, 表示放行过滤器, 接着执行下一个节点
                      如果下一个节点仍然是过滤器, 则接着进行过滤, 执行的过程同上
                      如果没有后续的过滤器, 则执行真正的资源处理这次请求
                      
            --------------------------------------------
            destroy()
                略
            
    ===================================================          
    三.过滤器的应用
        ------------------------------------------------
        3.1.全站乱码解决过滤器
            (1).创建EncodingFilter过滤器类, 实现过滤器接口(Filter)
                详细代码参考: EncodingFilter.java
                
            (2).在web.xml中配置过滤器
                <!-- 配置全站乱码解决过滤器 -->
                <filter>
                    <filter-name>EncodingFilter</filter-name>
                    <filter-class>cn.tedu.filter.EncodingFilter</filter-class>
                </filter>
                <filter-mapping>
                    <filter-name>EncodingFilter</filter-name>
                    <url-pattern>/*</url-pattern>
                </filter-mapping>
            
        ------------------------------------------------
        3.2.自动登陆过滤器实现
            (1).创建AutoLoginFilter过滤器类, 实现过滤器接口(Filter)
                详细代码参考: AutoLoginFilter.java
                
            (2).在web.xml中配置过滤器
                <!-- 配置自动登陆过滤器 -->
                <filter>
                    <filter-name>AutoLoginFilter</filter-name>
                    <filter-class>cn.tedu.filter.AutoLoginFilter</filter-class>
                </filter>
                <filter-mapping>
                    <filter-name>AutoLoginFilter</filter-name>
                    <url-pattern>/*</url-pattern>
                </filter-mapping>

            (3).在LoginServlet中, 实现30天自动登陆, 将用户名和密码保存进Cookie
                if("true".equals(request.getParameter("autologin"))){
                    //实现30天自动登陆
                    Cookie cookie = new Cookie("autologin", username+":"+password);
                    cookie.setPath(request.getContextPath()+"/");
                    cookie.setMaxAge(3600*24*30);
                    response.addCookie(cookie);
                }
    ===================================================
    四.//案例--装饰者模式在乱码处理中的应用

    public class EncodingFilter implements Filter {
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("全站乱码解决过滤器初始化成功...");
        }
        
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            //1.解决响应正文乱码
            response.setContentType("text/html;charset=utf-8");
            
            //2.解决请求参数乱码 -- (利用装饰设计模式对request对象进行包装)
            HttpServletRequest myReq = new MyHttpServletRequest((HttpServletRequest)request);
        
            //3.放行过滤器
            chain.doFilter(myReq, response);
        }

        public void destroy() {
            
        }
    }

    class MyHttpServletRequest extends HttpServletRequestWrapper{
        //将request对象保存在类的内部
        private HttpServletRequest request;
        
        //定义flag, 控制getParameterMap()方法中map的遍历次数
        private boolean flag = true;
        
        public MyHttpServletRequest(HttpServletRequest request) {
            super(request);//这行代码千万不要省写!!!
            this.request = request;
        }
        
        public String getParameter(String name) {
            return getParameterValues(name) == null ? null : getParameterValues(name)[0];
        }
        
        public String[] getParameterValues(String name) {
            return (String[]) getParameterMap().get(name);
        }
        
        public Map getParameterMap() {
            try {
                String method = request.getMethod();
                if("POST".equals(method)){//--POST提交
                    request.setCharacterEncoding("utf-8");
                    return request.getParameterMap();
                }else if("GET".equals(method)){
                    //手动编解码解决乱码问题!
                    Map<String, String[]> map = request.getParameterMap();
                    if(flag){
                        for(Map.Entry<String, String[]> entry : map.entrySet()){
                            String[] vs = entry.getValue();
                            for(int i=0; i<vs.length; i++){
                                vs[i] = new String(vs[i].getBytes("iso8859-1"), "utf-8");
                            }
                        }
                        flag = false;
                    }
                    return map;
                }else{
                    return request.getParameterMap();
                }
                
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
    }

    =================================================

    五.装饰类详解

    1.     request继承结构

    ServletRequest(接口)

    |-- HttpServletRequest(接口)

    |-- 匿名实现类(xxx)  实例: request对象

    2.     ServletRequestWrapper装饰类

    request对象 --> 被装饰者

    ServletRequestWrapper--> 装饰类

    1.ServletRequestWrapper装饰类 和 被装饰者(request对象)所属的类(xxx)实现了同一个接口(ServletRequest)

    2.提供了构造方法允许将被装饰者传入并保存在了类的内部

    3.对于不想改造的方法直接调用已有对象上的方法, 对于想要改造的方法直接进行改造(没有对任何方法进行改造), 如:

    3.     HttpServletRequestWrapper装饰类

    request对象 --> 被装饰者

    HttpServletRequestWrapper -- 装饰类

    HttpServletRequestWrapper类继承了ServletRequestWrapper装饰类类, 所以HttpServletRequestWrapper也是一个装饰类!!

    HttpServletRequestWrapper类没有直接去包装request对象, 而是先将当前构造方法中的request对象传给父类(ServletRequestWrapper), 让父类进行包装, 再继承父类中包装后的方法。

    而对于自身独有的方法, 自己再进行包装: 通过父类提供的方法(super.getRequest()) 获取 包装后的request对象, 并强制转型为 HttpServletRequest, 并通过提供 _getHttpServletRequest 方法, 方便在当前类的内部使用, 代码如下:

    对于HttpServletRequestWrapper类中所有的方法, 直接调 super.getRequest() 对象 -- 即被父类包装后的request对象上的方法

    也就是说, 对于HttpServletRequestWrapper装饰类, 是向将自己构造方法中的request对象传给父类(方便父类进行包装), 再通过super.getRequest(); 获取父类中包装的request对象(目的是保证自己和父类包装的是同一个request)

    接下来对内部的方法进行包装, 即HttpServletRequestWrapper类中的方法分为两类: 第一类是通过父类继承过来的(父类对于这行方法已经进行包装), 第二类是自己独有的方法, 在自身类的内部进行包装!!





            
            
                    

        
        












       

  • 相关阅读:
    使用jQuery和CSS自定义HTML5 Video 控件 简单适用
    在win7系统下使用Windows XP Mode 和 Windows Virtual PC搭建window xp系统
    Runtime 解读
    Reachability实时监控网络变化
    关于AsyncSocket
    关于CoreData的用法
    邓白氏编码申请
    Android 到底是个什么东西?
    听 Fabien Potencier 谈Symfony2 之 《What is Symfony2 ?》
    听 Fabien Potencier 谈Symfony2 之 《What is Dependency Injection ?》
  • 原文地址:https://www.cnblogs.com/gerald-x/p/7021318.html
Copyright © 2011-2022 走看看