Filter的用途
Filter可以用于以下方面:
- 记录request和response的log
- 进行认证和授权
- 进行压缩和加压,非HTTPS的加密和解密
- 错误处理。对于tomcat,出现错误通常会给出一个500的页面,还有错误诊断信息,对于一个公众服务,这些诊断信息可能会向黑客泄漏一些敏感信息,通过Filter,我们可以用try{}catch(){},将这些诊断信息记录在log中,而向公众展现一个通用的错误页面。
Filter可以在Servlet执行前以及执行后进行相应的动作,而不仅仅在执行前。
定义Filter
通过web.xml定义
和定义Servlet相似。在匹配条件中,可以指定url,可以指定servlet名字,也可以指定分派方式dispatcher。dispatcher有以下之中模式:
- REQUEST:普通模式,来自客户端的请求
- FORWARD:通过RequestDispatcher的forward(),或者<jsp:forward>
- INCLUDE:通过RequestDispatcher的include(),或者<jsp:include>
- ERROR:请求错误页面来处理HTTP错误,例如404,500
- ASYNC:来自AsyncContext的异步请求
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.abc.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/foo</url-pattern>
<url-pattern>/bar/*</url-pattern>
<servlet-name>myServlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ASYNC</dispatcher>
</filter-mapping>
如果没有指定dispacher,缺省为REQUEST。
Filter的init()将在web app启动时执行,在ServletContextListeners的初始化之后,执行的顺序按web.xml中<filter>定义的顺序。
使用Annotation定义
@WebFilter(
filterName = "myFilter",
urlPatterns = { "/foo", "/bar/*" },
servletNames = { "myServlet" },
dispatcherTypes = { DispatcherType.REQUEST, DispatcherType.ASYNC }
)
public class MyFilter implements Filter{
... ...
}
使用annotation的主要问题是无法确定filter的执行顺序,通常只在单个filter的请求下使用。但是,基于某些原因,例如我们需要通过ProGuard进行扰码,不适用web.xml的定义方式,我们还可以在代码中进行设定。在大型的web app中很少使用annotation来定义,一般采用部署描述(web.xml)或/和代码定义。
在代码中定义
前面提到filter的初始化在ServletContextListener的初始化之后执行,因此定义filter,需要在ServletContextListener的初始化过程中定义,还可以在ServletContainerInitializer的onStartup()中定义。
@WebListener
public class GlobalLisener implements ServletContextListener {
......
public void contextInitialized(ServletContextEvent event) {
ServletContext context = event.getServletContext();
//【1】通过addFilter()来顺序添加filter
FilterRegistration.Dynamic registration = context.addFilter("myFilter", new MyFilter());
//【2】设置filter的匹配
// -- 第一个参数为null,则是缺省的REQUEST模式
// -- 第二个参数false表明在代码设置的filter先于web.xml中设置的filter,true则是先web.xml定义的filter后代码设置的。
registration.addMappingForUrlPatterns( EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC),false, "/foo", "/bar/*" );
registration.addMappingForServletNames( EnumSet.of(DispatcherType.REQUEST, DispatcherType.ASYNC),false, "myServlet" );
}
}
Filter的顺序
前面我们了解如何通过web.xml和代码设定filter的优先顺序。filter可以通过url或者servlet名字进行匹配。在实际的匹配中,先执行满足url匹配的filter,如果有多个,则按filter的优先顺序,接着执行满足servlet名字匹配的filter,如果有多个,则按filter的优先顺序。例:FilterA优先于filterB,对于某个http请求,filterA是serveltName匹配,filterB是url匹配,则先执行filterB。
相关链接: 我的Professional Java for Web Applications相关文章