Java for Web學習筆記(三九):Filter(1)用途、定義和順序
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。