JSP Filters(过滤)
Filter是拦截Request请求的对象:在用户的请求访 问资源前处理ServletRequest以及ServletResponse,它可 用于日志记录、加解密、Session检查、图像文件保护 等。通过Filter可以拦截处理某个资源或者某些资源。 Filter的配置可以通过Annotation或者部署描述来完成。 当一个资源或者某些资源需要被多个Filter所使用到, 且它的触发顺序很重要时,只能通过部署描述来配置。
一.Filter API
1. Filter 相关接口,包含Filter, FilterConfig, FilterChain
Filter的实现必须继承javax.servlet.Filter接口。这个 接口包含了Filter的3个生命周期:init、doFilter、 destroy。
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。Servlet容器初始化Filter时,会触发Filter的init方 法,一般来说是在应用开始时。也就是说,init方法并 不是在该Filter相关的资源使用到时才初始化的,而且 这个方法只调用一次,用于初始化Filter。init方法的定 义如下:
oid init(FilterConfig filterConfig)
注意: FilterConfig实例是由Servlet容器传入init方法中的.
当Servlet容器每次处理Filter相关的资源时,都会调 用该Filter实例的doFilter方法。Filter的doFilter方法包含 ServletRequest、ServletResponse、FilterChain这3个参 数。
doFilter的定义如下:
void doFilter(ServletRequest request, ServletResponse response,FilterChain filterChain)
接下来,说明一下doFilter的实现中访问 ServletRequet、ServletResponse。这也就意味着允许给 ServletRequest增加属性或者增加Header。当然也可以修 饰ServletRequest或者ServletRespone来改变它们的行 为。
在Filter的doFilter的实现中,最后一行需要调用 FilterChain中的doFilter方法。注意Filter的doFilter方法 里的第3个参数,就是filterChain的实例:
filterChain.doFilter(request, response)
一个资源可能需要被多个Filter关联到(更专业一 点来说,这应该叫作Filter链条),这时Filter.doFilter() 的方法将触发Filter链条中下一个Filter。只有在Filter链 条中最后一个Filter里调用的FilterChain.doFilter(),才会 触发处理资源的方法。
如果在Filter.doFilter()的实现中,没有在结尾处调 用FilterChain.doFilter()的方法,那么该Request请求中 止,后面的处理就会中断。
注意: FilterChain接口中,唯一的方法就是doFilter。该方法与Filter中的 doFilter的定义是不一致的:在FilterChaing中,doFilter方法只有两个参 数,但在Filter中,doFilter方法有三个参数。
Filter接口中,最后一个方法是destroy,它的定义 如下:
Void destroy()
该方法在Servlet容器要销毁Filter时触发,一般在应 用停止的时候进行调用。
除非Filter在部署描述中被多次定义到,否则Servlet 窗口只会为每个Filter创建单一实例。由于Serlvet/JSP的 应用通常要处理用户并发请求,此时Filter实例需要同 时被多个线程所关联到,因此需要非常小心地处理多线 程问题。
2. Filter配置
当完成Filter的实现后,就可以开始配置Filter了。 Filter的配置需要如下步骤:
- 确认哪些资源需要使用这个Filter拦截处理。
- 配置Filter的初始化参数值,这些参数可以在Filter的 init方法中读取到;
- 给Filter取一个名称。一般来说,这个名称没有什么 特别的含义,但在一些特殊的情况下,这个名字十 分有用。例如,要记录Filter的初始化时间,但这个 应用中有许多的Filter,这时它就可以用来识别Filter 了。
FilterConfig接口允许通过它的getServletContext的 方法来访问ServletContext:
ServletContext getServletContext(
如果配置了Filter的名字,在FilterConfig的 getFilterName中就可以获取Filter的名字。getFilterName 的定义如下:
java.lang.String getFilterName()
当然,最重要的还是要获取到开发者或者运维给 Filter配置的初始化参数。为了获取这些初始化参数, 需要用到FilterConfig中的两个方法,第一个方法是 getParameterNames:
java.util.Enumeration<java.lang.String> getInitParameterNames()
这个方法返回Filter参数名字的Enumeration对象。 如果没有给这个Filter配置任何参数,该方法返回的是 空的Enumeration对象。
第二个方法是getParameter:
java.lang.String getInitParameter(java.lang.String parameterName)
有两种方法可以配置Filter:一种是通过WebFilter 的Annotation来配置Filter,另一种是通过部署描述来注 册。使用@WebFilter的方法,只需要在Filter的实现类 中增加一个注解即可,不需要重复地配置部署描述。当 然,此时要修改配置参数,就需要重新构建Filter实现 类了。换句话说,使用部署描述意味着修改Filter配置 只要修改一下文本文件就可以了。
使用@WebFilter,你需要熟悉下表中所列出来的 参数,这些参数是在WebFilter的Annotation里定义的。 所有参数都是可选的。
属性 | 描述 |
asyncSupported | Filter是否支持异步操作 |
description | Filter的描述 |
dispatcerTypes | Filter所生效范围 |
displayName | Filter的显示名 |
filterName | Filter的名称 |
initParams | Filter的初始化参数 |
largeIcon | Filter的大图名称 |
servletName | Filter所生效的Servlet名称 |
smallIcon | Filter的小图名称 |
urlPatterns | Filter所生效的URL路径 |
value | Filter所生效的URL路径 |
3. 示例1: 日志 Filter
作为第1个例子,将做一个简单的Filter:在app09a 的应用中把Request请求的URL记录到日志文本文件 中。日志文本文件名通过Filter的初始化参数来配置。 此外,日志的每条记录都会有一个前缀,该前缀也由 Filter初始化参数来定义。通过日志文件,可以获得许 多有用的信息,例如在应用中哪些资源访问最频繁; Web站点在一天中的哪个时间段访问量最多。
这个Filter的类名叫LoggingFilter。 一般情况下,Filter的类名都以*Filter结尾。
4.
二.
1.
2.
3.
4.
三.
1.
2.
3.
4.
四.
1.
2.
3.
4.
五.
1.
2.
3.
4.
六.
1.
2.
3.
4.
