過濾器Filter
過濾器依賴于servlet容器,是JavaEE標準。是在請求進入容器之后,還未進入Servlet之前進行預處理,并且在請求結束返回給前端這之間進行后期處理。在實現上基于函數回調,可以對幾乎所有請求進行過濾,但是缺點是一個過濾器實例只能在容器初始化時調用一次。
使用過濾器的目的是用來做一些過濾操作,獲取我們想要獲取的數據,比如:在過濾器中修改字符編碼;在過濾器中修改HttpServletRequest的一些參數,包括:過濾低俗文字、危險字符等
攔截器Interceptor
攔截器不依賴與servlet容器,依賴于web框架,在SpringMVC中就是依賴于SpringMVC框架。在實現上基于Java的反射機制,屬于面向切面編程(AOP)的一種運用。由于攔截器是基于web框架的調用,因此可以使用spring的依賴注入(DI)獲取IOC容器中的各個bean,進行一些業務操作,同時一個攔截器實例在一個controller生命周期之內可以多次調用。但是缺點是只能對controller請求進行攔截,對其他的一些比如直接訪問靜態資源的請求則沒辦法進行攔截處理。
過濾器和攔截器對比
(1)規范不同:Filter是在Servlet規范中定義的,是Servlet容器支持的。而攔截器是在Spring容器內的,是Spring框架支持的。
(2)使用的資源不同:同其他的代碼塊一樣,攔截器也是一個Spring的組件,歸Spring管理,配置在Spring文件中,因此能使用Spring里的任何資源、對象,例如Service對象、數據源、事務管理等,通過IoC注入到攔截器即可;而Filter則不能。
(3)深度不同:Filter在只在Servlet前后起作用。而攔截器能夠深入到方法前后、異常拋出前后等,因此攔截器的使用具有更大的彈性。所以在Spring構架的程序中,要優先使用攔截器。
(4)使用范圍不同:Filter是Servlet規范規定的,只能用于Web程序中。而攔截器既可以用于Web程序,也可以用于Application、Swing程序中。
攔截器的實現
SpringMVC 中的Interceptor 攔截請求是通過HandlerInterceptor 來實現的。HandlerInterceptor 接口中定義了三個方法,我們就是通過這三個方法來對用戶的請求進行攔截處理的。
package org.springframework.web.servlet;
public interface HandlerInterceptor {
boolean preHandle(
HttpServletRequest request, HttpServletResponse response,
Object handler)
throws Exception;
void postHandle(
HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView)
throws Exception;
void afterCompletion(
HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex)
throws Exception;
}
preHandle
顧名思義,該方法將在請求處理之前進行調用。
SpringMVC 中的Interceptor 是鏈式的調用的,在一個應用中或者說是在一個請求中可以同時存在多個Interceptor。每個Interceptor 的調用會依據它的聲明順序依次執行,而且最先執行的都是Interceptor 中的preHandle 方法,所以可以在這個方法中進行一些前置初始化操作或者是對當前請求的一個預處理,也可以在這個方法中進行一些判斷來決定請求是否要繼續進行下去。
該方法的返回值是布爾值Boolean類型的,當它返回為false 時,表示請求結束,后續的Interceptor 和Controller 都不會再執行;當返回值為true 時就會繼續調用下一個Interceptor 的preHandle 方法,如果已經是最后一個Interceptor 的時候就會是調用當前請求的Controller 方法。
postHandle
后處理回調方法,實現處理器的后處理(但在渲染視圖之前),此時我們可以通過modelAndView(模型和視圖對象)對模型數據進行處理或對視圖進行處理,modelAndView也可能為null。
afterCompletion
整個請求處理完畢回調方法,即在視圖渲染完畢時回調,如性能監控中我們可以在此記錄結束時間并輸出消耗時間,還可以進行一些資源清理,類似于try-catch-finally中的finally,但僅調用處理器執行鏈中。
多個過濾器與攔截器的代碼執行順序
相信從這個打印輸出,大家就可以很清晰地看到有多個攔截器和過濾器存在時的整個執行順序了。當然,對于過個攔截器它們之間的執行順序跟在SpringMVC的配置文件中定義的先后順序有關。
對于整個SpringMVC的執行流程來說,如果加上上面的攔截器和過濾器,其最終的執行流程就如下圖所示: