过滤器
五更疏欲断,一树碧无情。
李商隐·《蝉》
一、过滤器
类似Servlet,过滤器也是一个Java组件。请求发送至Servlet之前,可以用过滤器截获和处理请求;Servlet结束工作之后,在响应发回给客户之前,也可以用过滤器处理响应。
过滤器主要的任务:
- 请求过滤器:
- 完成安全检查
- 重新格式化请求首部或体
- 建立请求审计或日志
- 响应过滤器:
- 压缩响应流
- 追加或修改响应流
- 创建一个完全不同的响应
二、建立过滤器
2.1 代码
public class MyFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
}
public void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain) throws ServletException,IOException {//取常规的ServletRequest和ServletResponse做参数
HttpServletRequest httpReq = (HttpServletRequest) req;//强制转换为响应的Http子类型
HttpServletResponse httpResp = (HttpServletResponse) resp;
chain.doFilter(httpReq, httpResp);//接下来要调用的过滤器或Servlet
}
public void destroy() {
}
}
注:
不像监听器有许多接口,过滤器接口只有一个,即Filter
2.2 三个重要方法
每个过滤器必须实现Filter接口中的三个方法:init()、doFilter()和destroy()。
- init():该方法中完成调用过滤器之前的初始化工作
- doFilter():过滤器的主要工作在该方法中实现
- destroy():删除一个过滤器实例时,在该方法中完成一些清理工作
2.3 FilterChain
- 过滤器可以链在一起,一个接一个的运行(运行顺序由DD控制),过滤器的链尾将执行Servlet
- FilterChain:过滤器并不知道请求所涉及的其他过滤器,但是必须要有一个人知道过滤器执行的顺序才行,这个人就是FilterChain,它由DD中指定的filter元素驱动。FilterChain通过doFilter()方法可以调用一个过滤器或一个Servlet(取决于是否到达链尾)
- doFilter():该方法负责明确接下来调用谁的doFilter()方法(如果到了链尾,则是确定调用哪个Servlet的service()方法)
三、可入栈
Servlet规范并没有明确指定容器如何处理doFilter()方法,不过根据过滤器相互链接的过程,可以认为它们是栈上的方法调用(实际可能不存在这么一个物理栈)。
例如,对MyServlet的请求经过两个过滤器:一个FilterA,一个FilterB。则其出入栈过程如下:
四、声明和确定过滤器顺序
Web应用中可以有很多过滤器,要运行哪些过滤器以及运行的顺序都需要在DD中配置。
4.1 声明过滤器
<filter>
<filter-name>myFilter</filter-name>
<filter-class>MyFilter</filter-class>
<init-param>
<param-name>LogName</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>LogPassWord</param-name>
<param-value>root</param-value>
</init-param>
</filter>
- 必须有< filter-name >和< filter-class >
- < init-param >是可选的,可以有多个
4.2 声明对应URL模式的过滤器映射
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>*.html</url-pattern>
</filter-mapping>
- 必须有< filter-name >,用于链接到适当的< filter >元素
- < url-pattern >元素定义了哪些Web应用资源要使用这个过滤器
4.3 声明对应Servlet名的过滤器映射
<filter-mapping>
<filter-name>myFilter</filter-name>
<servlet-name>myServlet</servlet-name>
</filter-mapping>
- < servlet-name >定义了哪个Web应用资源要使用这个过滤器
- < url-pattern >、< servlet-name >二者之中必须有一个
4.4 为通过请求分派请求的Web资源声明一个过滤器映射
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>*.html</url-pattern>
<dispatcher>REQUEST</dispatcher>
和/或
<dispatcher>INCLUDE</dispatcher>
和/或
<dispatcher>FORWARD</dispatcher>
和/或
<dispatcher>ERROR</dispatcher>
</filter-mapping>
1.REQUEST表示对客户请求启用过滤器,如果没有指定< dispatcher >元素,默认为REQUEST
2. INCLUDE表示对由一个include()调用分派来的请求启用过滤器
3. FORWARD表示对由一个forward()调用分派来的请求启用过滤器
4. ERROR表示对错误处理器调用的资源启用过滤器
- 必须要有< filter-name >
- 必须要有< url-pattern >或< servlet-name >其中之一
- 可以有0~4个< dispatcher >元素
4.5 过滤器顺序的确定
当多个过滤器映射到同一个给定资源时,会按照以下规则确定顺序:
- 先找到与URL模式匹配的所有过滤器,并按照DD中声明的顺序放入链中
- 把所有与URL匹配的所有过滤器放入链中后,找到与匹配的所有过滤器,并按照DD中声明的顺序放入链中