Filter是在web.xml中另外一个常用的配置项,可以通过<filter>和<filter-mapping>组合起来使用Filter。实际上Filter可以完成与Servlet同样的工作,甚至比Servlet使用起来更加灵活,因为它除了提供了request和response对象外,还提供了一个FilterChain对象,可以让我们更加灵活地控制请求的流转。
过滤器
过滤器的功能
过滤器能够对Servlet容器传给Web组件的ServletRequest对象和ServletResponse对象进行检查和修改。过滤器本身并不生成ServletRequest对象和ServletResponse对象,它只为Web组件提供如下过滤功能:
- 过滤器能够在Web组件被调用之前检查ServletRequest对象,修改请求头和请求正文的内容,或者对请求进行预处理操作
- 过滤器能够在Web组件被调用之后检查ServletResponse对象,修改响应头和响应正文
- 过滤器可以检查ServletRequest和ServletResponse对象,并利用ServletRequestWrapper和ServletResponseWrapper包装类来修改ServletRequest和ServletResponse对象
- 可以在web.xml文件中为过滤器映射特定的url-pattern,当客户请求访问此URL时,Servlet容器就会先触发过滤器工作
- 多个过滤器可以被串联在一起,协同为Web组件过滤请求对象和响应对象
- 过滤器过滤的Web组件可以是Serlvet,JSP或HTML文件
创建过滤器
所有自定义的过滤器都必须实现:
javax.servlet.Filter
这个接口。
这个接口包含3个过滤器必须实现的方法:
- init(FilterConfig config) —— 在Web应用启动时,Servlet容器先创建包含了过滤器配置信息的FilterConfig对象,然后创建Filter对象,接着调用Filter对象的Init(FilterConfig)方法,在这个方法中可以通过config参数来读取web.xml文件中为过滤器配置的初始化参数
- doFilter(ServletRequest req, ServletResponse res, FilterChain chain) —— 完成实际的过滤操作;当客户请求访问的URL与过滤器映射的URL匹配时,Servlet容器将先调用过滤器的doFilter方法。FilterChain参数用于访问后续过滤器或者Web组件(Servlet);
- 如果希望执行后续的Filter或Servlet,必须在doFIlter中显式调用chain.doFilter()方法:
doFilter(ServletRequest req, ServletResponse res, FilterChain chain){
Code1;
chain.doFilter(req, res); // 如果希望执行后续的filter或者servlet必须执行这个方法;
Code2;
}
- destroy() —— Servlet容器在销毁过滤器对象前调用
过滤器由Servlet容器创建。
发布过滤器
发布过滤器时,必须在web.xml文件中加入<filter>元素和<filter-mapping>元素。
<filter>
<filter-name>过滤器名</filter-name>
<filter-class>过滤器类名</filter-class>
<init-param>
<param-name>参数名1</param-name>
<param-value>参数值1</param-value>
</init-param>
<init-param>
<param-name>参数名2</param-name>
<param-value>参数值2</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>过滤器名</filter-name>
<url-pattern>URL</url-pattern>
</filter-mapping>
当客户请求的URL和<url-pattern>指定的URL匹配时,Servlet容器就会先调用过滤器的doFilter方法。
如果希望过滤器能为所有的URL过滤,那么可以把<url-pattern>的值设为“/*”,这样,当客户请求访问Web应用中的任何一个Web组件时,Servlet容器都会先把请求转发给过滤器。
在web.xml文件中,必须先配置所有过滤器,再配置Servlet。
串联过滤器
多个过滤器可以串联起来协同工作,Servlet容器将根据它们在web.xml中定义的先后顺序,依次调用它们的doFilter方法。
例如,有两个过滤器串联起来,它们的doFilter()方法均采用如下结构:
在过滤器中修改请求和响应信息
如果要在过滤器中改写请求/响应信息,可以创建一个HttpServletRequest/HttpServletResponse的包装类,可以直接继承自HttpServletRequestWrapper/HttpServletResponseWrapper类,并覆盖其中的部分方法,再由过滤器把这个包装类的对象传给后续的Web组件。
public class MyResponseWrapper extends HttpServletResponseWrapper{
... ...
public MyResponseWrapper(ServletResponse res){
super((HttpServletResponse)res);
... ...
}
}
public class MyFilter implements Filter{
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
... ...
MyResponseWrapper myResWrapper = new MyResponseWrapper(response);
... ...
chain.doFilter(request, myResWrapper);
... ...
}
}