过滤器允许你拦截请求,也允许你控制响应。Filter很像Servlet,容器管理过滤器的生命周期。和Servlet类似,过滤器也有init()和destroy()方法,对应于servlet的doGet()/doPost(),过滤器则有一个doFilter()方法。过滤器也需要在DD中声明,过滤器的运行顺序也将在DD中声明。
1.过滤器中的生命周期
首先要有一个inti(),最常见的实现是在inti()中保存一个FilterConfig的引用,以备过滤器以后使用(获取过滤器参数等)。
真正的工作在doFilter()中完成。doFilter方法有3个参数:
一个ServletRequest(不是HttpServletRequest);
一个ServletResponse(不是HttpServletResponse);
一个FilterChain,过滤器并不知道请求所涉及的其他过滤器,但是必须有人知道过滤器执行的顺序,这个人就是FilterChain,它由DD中指定的filter元素驱动。FilterChain的doFilter()方法来调用下一个过滤器或servlet;
最后是destroy(),它在撤销实例之前完成所需要的清理工作。
2.声明和确定过滤器顺序
在DD中配置过滤器时,通常会做3件事:
1)声明过滤器和过滤器参数:
在DD中声明:
使用动态注入的方式声明:
2)将过滤器映射到想要过滤的web资源;
3)组织这些映射,创建过滤器调用顺序;
当多个过滤器映射到一个给定资源时,容器会使用以下规则:
- 先找到与URL模式匹配的所有过滤器,并按照在DD中声明的顺序组成一个链。
- 再找到与<servlet-name>匹配的过滤器,并放在链中。
4)过滤器可以直接应用于直接来之客户的请求,但是如果请求来自于转发、包含、错误处理,过滤器就无法起到作用。servlet 2.4提供了<dispatcher>元素解决这个问题。
3.包装器
servlet API中的包装器功能及其强大,它们为你要包装的东西实现了所需的所有方法,并将所有调用委托给底层的请求或相应对象。你要做的只是扩展某个包装器,如果要在哪些方法中做些特殊的定制工作,只要覆盖这些方法就可以了。包装器类是使用装饰模式的一个典型例子。
创建一个特定版本的请求或响应,这在创建过滤器时实在太常用了。所以Sun创建了4个“便利类”,一边更容易地完成这个任务:
- ServletRequestWrapper
- HttpServletRequestWrapper
- ServletResponseWrapper
- HttpServletResponseWrapper
请求包装器是指利用HttpServletRequestWrapper类将请求中的内容进行统一修改,例如修改请求字符编码、替换字符、权限验证等。
响应包装器是指利用HttpServletResponseWrapper类将相应中的内容进行统一修改,例如压缩输出内容、替换输出内容等。因为HttpServletResponse不能缓存输出内容,所以在doFilter()之后过滤器再想处理输出为时已晚,此时servlet已经直接将输出返回给客户。所以需要自定义一个具备缓存功能的response,这样在doFilter()之后过滤器可以进行输出的处理。