1. 程式人生 > >Java for Web學習筆記(三九):Filter(1)用途、定義和順序

Java for Web學習筆記(三九):Filter(1)用途、定義和順序

Filter的用途

Filter可以用於以下方面:

  1. 記錄request和response的log
  2. 進行認證和授權
  3. 進行壓縮和加壓,非HTTPS的加密和解密
  4. 錯誤處理。對於tomcat,出現錯誤通常會給出一個500的頁面,還有錯誤診斷資訊,對於一個公眾服務,這些診斷資訊可能會向黑客洩漏一些敏感資訊,通過Filter,我們可以用try{}catch(){},將這些診斷資訊記錄在log中,而向公眾展現一個通用的錯誤頁面。

Filter可以在Servlet執行前以及執行後進行相應的動作,而不僅僅在執行前。

定義Filter

通過web.xml定義

和定義Servlet相似。在匹配條件中,可以指定url,可以指定servlet名字,也可以指定分派方式dispatcher。dispatcher有以下之中模式:

  1. REQUEST:普通模式,來自客戶端的請求
  2. FORWARD:通過RequestDispatcher的forward(),或者<jsp:forward>
  3. INCLUDE:通過RequestDispatcher的include(),或者<jsp:include>
  4. ERROR:請求錯誤頁面來處理HTTP錯誤,例如404,500
  5. 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。