zoukankan      html  css  js  c++  java
  • Filter及Filter的那点事儿

    在学习java的一些框架的时候,对web.xml的相关配置不太懂,所以搜索了一些Filter(一系列的过滤器)、FilterChain;FileterDispatcher(Filter的程序调度)、Intercepter(拦截器)一些相关的资料学习。在看到Struts 2的工作机制后,知道客户端的每一次请求,在到达Servlet之前,Filter会对请求做一系列的过滤。而Filter是根据web.xml中的配置怎么过滤客户端请求的;

    1.Filter

    Filter 有如下几个用处:

    • l  在HttpServletRequest 到达Servlet 之前,拦截客户的HttpServletRequest 。 
    • l  根据需要检查HttpServletRequest ,也可以修改HttpServletRequest 头和数据。 
    • l  在HttpServletResponse 到达客户端之前,拦截HttpServletResponse 。 
    • l  根据需要检查HttpServletResponse ,可以修改HttpServletResponse 头和数据。

    Filter 有如下几个种类:

    • l  用户授权的Filter: Filter 负责检查用户请求,根据请求过滤用户非法请求。 
    • l  日志Filter: 详细记录某些特殊的用户请求。 
    • l  负责解码的Filter: 包括对非标准编码的请求解码。 
    • l  能改变XML 内容的XSLTFilter 等。 

    创建一个Filter 只需两个步骤: 

    • (1)创建Filter 处理类;
    • (2)在web.xml 文件中配置Filter。

      创建Filter 必须实现javax.servlet.Filter 接口,在该接口中定义了三个方法。 

    如下的代码实例中:设置了Filter的实现类(test.filter.LogFilter),用来执行过滤来自(/filter/*)这个路径下的请求;

     1 <!-- 定义Filter --> 
     2 <filter> 
     3     <!-- Filter 的名字 --> 
     4     <filter-name>log</filter-name> 
     5     <!-- Filter 的实现类 --> 
     6     <filter-class> test.filter.LogFilter</filter-class> 
     7 </filter> 
     8 <!-- 定义Filter 拦截地址 --> 
     9 <filter-mapping> 
    10     <!-- Filter 的名字 --> 
    11     <filter-name>log</filter-name> 
    12     <!-- Filter 负责拦截的URL --> 
    13     <url-pattern>/filter/*</url-pattern>
    14 </filter-mapping> 

    如下代码是test.filter.LogFilter的实现类;Filter的生命周期为:init()->doFilter()->destroy();在下面的请求Filter实现类处理中,仅在日志中记录请求的URL,对所有的请求都执行chain.doFilter(request,reponse)方法,当Filter 对请求过滤后,依然将请求发送到目的地址。 

     1 package test.filter;
     2  
     3 import javax.servlet.Filter;
     4 import javax.servlet.FilterChain;
     5 import javax.servlet.FilterConfig;
     6 import javax.servlet.ServletContext;
     7 import javax.servlet.ServletRequest;
     8 import javax.servlet.ServletResponse;
     9 import javax.servlet.http.HttpServletRequest;
    10  
    11 public class LogFilter implements Filter { 
    12     private FilterConfig config; 
    13     // 实现初始化方法 
    14     public void init(FilterConfig config) { 
    15         this.config = config; 
    16     } 
    17     // 实现销毁方法 
    18     public void destroy() { 
    19         this.config = null; 
    20     } 
    21     public void doFilter(ServletRequest request, ServletResponse response, 
    22             FilterChain chain) { 
    23         // 获取ServletContext 对象,用于记录日志 
    24         ServletContext context = this.config.getServletContext(); 
    25         long before = System.currentTimeMillis(); 
    26         System.out.println("开始过滤... "); 
    27         // 将请求转换成HttpServletRequest 请求 
    28         HttpServletRequest hrequest = (HttpServletRequest) request; 
    29         // 记录日志 
    30         context.log("Filter已经截获到用户的请求的地址: " + hrequest.getServletPath()); 
    31         try { 
    32             // Filter 只是链式处理,请求依然转发到目的地址。 
    33             chain.doFilter(request, response); 
    34         } catch (Exception e) { 
    35             e.printStackTrace(); 
    36         } 
    37         long after = System.currentTimeMillis(); 
    38         // 记录日志 
    39         context.log("过滤结束"); 
    40         // 再次记录日志 
    41         context.log(" 请求被定位到" + ((HttpServletRequest) request).getRequestURI() 
    42                 + "所花的时间为: " + (after - before)); 
    43     } 
    44 } 

    通过上述步骤的操作,此时就可以通过URI进行访问。具体访问后会在log文件中的localhost文件中产生具体的访问日志。如下所示:

    2010-12-28 21:12:50 org.apache.catalina.core.ApplicationContext log
    信息:  请求被定位到/examples/jsp/jsp2/el/basic-arithmetic.jsp所花的时间为: 0
    2010-12-28 21:14:55 org.apache.catalina.core.ApplicationContext log
    信息: Filter已经截获到用户的请求的地址: /jsp/jsp2/el/basic-comparisons.jsp
    2010-12-28 21:14:56 org.apache.catalina.core.ApplicationContext log
    信息: 过滤结束

    相应地,我们还可以自定义"编码的修正"、"用户权限的认证"等的实现类。

    但是,我们开发过程中会出现如下的Filter定义;

    <filter>
            <filter-name>encodingFilter</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <init-param>
                <param-name>encoding</param-name>
                <param-value>UTF-8</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>encodingFilter</filter-name>
            <url-pattern>*.shtml</url-pattern>
        </filter-mapping>

    该Filter的拦截URL是对所有的.shtml请求的拦截;该Filter的实现类,是Spring框架中默认的实现类,这样就为我们节省了自定义实现类的精力。

    2.FilterChain

    上面提到的两个"编码的修正"和"用户权限的认证"的过滤器,前者(EncodingFilter)负责设置编码,后者(SecurityFilter)负责控制权限,服务器会按照web.xml中过滤器定义的先后循序组装成一条链,然后一次执行其中的doFilter()方法。

    程序实现了doFilter()方法,实现该方法就可实现对用户请求进行预处理,也可实现对服务器响应进行后处理——它们的分界线为是否调用了chain.doFilter(),执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理。

    Filter的初始化时对<filter>标签设置的实现类的初始化;多个Filter初始化的顺序是Filter定义的先后顺序,而在一个客户端请求过来触发多个Filter时,Filter的调用是<filter—mapping>定义的先后顺序。FilterChain中的Filter执行遵循栈的设计思想,如Filter1有Filter1Before、Filter1After,Filter2有Filter2Before、Filter2After执行语句块,如果Filter的调用顺序是Filter1、Filter2;则语句的执行顺序为:

    • Filter1Before;
    • Filter2Before;
    • Filter2After;
    • Filter1After;

    实际上Filter和Servlet极其相似,区别只是Filter不能直接对用户生成响应。实际上Filter里doFilter()方法里的代码就是从多个Servlet的service()方法里抽取的通用代码,通过使用Filter可以实现更好的复用。

  • 相关阅读:
    CodeForces 173B Chamber of Secrets spfa
    CodeForces 173A Rock-Paper-Scissors 数学
    Codeforces Gym 100803G Flipping Parentheses 线段树+二分
    Codeforces Gym 100803D Space Golf 物理题
    Codeforces Gym 100803F There is No Alternative 暴力Kruskal
    Codeforces Gym 100803C Shopping 贪心
    《白日梦想家》观后感
    select sum也会返回null值
    mysql update更新带子查询的实现方式
    mysql 添加索引 mysql 如何创建索引
  • 原文地址:https://www.cnblogs.com/yangyabo/p/5955257.html
Copyright © 2011-2022 走看看