• 过滤器


    过滤器
    过滤器是一种代码重用的技术,它可以改变 HTTP 请求的内容,响应,及 header 信息。过滤器通常不产生响应或像servlet 那样对请求作出响应,而是修改或调整到资源的请求,修改或调整来自资源的响应。
    供开发人员使用的过滤器功能有六种类型:
    在执行请求之前访问资源
    在执行请求之前处理资源的请求
    用请求对象的自定义版本包装请求,对请求的 header 和数据进行修改
    用响应对象的自定义版本包装响应,对响应的 header 和数据进行修改
    拦截资源调用之后的调用
    按指定顺序执行的零个、一个或多个拦截器作用于 Servlet ,一组 Servlet 或静态内容
    基础开发
    应用开发人员通过实现 javax.servlet.Filter 接口并提供一个公共的空参构造器来创建过滤器。该类及构建Web应用的静态资源和 Servlet 打包在 Web 应用归档文件中。 Filter 在部署描述符中通过 元素声 明。一个过滤器或一组过滤器可以通过在部署描述符中定义 - mapping> 来为调用配置。可以使 用servlet 的逻辑视图名把过滤器映射到一个特定的 servlet ,或者使用 URL 模式把一组 Servlet 和静态资源
    内容映射到过滤器。
    需求:编码字符集问题
    定义过滤器类实现 Filter 接口
    web.xml 中配置
    在部署描述符中声明的每个 在每个 JVM 的容器中仅实例化一个实例。容器提供了声明在过滤器 的部署描述符的过滤器config FilterConfig ),对 Web 应用的 ServletContext 的引用和一组初始化参数。
    public class EncodingFilter implements Filter {
    @Override
    public void doFilter ( ServletRequest request , ServletResponse response ,
    FilterChain chain ) throws IOException ,
    ServletException {
    request . setCharacterEncoding ( "UTF-8" );
    response . setCharacterEncoding ( "UTF-8" );
    // 前置处理
    chain . doFilter ( request , response ); // 执行下一个过滤器
    // 后置处理
    }
    }
    encoder
    com.yan.filters.EncodingFilter
    encoder
    /aa.do
    web.xml 中针对 Filter 添加初始化参数
    可以在 Filter 实现类的 init 方法中通过 FilterConfig 进行获取
    过滤器的核心概念是包装请求或响应,以便它可以覆盖行为执行过滤任务。在这个模型中,开发人员不
    仅可以覆盖请求和响应对象上已有的方法,也能提供新的 API 以适用于对过滤器链中剩下的过滤器或目标
    web 资源做特殊的过滤任务。
    encoder
    com.yan.filters.EncodingFilter
    配置初始化参数
    encoding 参数名称
    ISO-8859-1 具体的配置值
    public class EncodingFilter implements Filter {
    public EncodingFilter (){ // 过滤器对象在服务器启动后自动加载创建对象
    System . out . println ( " 构造器 ..." );
    }
    private String encoding = "UTF-8" ;
    @Override
    public void init ( FilterConfig filterConfig ) throws ServletException {
    // 初始化方法在对象创建完成后自动执行,可以通过 filterConfig 对象获取配置参数值。在整个
    Filter 对象的生命周期中运行且只运行一次
    System . out . println ( "init 方法 ...." );
    String ss = filterConfig . getInitParameter ( "encoding" ); // 通过服务器调
    init 方法时传入的 FilterConfig 对象读取配置参数值,名称已知
    if ( ss != null && ss . trim (). length () > 0 )
    this . encoding = ss . trim ();
    }
    @Override
    public void destroy () { //Filter 对象处理完成后常驻内存,只有在关闭服务器等特殊
    情况下才会销毁对象。在销毁对象前执行 destroy 方法,可以用于执行资源回收操作
    System . out . println ( "destroy...." );
    }
    @Override
    public void doFilter ( ServletRequest request , ServletResponse response ,
    FilterChain chain ) throws IOException , ServletException { // 以单实例多线程的方
    式执行过滤处理
    request . setCharacterEncoding ( encoding );
    response . setCharacterEncoding ( encoding );
    System . out . println ( "EncodingFilter....begin...." );
    // 前置处理
    chain . doFilter ( request , response ); // 执行下一个过滤器
    // 后置处理
    System . out . println ( "EncodingFilter....end...." );
    }
    }
    可以使用部署描述符中的 - params> 元素把一组初始化参数关联到过滤器。这些参数的名字和值在
    过滤器运行期间可以使用过滤器的 FilterConfig 对象的 getInitParameter getInitParameterNames 方法
    得到。另外, FilterConfig 提供访问 Web 应用的 ServletContext 用于加载资源,记录日志,在
    ServletContext 的属性列表存储状态。链中最后的过滤器和目标 servlet 或资源必须执行在同一个调用线 程。
    过滤器可以通过 @WebFilter 注解定义或者在部署描述符中使用 元素定义。在这个元素中,可声明三种内容:
    filter-name :用于映射过滤器到 servlet URL
    value 用于定义对应的 URL 地址,是 urlPatterns 的别名
    init-params :过滤器的初始化参数
    容器必须为部署描述符中定义的每个过滤器声明实例化一个 Java 类实例。因此,如果开发人员对一个过 滤器类声明了两次,则容器将实例化两个相同的过滤器类的实例。
    容器实例过滤器对象时是通过反射实现的,所以要求无参构造器
    一旦在部署描述符中声明了过滤器,配置人员使用 - mapping> 定义 Web 应用中的 servlet 和静态 资源到过滤器的应用。过滤器可以使用 - name> 元素关联到一个 Servlet 。过滤器可以使用
    - pattern> 风格的过滤器映射关联到一组 servlet 和静态内容。
    当使用 - pattern> 风格配置 - mapping> 元素,容器必须使用路径映射规则决定
    pattern> 是否匹配请求 URI
    容器使用的用于构建应用到一个特定请求 URI 的过滤器链的顺序:
    @WebFilter ( filterName = "encoder" , value =
    { "*.do" , "/bb.did" , "/images/*" }, initParams = {
    @WebInitParam ( name = "encoding" , value = "ISO8859-1" )
    })
    public class EncodingFilter implements Filter {
    encoder
    com.yan.filters.EncodingFilter
    encoding
    ISO-8859-1
    encoder
    test
    test
    com.yan.action.TestServlet
    test
    /test.do
    1 )首先 - pattern> 按照在部署描述符中的出现顺序匹配过滤器映射。
    2 )接下来 - name> 按照在部署描述符中的出现顺序匹配过滤器映射。
    如果过滤器映射同时包含了 - name> - pattern> ,容器必须展开过滤器映射为多个过滤
    器映射(每一个 - name> - pattern> 一个),保持 - name> - pattern>
    元素顺序。
    通过在部署描述符中使用心得 元素,开发人员可以为 filter-mapping 指定是否想要过滤器
    应用到请求,当:
    1 )请求直接来自客户端。可以由一个带有 REQUEST 值的 元素,或者没有任何
    元素来表示。
    2 )使用表示匹配 - pattern> - name> web 组件的请求分配器的 forward() 调用情况下
    处理请求。可以由一个带有 FORWARD 值的 元素表示。
    3 )使用表示匹配 - pattern> - name> Web 组件的请求分派器的 include() 调用情况下
    处理请求。可以由一个带有 INCLUDE 值的 元素表示。
    4 )使用错误处理指定的错误页面机制处理匹配 - pattern> 的错误资源的请求。可以由一个带有
    ERROR 值的 元素表示。
    5 )使用异步处理中的异步上下文分派机制对 web 组件使用 dispatche 调用处理请求。可以由一个带有
    ASYNC 值的 元素表示。
    6 )也可以是 1,2,3,4,5 的任何组合。
    FilterConfig
    FilterConfig Filter 过滤器的的配置类, Tomcat 启动创建 Filter 时就会创建一个 FilterConfig 类对象,这
    里包含了 Filter 的配置信息。
    FilterConfig 类的作用是获取 filter 过滤器的配置内容
    1 、获取过滤器的名称即 Filter-name 标签的值。
    2 、获取过滤器的初始参数即 init-param 标签的值。
    3 、获取 ServletContext 对象。
    FilterChain 过滤链
    String ss = filterConfig . getInitParameter ( "encoding" ); 用于获取指定的配置参数
    值,如果没有配置指定的参数则返回为 null
    String filterName = filterConfig . getFilterName (); 获取配置的 filter 的名称,例如对应
    < filter - name >
    final Enumeration < String > names = filterConfig . getInitParameterNames (); 获取
    所有的配置参数名称的迭代器
    while ( names . hasMoreElements ()){
    String name = names . nextElement ();
    String value = filterConfig . getInitParameter ( name );
    }
    final ServletContext application = filterConfig . getServletContext (); 获取应用
    上下文对象
    作用:往下继续执行过滤器或者执行目标资源
    针对不同的信息处理写不同的 Filter ,然后把 Filter 放在一个 FilterChain 中,以实现信息处理的热拔插,
    这样一个 FilterChain 就像一条职责链,链上的每个节点处理不同的功能
    FilterChain 过滤器有多个 Filter 时的特点:
    多个 Filter 的执行顺序的先后是由在 web.xml 中定义的先后(从上到下)顺序决定的。注意:由于
    Filter 是根据 URL 进行过滤的,最先走到的是 filter-mapping 标签,所以上面所说的定义的先后顺序
    是指 filter-mapping 标签的位置顺序。
    多个 Filter 执行的时候默认是同一个线程目标资源也是同一个线程
    执行的时候是同一个 request 对象。(因为同一次请求)
    Filter 拦截器路径
    1 、精确匹配。例 /target.jsp 表示 URL 地址必须是 http:// 服务地址 : 端口 / 工程目录 /target.jsp
    2 、目录匹配。例 /admin/* 表示 URL 地址必须是以 http:// 服务地址 : 端口 / 工程目录 /admin/ 开头
    3 、后缀名匹配。例如 *.jsp 表示 URL 地址必须以 .jsp 结尾; *.do 表示 URL 地址必须以 .do 结尾,注
    意不能是含有 / 否则错误
    Filter 过滤器它只关心请求的地址是否匹配, 不关心请求的资源是否存在
    责任链模式
    责任链模式 Chain of Responsibility Pattern 为请求创建了一个接收者对象的链。这种模式给予请求的类
    型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式
    意图:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条
    链,并且沿着这条链传递请求,直到有对象处理它为止。
    主要解决:职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的
    处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
    优点: 1 、降低耦合度。它将请求的发送者和接收者解耦。 2 、简化了对象。使得对象不需要知道链的
    结构。 3 、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增
    或者删除责任。 4 、增加新的请求处理类很方便。
    缺点: 1 、不能保证请求一定被接收。 2 、系统性能将受到一定影响,而且在进行代码调试时不太方
    便,可能会造成循环调用。 3 、可能不容易观察运行时的特征,有碍于除错。
    首先定义接口 Filter 。所有的 Filter 必须遵循这个规范,才能装载在 FilterChain
    定义 FilterChain 以及各个 Filter
    public interface Filter {
    void doFilter(Request request,Response response,FilterChain chain);
    }
    public class FilterChain implements Filter {
    List < Filter > fs = new ArrayList < Filter > ();
    int index = 0 ;
    public FilterChain addFilter ( Filter f ) {
    fs . add ( f );
    return this ;
    }
    public void doFilter ( Request request , Response response , FilterChain chain ) {
    定义过滤器
    测试程序
    Filter 生命周期
    1 、加载和实例化。
    Web 容器启动时,即会根据 web.xml 中声明的 filter 顺序依次实例化这些 filter
    2 、初始化。
    Web 容器调用 init(FilterConfig) 来初始化过滤器。容器在调用该方法时,向过滤器传递
    FilterConfig 对象, FilterConfig 的用法和 ServletConfig 类似。利用 FilterConfig 对象可以得到
    ServletContext 对象,以及在 web.xml 中配置的过滤器的初始化参数。在这个方法中,可以抛出
    ServletException 异常,通知容器该过滤器不能正常工作。此时的 Web 容器启动失败,整个应用
    if ( index == fs . size ())
    return ;
    Filter f = fs . get ( index );
    index ++ ;
    f . doFilter ( request , response , chain );
    }
    }
    public class HTMLFilter implements Filter {
    public void doFilter ( Request request , Response response , FilterChain
    chain ) {
    request . requestStr = request . requestStr . replace ( "<" , "
    [" ). replace ( ">" , "]" ) + "--HTML--" ;
    chain . doFilter ( request , response , chain );
    response . responseStr += "--HTML--" ;
    }
    }
    public class SensitiveFilter implements Filter {
    public void doFilter ( Request request , Response response , FilterChain
    chain ) {
    request . requestStr = request . requestStr . replace ( " 被就业 " , "
    " ). replace ( " 敏感 " , "**" ) + "--Sensitive--" ;
    chain . doFilter ( request , response , chain );
    response . responseStr += "--Sensitive--" ;
    }
    }
    String msg = " 测试,