Java中过滤器(Filter)的工作原理和代码演示『责任链模式』

一、Filter简介

Filter也称之为过滤器,它是WEB开发人员通过Filter技术,对web服务器管理的所有web资源:

例如  Jsp,Servlet, 静态图片文件静态html文件等进行拦截,从而实现一些特殊的功能。

例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等

一些高级功能。
  Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter
技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截,Filter接口源代码:
[java]  view plain  copy
  1. public abstract interface Filter{  
  2.     public abstract void init(FilterConfig paramFilterConfig) throws ServletException;  
  3.     public abstract void doFilter(ServletRequest paramServletRequest, ServletResponse paramServletResponse, FilterChain   
  4.         paramFilterChain) throws IOException, ServletException;  
  5.     public abstract void destroy();  
  6. }  

二、Filter的工作原理(实现拦截)

        Filter接口中有一个doFilter方法,在编写好Filter,且配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:
    调用目标资源之前,让一段代码执行。
    是否调用目标资源(即是否让用户访问web资源)。

    调用目标资源之后,让一段代码执行。

arg0.setCharacterEncoding(encoding);

                            arg2.doFilter(arg0,arg1);//在这句之前的处理就是前置处理,在这句之后的处理就是后置处理

arg1.setCharacterEncoding(encoding);                       

概念:     FilterChain--过滤链

 web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个

doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,
否则web资源不会被访问

三、 Filter开发流程

(1)  Filter开发分为2步:
 * 编写java类实现Filter接口,并实现其doFilter方法。

 * 在web.xml 文件中使用<filter>和<filter-mapping>元素对编写的filter类进行注册,并设置它所能拦截的资源。

1、定义过滤器类  直接或者间接实现Filter接口的类

         publicclass EncoderFilter implements Filter {

                   privateString encoding = "UTF-8";

                  //在Filter对象创建完毕后立即执行,且只执行一次,主要用于获取配置参数

                   publicvoid init(FilterConfig config) throws ServletException {

                            Stringss = config.getInitParameter("encoding");

                            if(ss != null && ss.trim().length() > 0)

                                     encoding= ss.trim();

                   }

                                       //在Filter对象销毁之前执行,一般用于资源回收

                   publicvoid destroy() {

                            System.out.println("销毁filter对象");

                   }

                                      //满足条件后执行的处理逻辑

                   publicvoid doFilter(ServletRequest arg0, ServletResponse arg1,

                                     FilterChainarg2) throws IOException, ServletException {

                                        //filterChain对象提供了一个方法doFilter,表示继续向后执行下一个节点

                            arg0.setCharacterEncoding(encoding);

                            arg2.doFilter(arg0,arg1);//在这句之前的处理就是前置处理,在这句之后的处理就是后置处理

arg1.setCharacterEncoding(encoding);

                   }

         }

  2、在web.xml中配置过滤器生效的条件--不是访问路径

   <welcome-file-list> 

       <welcome-file>index.jsp</welcome-file> 

  </welcome-file-list> 

  <!--配置过滤器--> 

      <filter> 

         <filter-name>FilterTest</filter-name> 

         <filter-class>com.yangcq.filter.FilterTest</filter-class> 

      </filter> 

  <!--映射过滤器--> 

  <filter-mapping> 

         <filter-name>FilterTest</filter-name> 

 <!--“/*”表示拦截所有的请求 --> 

         <url-pattern>/*</url-pattern> 

  </filter-mapping> 

</web-app>

(2) Filter链
   在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链。web服务器根据Filter在web.xml文件中的注册顺序,
决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter
方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个filter,
如果没有,则调用目标资源。

四,Spring框架下,过滤器的配置
    如果项目中使用了Spring框架,那么,很多过滤器都不用自己来写了,Spring为我们写好了一些常用的过滤器。下面我们就以字符编码的
过滤器CharacterEncodingFilter为例,来看一下Spring框架下,如何配置过滤器。

<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> 

   <init-param> 

       <param-name>forceEncoding</param-name> 

       <param-value>true</param-value> 

   </init-param> 

</filter> 

<filter-mapping> 

   <filter-name>encodingFilter</filter-name> 

   <url-pattern>/*</url-pattern> 

</filter-mapping>

接下来,我们看一下CharacterEncodingFilter这个过滤器的关键代码:

public classCharacterEncodingFilter extends OncePerRequestFilter{ 

    private static final booleanresponseSetCharacterEncodingAvailable = ClassUtils.hasMethod( 

       class$javax$servlet$http$HttpServletResponse,"setCharacterEncoding", new Class[] { String.class }); 

    // 需要设置的编码方式,为了支持可配置,Spring把编码方式设置成了一个变量 

    private String encoding; 

    // 是否强制使用统一编码,也是为了支持可配置 

    private boolean forceEncoding; 

    // 构造器,在这里,Spring把forceEncoding的值默认设置成了false 

    public CharacterEncodingFilter(){ 

        this.forceEncoding = false; 

    } 

    // encoding/forceEncoding的setter方法 

    public void setEncoding(String encoding){ 

        this.encoding = encoding; 

    } 

    public void setForceEncoding(booleanforceEncoding){ 

        this.forceEncoding =forceEncoding; 

    } 

    // Spring通过GenericFilterBean抽象类,对Filter接口进行了整合, 

    protected void doFilterInternal(HttpServletRequestrequest, HttpServletResponse response, FilterChain filterChain) 

        throws ServletException,IOException{ 

        if ((this.encoding != null) &&(((this.forceEncoding) || (request.getCharacterEncoding() == null)))) { 

            request.setCharacterEncoding(this.encoding); 

            if ((this.forceEncoding) &&(responseSetCharacterEncodingAvailable)) { 

               response.setCharacterEncoding(this.encoding); 

            } 

        } 

        filterChain.doFilter(request,response); 

    } 

}







猜你喜欢

转载自blog.csdn.net/xiaonan_it/article/details/80819541