1 过滤器概述
当web容器接收到对一个资源的请求时,它将判断是否有过滤器与这个资源相关联,如果有,那么容器将把这个请求交给过滤器进行处理。在过滤器中,你可以改变请求的内容或者重新设置请求的报头信息,然后再将请求发送给目标资源。当目标资源对请求作出响应时,容器同样会将响应先转发给过滤器,在过滤器中,你可以对响应的内容进行转换,然后再将响应发送给客户端。从此过程中可以看出,客户端和目标资源并不需要知道过滤器的存在,也就是说,在web应用中部署过滤器,对客户端和目标资源是透明的。
在web应用中,你可以部署多个过滤器,这些过滤器组成过滤器链,过滤器链中的每一个过滤器负责特定的操作和任务,客户端的请求在这些过滤器之间传递,直到目标资源。
在请求资源时,过滤器链中的过滤器将依次对请求进行处理,并将请求传递给下一个过滤器,直到目标资源,在发送响应时,则按照相反的顺序对响应进行处理,直到客户端。
如图所示,由多个过滤器组成的过滤器链。
过滤器并不是必须要将请求传递给下一个过滤器(或者目标资源),它也可以自行处理请求,然后发送响应给客户端,或者将请求发送给另外一个目标资源。
过滤器在web开发的一些主要应用:
1)对用户请求进行统一认证
2)对用户的访问请求进行记录和审核
3)对用户发送的数据进行过滤或者替换
4)对响应内容进行压缩,减少传输容量
5)对请求和响应进行加解密处理
6)触发资源访问事件
2 Filter API
与过滤器开发相关的接口和类都包含在javax.servlet或者javax.servlet.http包中,主要有:
javax.servlet.Filter接口
javax.servlet.FilterConfig接口
javax.servlet.FilterChain接口
javax.servlet.ServletRequestWrapper类
javax.servlet.ServletResponseWrapper类
javax.servlet.http.HttpServletRequestWrapper类
javax.servlet.http.HttpServletResponseWrapper类
1)Filter接口
开发过滤器要实现该接口,并提供一个公共的不带参数的构造方法。
该接口的方法:
public abstract void init(FilterConfig filterconfig)throws ServletException;
web容器调用该方法初始化过滤器,容器在调用该方法时,向过滤器传递FiterConfig对象,FiterConfig对象的用法和ServletConfig类似。利用FilterConfig对象可以得到ServletContext对象,以及在配置文件配置的过滤器的初始化参数,这个方法可以抛出ServletException异常,通知容器过滤器不能正常工作。
public abstract void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain)throws IOException, ServletException;
doFilter()方法类似于Servlet中service()方法。当客户端请求目标资源时,容器就会调用与这个目标资源相关联的过滤器的doFilter()方法。在这个方法里,可以对请求和响应进行处理。在实现特定的操作后,可以调用chain.doFilter(request,response)将请求传给下一个过滤器,也可以直接向客户端返回响应,或者利用RequestDispatcher的forward()和include()方法,以及HttpServletResponse的sendRedirect()方法将请求转向其他资源。这个方法的请求和响应参数是ServletRequest ServletResponse ,也就是说,过滤器的使用并不依赖于具体的协议。
public abstract void destroy();
web容器调用该方法表示过滤器的生命周期结束,在这个方法中,可以释放过滤器使用的资源,
与Servlet不同的是,Filter接口并没有相应的实现类可供继承,要开发过滤器,只能实现Filter接口。
2)FilterConfig接口
类似于ServletConfig接口,用于在过滤器初始化时向其传递信息。
FilterConfig接口由容器实现,容器将其实例作为参数传入过滤器对象的init()方法中
在FilterConfig接口中,定义了四个方法:
public abstract String getFilterName(); 以字符串形式返回在web.xml中配置的Filter的名字
public abstract ServletContext getServletContext(); 返回Servlet上下文对象的引用
public abstract String getInitParameter(String s); 返回在web.xml中指定名字为s的初始化参数的值
public abstract Enumeration getInitParameterNames(); 返回过滤器的所有初始化参数名字的枚举集合,如果没有初始化参数,返回一个空的枚举集合。
3)FilterChain接口
该接口由容器实现,容器将其作为参数传入过滤器对象的doFilter()方法中。过滤器对象使用FiterChain对象调用过滤器链中的下一个过滤器。
如果此过滤器是链中的最后一个过滤器,那么将调用目标资源。
FilterChain接口只有一个方法:
public abstract void doFilter(ServletRequest servletrequest, ServletResponse servletresponse)throws IOException, ServletException;
3 过滤器在web.xml中的配置
在实现一个过滤器后,需要在web.xml进行配置,这是通过和元素来完成的
1)filter元素
其中 元素的作用是相同的。
元素用于指定过滤器的名字,该元素的内容不能为空。元素指定过滤器的完整的限定类名。
元素用于为过滤器指定初始化参数,它的子元素指定参数的名字,指定参数的值,在过滤器中可以使用FilterConfig对象获取这些初始化参数
注意:
1 、Servlet容器对在web.xml中配置的每一个过滤器,只创建一个实例。
2 、 与Servlet相似,容器将在同一个过滤器实例上运行多个线程来同时为多个请求服务,因此开发过滤器时,也应该注意线程安全的问题。
3 、如果在web.xml中,对同一个过滤器类声明了两次,那么容器会创建两个相同的过滤器类的实例。
2)filter-mapping元素
元素用于指定过滤器关联的URL或者Servlet。元素的结构:
注意:
Servlet2.5规范允许和元素出现多次,之前的规范只允许一个元素包含一个或者一个子元素。
如:
DemoFilter
/demo/*
Servlet1
Servelt2
/test/*
此外,Servlet2.5规范还允许为元素指定*号,来匹配所有的Servlet。
AllDispather
*
FORWARD
元素结构解析:
其中子元素的值必须是在元素中声明过的过滤器的名字。
元素和元素可以选择一个,元素指定过滤关联的URL样式,元素指定过滤器对应的Servlet。用户在访问元素指定的URL上的资源或者元素指定的Servlet时,该过滤器才会被容器调用。
还可以包含0到4个元素,元素指定过滤器对应的请求方式,可以是REQUEST INCLUDE FORWARD ERROR四种之一或者多种,默认是REQUEST。
REQUEST:当用户直接访问页面时,web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或者forward()方法访问时,那么该过滤器将不会被调用。
INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用,除此之外,过滤器不会被调用。
FORWARD:如果目标资源时通过ResquestDispatcher的forward()方法访问时,那么该过滤器将会被调用,除此之外,过滤器不会被调用。
ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
例如:
1)
bookFilter
/process.jsp
当用户访问process.jsp时,容器会调用bookFilter过滤器
2)
bookFilter
/index.jsp
REQUEST
FORWARD
当用户直接访问index.jsp页面时,或者通过RequestDispatcher的forward()方法访问时,容器会调用bookFilter过滤器。