1.Filter概述
Servlet Filter又称Servlet过滤器,它是在Servlet2.3规范中定义的,能够对Servlet容器传给Web资源的request对象和response对象执行检查和修改。
Filter不是Servlet,不能直接访问,其本身也不能生成request对象和response对象,只能为web资源提供以下过滤功能:
(1)在web资源被访问前,检查request对象,修改请求头和请求正文,或对请求执行预处理操作。
(2)将请求传递到下一个过滤器或目标资源。
(3)在web资源被访问后,检查response对象,修改响应头和响应正文。
Filter是Servlet规范中最实用的技术,通过其可对服务器管理的所有web资源(jsp,servlet,html等)拦截,从而实现特殊的功能,例如用户权限控制、过滤敏感词、设置统一编码格式等。
注意:过滤器并不是必须要将请求传递到下一个过滤器或目标资源,可自行对请求处理,并发送响应给客户端,也可以将请求转发或重定向到其他web资源。
2.Filter接口
与开发Servlet需要实现javax.servlet.Servlet接口类似,开发过滤器要实现javax.servlet.Filter接口,并提供一个公开的不带参数的构造方法,在Filter接口中,定义了3个方法,如下所示:
(1)init():该方法用于初始化过滤器。
(2)doFilter():该方法完成实际的过滤操作,当客户端请求的URL与过滤器映射的URL匹配时,容器会先调用该方法对请求进行拦截。
(3)destroy():该方法在销毁Filter对象之前被调用,用于释放被Filter对象占用的资源。
3、Filter的工作流程
(1)客户端请求访问容器内的web资源。
(2)Servlet容器接收请求,并针对本次请求分别创建一个request对象和response对象。
(3)请求到达web资源之前,先调用Filter的doFilter()方法,检查request对象,修改请求头和请求正文,或对请求执行预处理操作。
(4)在Filter的doFilter()方法内,调用FilterChain.doFilter()方法,将请求传递给下一个过滤器或目标资源。
(5)目标资源生成响应信息返回客户端之前,处理控制权会再次回到Filter的foFilte()方法,执行FilterChain.doFilter()后的语句,检查response对象,修改响应头和响应正文。
(6)响应信息返回客户端。
4、Filter生命周期(分为3个阶段)
(1)初始化阶段:
Servlet容器负责加载和实例化Filter。容器启动时,读取web.xml或@WebFilter的配置信息加载和实例化所有过滤器。
加载和实例化完成后,Servlet容器调用init()方法初始化Filter实例。在Filter生命周期内,init()方法只执行一次。
(2)拦截和过滤阶段
这个阶段是Filter生命周期中最重要的阶段。当客户端请求访问web资源时,Servlet容器会根据web.xml或@WebFilter的过滤规则执行检查。当客户端请求的URL与过滤器映射匹配时,容器将该请求的request对象以及FilterChain对象以参数的形式传递给Filter的doFilter()方法,并调用该方法请求/响应拦截和过滤。
(3)销毁阶段
Filter对象创建后会驻留在内存中,直到容器关闭或应用被移除时销毁,销毁Filter对象之前,容器会先调用destory()方法,释放过滤器占用的资源。在Filter生命周期内,destory()只执行一次。
5.注册和映射Filter
(1)通过web.xml配置
元素说明:
<filter>用于注册过滤器
<filter-name>是<filter>元素的子元素,用于指定过滤器的注册名,该元素的内容不能为空。
<filter-class>是<filter>元素的子元素,用于指定过滤器的完整限定名(包名+类名)
<init-param>是<filter>元素中的子元素,用于为过滤器指定初始化参数,它的子元素<param-name>指定参数的名称,<param-value>指定参数的值
<filter-mapping>元素用于设置Filter负责拦截的资源。
<filter-name>是<filter-mapping>元素的子元素,用于设置Filter的注册名,该值必须在<filter>元素的子元素<filter-name>中声明过。
<url-pattern>是<filter-mapping>元素的子元素,用于设置Filter拦截的请求路径。
<servlet-name>是<filter-mapping>元素的子元素,用于指定Filter拦截的资源被Servlet容器调用的方式,可以是REQUEST,INCLUDE,FORWAED和ERROR之一。默认情况是REQUEST。用户可以设置多个<dispatcher>子元素指定Filter对资源的多种调用方式进行拦截。
<dispather>元素的取值及意义:
REQUEST:当用户直接访问页面时,容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问,则该过滤器就不会被调用。
INCLUDE:如果目标资源通过RequestDispatcher的include()方法访问,则该过滤器将被调用,除此之外,该过滤器不会被调用。
ERROR:如果目标资源通过声明式异常处理机制访问,则该过滤器将被调用,除此之外,过滤器不会被调用。
(2)通过@WebFilter注解配置
@WebFilter注解也可配置过滤器,容器在部署应用时,会根据具体属性配置将相应类部署为过滤器。
@WebFilter注解具有下标给出的一些常用属性,但是value,urlPatterns,servletNames三者必须至少包含一个,且value和urlPatterns不能共存,如果同时指定,通常忽略value的取值。
6、过滤器链
在web应用中,可部署多个Filter,若这些Filter都拦截同一目标资源,就组成了一个Filter链,过滤器链中的每个过滤器负责特定操作和任务,客户端请求在各个过滤器减传递,直至传递给目标资源。
FilterChain接口:javax.servlet包中提供了一个FilterChain接口,该接口由容器实现。容器将其实例对象作为参数传入Filter对象的doFilter()方法中。Filter对象可以使用FilterChain对象调用链中下一个Filter的doFilter()方法,若该Filter是链中最后一个过滤器,则调用目标资源的service()方法。FilterChain接口中只有一个方法——doFilter,详细信息如下:
7.Filter链的拦截过程
请求资源时,过滤器链中的过滤器一次对请求处理,并将请求传递给下一个过滤器,直到最后将请求传递给目标资源,发送响应信息时。则按照相反的顺序对相应处理,直到将响应返回给客户端。
注意:过滤器链中的任何一个Filter没有调用FilterChain.doFilter()方法,请求都不会达到目标资源。
8、总结Filter代码编写流程
(1)定义类,实现Filter接口,并重写其所有方法
(2)配置Fiter拦截资源的路径:在类上定义@WebFilter注解或者web.xml文件配置。
(3)在doFilter()方法中设置处理的方法。
具体的代码案例:
<span style="background-color:#f8f8f8"><span style="color:#333333">package Filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/*") //表示拦截所有资源
public class UserSessionFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {Filter.super.init(filterConfig);}
@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("过滤器成功执行!");//放行filterChain.doFilter(servletRequest,servletResponse);
}
@Overridepublic void destroy() {Filter.super.destroy();}
}</span></span>
运行截图: