首页 > 代码库 > Filter基础
Filter基础
一、概要
简单的说,Filter的作用就是拦截Tomcat的service(Request,Response)方法,拿到Request、Response对象进行处理,然后释放控制,继续自动流转。其运用的还是“分层”的思想。
至于为什么要加入这一层,为什么要对Request、Response对象进行拦截,个人感觉根本原因是为了对多个服务器资源(Servlet、JSP等)的请求、相应进行一些公共的设置,这里强调的是“多个”。如果是一个资源,就没有设置Filter的必要,因为只需要在这个资源需要的地方(之前)设置Request、Response即可,也就是“设置”放到哪里都可以,因为很多请求、响应有很多共同的设置,所以将共同之处抽出来作为一层,就是所谓的Filter。作用如下图:
传统调用:
加上Filter:
二、FilterChain
当几个Servlet有一些相同的设置(过滤),而另几个Servlet有其它相同的设置……,这样一个Filter是不能完成所有的过滤,所以就需要多个Filter协作来共同完成这项任务。于是著名的FilterChain就出来了。那么这个FilterChain中的多个Filter是如何协作的呢?
每个Filter的职能不同,当一个Servlet的请求到达后,这个请求就会沿着这条Filter链,一个一个走过,走到它需要的Filter时,这个Filter就会进行对它的Request、Response进行操作,完毕后自动向下流转。这就是所谓的职责链模式。
每个Filter有3个方法:
? init(FilterConfig filterConfig)
? doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
? destroy()
三个方法(下面进行详细介绍)依次执行,一个Filter链中的多个Filter的执行顺序如下图:
即:执行第一个过滤器的chain.doFilter()之前的代码---->第二个过滤器的chain.doFilter()之前的代码---->……---->第n个过滤器的chain.doFilter()之前的代码---->所请求servlet的service()方法中的代码——>所请求servlet的doGet()或doPost()方法中的代码---->第n个过滤器的chain.doFilter()之后的代码---->……---->第二个过滤器的chain.doFilter()之后的代码---->第一个过滤器的chain.doFilter()之后的代码。
三、主要接口与方法
首先Servlet过滤器API包含了3个接口,它们都在javax.servlet包中,分别是Filter接口、FilterChain接口和FilterConfig接口。使用:
? 所有的过滤器都必须实现Filter接口。该接口定义了init(),doFilter(),destory()三个方法。
? FilterChain接口作为了doFilter0方法的参数: doFilter(ServletRequest request, ServletResponse response,FilterChain chain)
? FilterConfig接口作为了init()方法的参数: init(FilterConfig filterConfig)
也就是,过滤器类将实现Filter接口,然后使用这个过滤器类中的FilterChain和FilterConfig接口。该过滤器类的—个引用将传递给FilterChain对象,以允许过滤器把控制权传递给链中的下一个资源。FilterConfig对象将由容器提供给过滤器,以允许访问该过滤器的初始化数据。下面对3个接口与所包含的方法进行简要介绍:
Filter接口
1) public void init (FilterConfig filterConfig) throws ServletException.
当开始使用servlet过滤器服务时,Web容器调用此方法一次,为服务准备过滤器;即通过FilterConfig对象拿到过滤器的初始化参数,即配置文件中配置的信息。然后在需要使用过滤器的时候调用doFilter(),并传递配置信息。
2) public voiddoFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
每个过滤器都接受当前的请求和响应,且FilterChain过滤器链中的过滤器(应该都是符合条件的)都会被执行。doFilter方法中,过滤器可以对请求和响应做它想做的一切,通过调用他们的方法收集数据,或者给对象添加新的行为。
过滤器通过传送至此方法的FilterChain参数,调用chain.doFilter()将控制权传送给下一个过滤器。当这个调用返回后,过滤器可以在它的 Filter方法的最后对响应做些其他的工作。如果过滤器想要终止请求的处理或得到对响应的完全控制,则可以不调用下一个过滤器,而将其重定向至其它一些页面。当链中的最后一个过滤器调用chain.doFilter()方法时,将运行最初请求的Servlet。
3) public voiddestroy()
如果doFilter()法里的所有线程退出或已超时,容器调用此方法。服务器调用destory()以指出过滤器已结束服务,用于释
放过滤器占用的资源。
FilterChain接口
1) public voiddoFilter(ServletRequest request,ServletResponse response) throws java.io.IOException,ServletException
此方法是由Servlet容器提供给开发者的,用于对资源请求过滤链的依次调用,通过FilterChain调用过滤链中的下一个过滤 器,如果是最后一个过滤器,则下一个就调用目标资源。
FilterConfig接口
FilterConfig接口检索过滤器名、初始化参数以及活动的Servlet上下文。
1) public java.lang.StringgetFilterNam()
2) public ServletContext getServletContex()
3) public java.lang.String getlnitParameter(java.lang.String name)
4) public java.util.EnumerationgetlnitParameterNames()
四、配置使用
过滤器通过Web应用程序中的配置描述符web.xml文件中的明,包括部分<filter>、<filter-mapping>:
<filter>,主要包括:
1) <filter-name>和<f‘flter-class>两个必须的子元素
2) <icon>、<init-param>,<display-name>,<description>这4个可选的子元素。
<filter-name>子元素定义了—个过滤器的名字,<filter-class>指定了由容器载入的实际类,<init-param>子元素为过滤器提供初始化参数。
<filter-mapping>主要由
1) <filter-name>,<servlet-name>和<url-pattem>子元素组成。
<servlet-name>将过滤器映射到一个或多个Servlet上,<url-pattem>将过滤器映射到—个或多个任意特征的URL的JSP页面。
<url-pattem>的4种配置方式:
<filter> <filter-name>CharsetEncodingFilter</filter-name> <filter-class>com.bjpowernode.drp.util.filter.CharsetEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>GBK</param-value> </init-param> </filter> <!--精确匹配,不采用任何修饰符 --> <filter-mapping> <filter-name>CharsetEncodingFilter</filter-name> <url-pattern>/servlet/TestServlet</url-pattern> </filter-mapping> <!--扩展匹配,由*号和扩展名组成 --> <filter-mapping> <filter-name>CharsetEncodingFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping> <!--路径前缀匹配,包含一个目录和一个/* --> <filter-mapping> <filter-name>CharsetEncodingFilter</filter-name> <url-pattern>/servlet/*</url-pattern> </filter-mapping> <!--全匹配,使用/* --> <filter-mapping> <filter-name>CharsetEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
五、代码示例:
Filter类:
package com.bjpowernode.drp.util.filter;import java.io.IOException;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import org.omg.CORBA.Request;/** * 采用Filter同意处理字符集 * @author v-wangzhip */public class CharsetEncodingFilter implements Filter { private String encoding; @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //System.out.println("CharsetEncodingFilter---->begin"); //设置字符集 request.setCharacterEncoding(encoding); //继续向下执行 chain.doFilter(request, response); //System.out.println("CharsetEncodingFilter---->end"); } @Override public void init(FilterConfig filterConfig) throws ServletException { this.encoding=filterConfig.getInitParameter("encoding"); System.out.println("encoding---->"+ encoding); }}
Web.xml配置:
<filter> <filter-name>CharsetEncodingFilter</filter-name> <filter-class>com.bjpowernode.drp.util.filter.CharsetEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>GBK</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharsetEncodingFilter</filter-name> <url-pattern>*.jsp</url-pattern> </filter-mapping> <filter-mapping> <filter-name>CharsetEncodingFilter</filter-name> <url-pattern>/servlet/*</url-pattern> </filter-mapping>
六、总结
个人感觉,Filter是将多个请求-响应中公共的需要设置的东西提出来插入到请求-响应之间的一个中间层。多个Filter组成一个FilterChain,每个Filter有自己的职能,能按照一定规则来处理到达的请求和响应,体现了职责链模式。Filter只对post请求起作用,它提供了一种声明式服务,具有可插拔能力,即可以随意开启和关闭。
Filter基础