过滤器 & 装饰者模式

一.过滤器概述
    ------------------------------------------------
    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);
        }
    }
}html

=================================================java

五.装饰类详解web

1.     request继承结构

ServletRequest(接口)设计模式

|-- HttpServletRequest(接口)服务器

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

2.     ServletRequestWrapper装饰类

request对象 --> 被装饰者app

ServletRequestWrapper--> 装饰类this

 

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

 

 

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

 

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类中的方法分为两类: 第一类是经过父类继承过来的(父类对于这行方法已经进行包装), 第二类是本身独有的方法, 在自身类的内部进行包装!!

相关文章
相关标签/搜索