一、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(); }
三、Filter鏈日誌
一般只有一個Servlet能夠處理請求,但能夠使用許多過濾攔截請求。一個請求將被不少過濾器處理後傳遞最終傳遞給Servlet。如圖所示這樣:code
這樣的工做方式被稱爲過濾器鏈,這種工做方式至關於一個工做棧,當請求進入時,第一個過濾器將被添第一個過濾器將被添加到棧中,而後再把第二個過濾器添加到棧中,直到最終的Servlet,這是棧的最後一個元素,當Servlet的請求完成的時候,Servlet將從棧中去除,而後控制權將返回最後一個過濾器,而後再移除最後一個過濾器,一直到第一個過濾器中,當棧空的時候,請求處理也就完成了。
四、Filter的部署方式
Filter除了能夠映射到某個URL上,某個Servlet上,還能夠映射到不一樣的請求派發器類型,在Servlet容器中有這麼幾種派發請求方式:
部署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>
使用註解:
@WebFilter( filterName = "filterA", urlPatterns = {"/filterA","/filterB"}, servletNames = {"someServlet"}, dispatcherTypes = {DispatcherType.REQUEST,DispatcherType.ASYNC} )
五、過濾器排序
定義三個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是最早被啓動的,最後結束的。