一、过滤器概述
Filter 过滤器是在 Java Servlet 2.3 规范中定义的,Filter 不是 Servlet,不能直接访问,其本身也不能生成 request 对象和 response 对象,只能对 Servlet 容器的请求和响应对象进行检查和修改,即拦截请求和处理响应。
filter工作过程:
- 在 web资源被访问前,检查request对象,修改请求头和请求正文,或对请求进行预处理操作。
- 将请求传递给下一个过滤器或目标资源。
- 在web资源被访问后,检查response对象,修改响应头和响应正文。
注意:过滤器并不是必须要将请求传递到下一个过滤器或目标资源,它可以自行对请求进行处理,并发送响应给客户端,也可以将请求转发或重定向到其他的 Web 资源。
Filter 是 Servlet 规范中最实用的技术,它可以对服务器管理的所有 Web 资源(例如 JSP、Servlet、静态 HTML 文件、静态图片等)进行拦截,从而实现一些特殊的功能,例如用户的权限控制、过滤敏感词、设置统一编码格式等。
根据规范建议的各种类型的过滤器:
- 身份验证过滤器(Authentication Filters)
- 数据压缩过滤器(Data compression Filters)
- 加密过滤器(Encryption Filters)
- 触发资源访问事件过滤器
- 图像转换过滤器(Image Conversion Filters)
- 日志记录和审核过滤器(Logging and Auditing Filters)
- MIME-TYPE 链过滤器(MIME-TYPE Chain Filters)
- 标记化过滤器(Tokenizing Filters)
- XSL/T 过滤器(XSL/T Filters),转换 XML 内容
二、使用
第一步:编写 Java 类实现 javax.servlet.Filter 接口,重写其 doFilter 方法。
public interface Filter {
default void init(FilterConfig filterConfig) throws ServletException {
}
void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException;
default void destroy() {
}
}
Filter 接口定义了三个方法:
方法 | 功能描述 |
void init(FilterConfig filterConfig) | web 服务器在应用程序启动时创建Filter 的实例对象,并调用其 init 方法,读取 web.xml 或 @WebFilter 配置,完成对象的初始化功能,为后续的用户请求作好拦截的准备工作(Filter 对象只会创建一次,init 方法也只会执行一次)。通过 init 方法的参数,可获得代表当前 Filter 配置信息的 FilterConfig 对象 |
void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) | 该方法完成实际的过滤操作,当客户端请求的 URL 与过滤器映射的 URL 匹配时,容器会先调用该方法对请求进行拦截。参数 req 和 resp 表示请求和响应对象。参数 chain 代表当前 Filter 链对象,在该方法内部,调用 chain.doFilter() 方法,才能把请求交付给 Filter 链中的下一个 Filter 或者 Web 资源 |
void destroy() | 该方法在销毁 Filter 对象之前被调用,用于释放被 Filter 对象占用的资源。在 Filter 的生命周期内,destory() 只执行一次 |
如果多个过滤器都拦截同一目标资源,则它们就组成了一个 Filter 链(也称过滤器链),先配置先执行,响应时则以相反顺序执行。
三、配置filter
1.配置文件 web.xml
通过 <filter>
及其子元素注册 Filter
<filter>
<filter-name>XXXXFilter</filter-name>
<filter-class>XX.XX.XXXXFilter</filter-class>
<init-param>
<param-name>name</param-name>
<param-value>value</param-value>
</init-param>
</filter>
- <filter> :注册过滤器
- <filter-name> :指定过滤器的注册名,该元素的内容不能为空
- <filter-class> :指定过滤器的完整限定名(包名+类名)
- <init-param> :为过滤器指定初始化参数,它的子元素 <param-name> 指定参数的名称,<param-value> 指定参数的值
使用 <filter-mapping>
及其子元素映射 Filter
<filter-mapping>
<filter-name>XXXXFilter</filter-name>
<url-pattern>/url</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>XXXXFilter</filter-name>
<servlet-name>XXXXServlet</servlet-name>
</filter-mapping>
- <filter-mapping> :设置 Filter 负责拦截的资源。
- <filter-name> :设置 Filter 的注册名,该值必须在 <filter>元素的子元素<filter-name> 中声明过。
- <url-pattern> :设置 Filter 拦截的请求路径
- <servlet-name> :设置 Filter 拦截的 Servlet 名称
- <dispatcher> :指定 Filter 拦截的资源被 Servlet 容器调用的方式,可以是 REQUEST(请求的)、INCLUDE(包含在页面的)、FORWARD(转发的)、ASYNC(异步的) 和 ERROR(出错的) 之一,默认 REQUEST。用户可以设置多个 <dispatcher> 子元素指定 Filter 对资源的多种调用方式进行拦截
关于 <url-pattern>
<!--通配符* 所有资源:作用于服务器所有路径下的资源-->
<url-pattern>/*</url-pattern>
<!--后缀名匹配:作用于服务器所有的jsp资源-->
<url-pattern>*.jsp</url-pattern>
<!--目录匹配:xxx路径下的所有资源-->
<url-pattern>/xxx/*</url-pattern>
<!--作用于xxx路径下所有的do资源-->
<url-pattern>/xxx/*.do</url-pattern>
<!--匹配某一具体资源-->
<url-pattern>/user/login</url-pattern>
2、注解
@WebFilter
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebFilter {
String description() default "";
String displayName() default "";
WebInitParam[] initParams() default {};
String filterName() default "";
String smallIcon() default "";
String largeIcon() default "";
String[] servletNames() default {};
String[] value() default {};
String[] urlPatterns() default {};
DispatcherType[] dispatcherTypes() default {DispatcherType.REQUEST};
boolean asyncSupported() default false;
}
@WebFilter 注解具有以上共 11 个属性,其中下图 9 个为常用属性,均为可选属性,但 value、urlPatterns、servletNames 三者必需至少包含一个,且 value 和 urlPatterns 不能共存,如果同时指定,通常忽略 value 的取值
@WebFilter(filterName = "XXXXFilter",
urlPatterns = "/*",
initParams = {
@WebInitParam(name = "name", value = "value")
})
执行顺序:
- 只使用 web.xml 时,由<filter-mapping>配置顺序决定,越靠前越先执行
- 只使用注解时,由 filterName字母顺序决定,例如 AFilter 会比 BFilter 先执行
- 配置文件和注解同时使用,web.xml 先于 @WebFilter
- 对 request 的过滤,代码放在 chain.doFilter() 之前,response 则在其后
四、filter生命周期
- 先执行Filter的构造方法
- 然后执行Filter的init()方法,对象创建后,马上就被调用,对Filter做一些初始化操作
- 执行Filter的doFilter()方法,每次访问目标资源,只要匹配过滤的地址,就会调用。
- 执行Filter的destroy()方法,服务器停止时调用,用来释放资源。