一、Filter简介:

Filter 的基本功能是对 Servlet 容器调用 Servlet 的过程进行拦截,从而在 Servlet 进行响应处理的前后实现一些特殊的功能。

1. 在servlet被调用之前截获;  

 2. 在servlet被调用之前检查servlet request;  

 3. 根据需要修改request头和request数据;   

 4. 根据需要修改response头和response数据;   

 5. 在servlet被调用之后截获.

二、Filter的工作流程

当一个请求符合某个过滤器的过滤条件时该请求就会交给这个过滤器去处理。那么当两个过滤器同时过滤一个请求时谁先谁后呢?这就涉及到了过滤链FilterChain。        

     所有的奥秘都在Filter的FilterChain中。服务器会按照web.xml中过滤器定义的先后循序组装成一条链,然后一次执行其中的doFilter()方法。执行的顺序就如下图所示,执行第一个过滤器的chain.doFilter()之前的代码,第二个过滤器的chain.doFilter()之前的代码,请求的资源,第二个过滤器的chain.doFilter()之后的代码,第一个过滤器的chain.doFilter()之后的代码,最后返回响应。

 

三、Filter API

在 Servlet API 中定义了三个接口类来开供开发人员编写 Filter 程序:Filter, FilterChain, FilterConfig。

3.1  FilterConfig:

    FilterConfig对象包含了Filter在web.xml中的配置,还包含了servletContext对象(运行环境)。FilterConfig的用法和ServletConfig类似)。利用FilterConfig对象可以得到ServletContext对象,以及部署描述符中配置的过滤器的初始化参数。

3.2  Filter接口:

(1)init():init(FilterConfig filterConfig)throwsServletException

      Filter的实例化和初始化,在服务启动时完成。

  web服务启动的时候,将会根据web.xml中的filter配置信息,来创建每一个Filter实例对象,并保存在内存中。然后立即调用init(),将FilterConfig对象传入。

(2)destroy():

在Web容器卸载 Filter 对象之前被调用。该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。

(3)doFilter(ServletRequest request,ServletResponseresponse,

   FilterChain chain)throwsjava.io.IOException,ServletException:

doFilter()方法类似于Servlet接口的service()方法。当客户端请求目标资源的时候,容器就会调用与这个目标资源相关联的过滤器的 doFilter()方法。

request, response 为 web 容器或 Filter 链的上一个 Filter 传递过来的请求和相应对象。

当特定操作完成以后,会以下面两个方式去处理:

方式一:      

在特定的操作完成后,可以在当前 Filter 对象的 doFilter 方法内部需要调用 FilterChain 对象的 chain.doFilter(request,response)方法才能把请求交付给 Filter 链中的下一个 Filter 或者目标 Servlet 程序去处理。

  方式二:

可以直接向客户端返回响应信息,或者利用RequestDispatcher的forward()和include()方法,以及 HttpServletResponse的sendRedirect()方法将请求转向到其他资源。

3.3  FilterChain接口:

FilterChain接口:代表当前 Filter 链的对象。由容器实现,容器将其实例作为参数传入过滤器对象的doFilter()方法中。过滤器对象使用FilterChain对象调用过滤器链中的下一个过滤器,如果该过滤器是链中最后一个过滤器,那么将调用目标资源。

以下是doFilter()实现的代码片段:

finalclass ApplicationFilterChain implementsFilterChain, CometFilterChain {
  private ApplicationFilterConfig[] filters =
        new ApplicationFilterConfig[0];
  private intpos = 0;
privatevoid internalDoFilter(ServletRequest request,
                                 ServletResponse response){
      //获取下一个Filter
      ApplicationFilterConfig filterConfig =filters[pos++];
     Filterfilter = null;
      filter= filterConfig.getFilter();
      filter.doChain(request,response);
     // do other work
  }


 

四、Filter示例

Filter类:

publicclass TestFilter implements Filter {
 
   @Override
   public void init(FilterConfig filterConfig)throws ServletException {
      System.out.println(filterConfig.getInitParameter("name"));
   }
 
   @Override
   public void doFilter(ServletRequest request,ServletResponse response,
         FilterChain chain)throws IOException, ServletException {
      HttpServletRequest req =(HttpServletRequest) request;
      System.out.println(req.getRemoteAddr());
      HttpServletResponse resp =(HttpServletResponse) response;
      System.out.println("uri="+req.getRequestURI());
      HttpSession session = req.getSession();
      String name = (String)session.getAttribute("name");
      if (name != null){
         System.out.println("filter1");
         chain.doFilter(request, response);
         System.out.println("filter1-end");
      }else{
         resp.sendRedirect("login.jsp");
         return;
      }
     
   }
 
   @Override
   public void destroy() {
      // TODOAuto-generated method stub
     
   }
 
}
 

web.xml的配置:

  

<filter>
    <filter-name>testFilter</filter-name>
    <filter-class>test.TestFilter</filter-class>
    <init-param>
      <param-name>name</param-name>
      <param-value>Christian</param-value>
    </init-param>
    <init-param>
      <param-name>password</param-name>
      <param-value>lili@yaoyao</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>testFilter</filter-name>
    <url-pattern>/testSession</url-pattern>
  </filter-mapping>

 

五、Filter与Servlet

Filter与servlet是密不可分的。Tomcat在接收到一个来自客户端(如浏览器)的请求之后,在这个请求被传递给servlet之前,需要经过层层Filter的过滤。它能够在一个request到达servlet之前预处理request,也可以在离开servlet时处理response。

Filter与servlet是一个层层包裹的关系,如下图:

因此filter的实质就是拦截器(interceptor),它与Spring AOP中的包围通知(MethodInterceptor)类似,层层的包围住servlet。



六、Filter可以解决哪些实际问题?

常见的filter的应用有:权限控制(如Acegi的实现),记录日志,转换编码格式,加密等。

举例:(以下从其他网站上学习的内容)

Filter的典型应用

1.使浏览器不缓存页面的过滤器:

有 3 个 HTTP 响应头字段都可以禁止浏览器缓存当前页面,它们在 Servlet 中的示例代码如下:

response.setDateHeader("Expires",-1);

response.setHeader("Cache-Control","no-cache");

response.setHeader("Pragma","no-cache");

并不是所有的浏览器都能完全支持上面的三个响应头,因此最好是同时使用上面的三个响应头

2.典型应用2

字符编码的过滤器

通过配置参数encoding指明使用何种字符编码,以处理Html Form请求参数的中文问题

具体的实例代码如下:

public voiddoFilter(ServletRequest arg0, ServletResponse arg1,

                     FilterChain arg2) throwsIOException, ServletException {

              // TODO Auto-generated methodstub

             arg0.setCharacterEncoding(“UTF-8”);

              arg2.doFilter(arg0, arg1);

       }

 


Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐