JavaWeb——Filter過濾器

一、Filter的目的  瀏覽器

  Filter用於在Servlet以前檢測和修改請求和響應,它能夠拒絕、重定向或轉發請求。常見的有這幾種:app

  • 日誌過濾器

  使用過濾器記錄請求,提供請求日誌記錄,還能夠添加追蹤信息用於特定的請求。異步

  • 驗證過濾器

  用於驗證用戶已經「登錄」,不少Servlet的操做都須要驗證用戶的身份權限,驗證過濾器就是把這一功能提取出來,將驗證和受權操做集中帶一個位置,方便開發和維護jsp

  • 壓縮和加密過濾器

  其實根本上的目的和上一個驗證過濾器同樣,不過這裏的功能是壓縮和加密ide

  • 錯誤處理過濾器

  對於客戶端來講,有時候出現錯誤錯誤一般會返回一個Http響應代碼500,通常還伴隨這一些診斷信息,一般這些信息對於開發者而言是有用的,可是對於黑客來講,這些診斷信息可能暴露一些敏感的系統信息,並且錯誤幾乎是不可避免的,因此咱們須要防止這些信息泄露,使用錯誤處理過濾器爲用戶顯示一個特殊的頁面,好比這個,url是我隨便填的一個:加密

 

二、建立Filterurl

  其實Filter只是一個接口,源代碼以下:spa

public interface Filter { void init(FilterConfig var1) throws ServletException; void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException; void destroy(); }
  • init()方法用於初始化過濾器,這裏能夠看到一個FilterConfig類,Filter就是使用這個類來進行初始化配置
  • doFilter()方法就是用來實現具體功能,檢測和修改請求和響應,由於一個項目可能不止須要一個Filter,就好比某個Servlet須要先驗證再加密壓縮,可能就須要使用兩個Filter,這樣就造成了一個過濾器鏈,驗證的Filter成功後再將請求傳遞給加密壓縮的Filter,FilterChain將用於傳遞請求和響應。

  • destroy()方法將用於銷燬Filter

 

三、Filter鏈日誌

  一般只有一個Servlet能夠處理請求,但能夠使用許多過濾攔截請求。一個請求將被不少過濾器處理後傳遞最終傳遞給Servlet。如圖所示這樣:code

  這樣的工做方式被稱爲過濾器鏈,這種工做方式至關於一個工做棧,當請求進入時,第一個過濾器將被添第一個過濾器將被添加到棧中,而後再把第二個過濾器添加到棧中,直到最終的Servlet,這是棧的最後一個元素,當Servlet的請求完成的時候,Servlet將從棧中去除,而後控制權將返回最後一個過濾器,而後再移除最後一個過濾器,一直到第一個過濾器中,當棧空的時候,請求處理也就完成了。

 

四、Filter的部署方式

  Filter除了能夠映射到某個URL上,某個Servlet上,還能夠映射到不一樣的請求派發器類型,在Servlet容器中有這麼幾種派發請求方式:

  • 普通請求:一般來自客戶端,,幷包含了容器中特定的Web應用程序的目標URL
  • 轉發請求:當代碼調用RequestDispatcher的forward方法或者使用<jsp:forward>標籤是將觸發這些請求。
  • 包含請求:使用<jsp:include>標籤或者調用RequestDispatcher的include方法的時候,將會產生一個不一樣的、與原始請求相關的內部請求
  • 錯誤資源請求:訪問HTTP錯誤的錯誤頁面的請求
  • 異步請求

  部署Filter有兩種方式,第一種是使用部署描述符

<filter>
  <filter-name>filterA</filter-name>
  <filter-class>filter.FilterA</filter-class>
 </filter>
  <filter-mapping>
    <filter-name>filterA</filter-name>
    <url-pattern>/filterA</url-pattern>
    <servlet-name>someServlet</servlet-name>
    <dispatcher>REQUEST</dispatcher>
  </filter-mapping>

  

  •  <filter-name>將指定filter的名字
  • <filter-class>將指定filter的類名
  • <url-pattern>將指定映射的URL
  • <servlet-name>將指定映射的Servlet的名字
  • <dispatcher>將響應的請求的派發方式,有效的<dispatcher>類型有REQUEST、FORWARD、INCLUDE、ERROR、ASYNC

  使用註解:

@WebFilter( filterName = "filterA", urlPatterns = {"/filterA","/filterB"}, servletNames = {"someServlet"}, dispatcherTypes = {DispatcherType.REQUEST,DispatcherType.ASYNC} )

 

 五、過濾器排序

  • 匹配請求的過濾器將按照它們出如今部署描述符的順序添加到過濾器鏈中
  • URL映射的過濾器優先級比Servlet名稱映射的過濾器優先級高

  定義三個Filter,分別爲FilterA、FilterB、FilterC,三個Filter在啓動的時候都會輸出類名+start,而後將請求和響應傳遞給下一個Filter,到出棧以前都會輸出類名+end

public class FilterA implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("FilterA start"); filterChain.doFilter(servletRequest,servletResponse); System.out.println("FilterA end"); } @Override public void destroy() { } }

 

   而後定義一個Servlet,這裏就是啓動的時候輸出「ServletOne.doget() start」,結束的時候輸出「ServletOne.doget() start」

@WebServlet( name = "servletOne", urlPatterns = "/servletOne" ) public class ServletOne extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("ServletOne.doget() start"); resp.getWriter().write("ServletOne"); System.out.println("ServletOne.doget() end"); } }

 

   而後這樣配置Filter:

<filter>
  <filter-name>filterA</filter-name>
  <filter-class>filter.FilterA</filter-class>
</filter>
  <filter-mapping>
    <filter-name>filterA</filter-name>
    <servlet-name>servletOne</servlet-name>
  </filter-mapping>

  <filter>
    <filter-name>filterB</filter-name>
    <filter-class>filter.FilterB</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>filterB</filter-name>
    <url-pattern>/servletOne</url-pattern>
  </filter-mapping>

  <filter>
    <filter-name>filterC</filter-name>
    <filter-class>filter.FilterC</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>filterC</filter-name>
    <url-pattern>/servletOne</url-pattern>
  </filter-mapping>

  FilterA將映射到名稱爲servletOne的Servlet,FilterB、FilterC都將映射的URL是/servletOne。運行成功以後在瀏覽器中輸入http://localhost:8080/hello-world/servletOne,咱們將在IDEA的輸出中看到這樣的結果

filter.FilterB@17f58a6f start filter.FilterC@193266e1 start filter.FilterA@1d0de11fstart ServletOne.doget() start ServletOne.doget() end filter.FilterA@1d0de11f end filter.FilterC@193266e1 end filter.FilterB@17f58a6f end

 

   能夠看到最早啓動的是FilterB,其次是FilterC,最後是FilterA。由於FilterA是映射的Servlet的名稱而FilterB、FilterC都是映射的URL因此FilterA將在最後啓動,同時也在Servlet結束後結束。由於FilterB在部署時在FilterC以前因此FilterB是最早被啓動的,最後結束的。

相關文章
相關標籤/搜索