servlet filter和spring mvc Interceptor區別:
1.攔截器是基於java的反射機制的,而過濾器是基於函數回調。
2.攔截器不依賴與servlet容器,過濾器依賴與servlet容器。
3.攔截器只能對action請求起作用,而過濾器則可以對幾乎所有的請求起作用。
4.攔截器可以訪問action上下文、值棧里的對象,而過濾器不能訪問。
5.在action的生命周期中,攔截器可以多次被調用,而過濾器只能在容器初始化時被調用一次。
6.攔截器可以獲取IOC容器中的各個bean,而過濾器就不行,這點很重要,在攔截器里注入一個service,可以調用業務邏輯。
servlet filter和spring mvc Interceptor執行順序:

===========before doFilter1
===========before doFilter2
===========HandlerInterceptorAll preHandle
===========HandlerInterceptor1 preHandle
===========HandlerInterceptor2 preHandle
執行Controller
Controller return前
===========HandlerInterceptor2 postHandle
===========HandlerInterceptor1 postHandle
===========HandlerInterceptorAll preHandle
Controller return后,Jsp加載完成
===========HandlerInterceptor2 afterCompletion
===========HandlerInterceptor1 afterCompletion
===========HandlerInterceptorAll preHandle
===========before doFilter2
===========before doFilter1

Filter:
Java中的Filter並不是一個標准的Servlet ,它不能處理用戶請求,也不能對客戶端生成響應。 主要用於對HttpServletRequest 進行預處理,也可以對HttpServletResponse 進行后處理,是個典型的處理鏈。完整的流程是:Filter對用戶請求進行預處理,接着將請求交給Servlet進行處理並生成響應,最后Filter再對服務器響應進行后處理。在HttpServletRequest 到達Servlet 之前,攔截客戶的HttpServletRequest。根據需要檢查HttpServletRequest ,也可以修改HttpServletRequest 頭和數據。在HttpServletResponse 到達客戶端之前,攔截HttpServletResponse。根據需要檢查HttpServletResponse ,可以修改HttpServletResponse 頭和數據。
Filter隨web應用的啟動而啟動,只初始化一次,隨web應用的停止而銷毀。
1.啟動服務器時加載過濾器的實例,並調用init()方法來初始化實例;
2.每一次請求時都只調用方法doFilter()進行處理;
3.停止服務器時調用destroy()方法,銷毀實例。
自定義Servlet Filter:
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class ErrorHandleFilter implements Filter { @Override public void destroy() { // ... } @Override public void init(FilterConfig filterConfig) throws ServletException { // } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { long before = System.currentTimeMillis(); System.out.println("===========before doFilter") chain.doFilter(request, response); long after = System.currentTimeMillis(); System.out.println("===========after doFilter") } catch (Exception ex) { request.setAttribute("errorMessage", ex); request.getRequestDispatcher("/WEB-INF/views/jsp/error.jsp") .forward(request, response); } } }
上面程序實現了doFilter()方法,實現該方法就可實現對用戶請求進行預處理,也可實現對服務器響應進行后處理——它們的分界線為是否調用了chain.doFilter(),執行該方法之前,即對用戶請求進行預處理;執行該方法之后,即對服務器響應進行后處理。調用Servlet的doService()方法是就是在chain.doFilter(request, response)這個方法中進行的。
在web.xml中配置:
<filter> <filter-name>errorHandlerFilter</filter-name> <filter-class>com.mkyong.form.web.ErrorHandleFilter</filter-class> </filter> <filter-mapping> <filter-name>errorHandlerFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
使用Spring進行管理:
DelegatingFilterProxy就是一個對於servlet filter的代理,它沒有實現過濾器的任何邏輯。通過spring容器來管理ServletFilter的生命周期。如果filter中需要一些Spring容器的實例,可以通過spring直接注入。
在web.xml中配置:
<filter> < filter-name>myFilter</filter-name> < filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> < filter-name>myFilter</filter-name> < url-pattern>/*</url-pattern> </filter-mapping>
在contextApplication.xml中,配置具體的Filter類的實例。在Spring中配置的bean的name要和web.xml中的<filter-name>一樣
<bean name="myFilter" class="com.*.MyFilter"></bean>
Interceptor:
spring mvc中的Interceptor可以理解為是Spring MVC框架對AOP的一種實現方式。一般簡單的功能又是通用的,每個請求都要去處理的,比如判斷token是否失效可以使用spring mvc的HanlderInterceptor, 復雜的,比如緩存,需要高度自定義的就用spring aop。一般來說service層更多用spring aop,controller層有必要用到request和response的時候,可以用攔截器。
spring mvc中的Interceptor攔截請求是通過HandlerInterceptor來實現的。所以HandlerInteceptor攔截器只有在Spring Web MVC環境下才能使用。在SpringMVC中定義一個攔截器主要有兩種方式,第一種方式是要實現Spring的HandlerInterceptor接口,或者是其它實現了HandlerInterceptor接口的類,比如HandlerInterceptorAdapter。第二種方式是實現WebRequestInterceptor接口,或者其它實現了WebRequestInterceptor的類。
HandlerInterceptor接口中定義了三個方法preHandle, postHandle, 和afterCompletion:
- preHandle:預處理回調方法,實現處理器的預處理(如登錄檢查),返回值:true表示繼續流程(如調用下一個攔截器或處理器),false表示流程中斷(如登錄檢查失敗),不會繼續調用其他的攔截器或處理器,此時我們需要通過response來產生響應。
- postHandle:后處理回調方法,實現處理器的后處理(但在渲染視圖之前),此時我們可以通過modelAndView(模型和視圖對象)對模型數據進行處理或對視圖進行處理,modelAndView也可能為null。
- afterCompletion:整個請求處理完畢回調方法,即在視圖渲染完畢時回調。該方法也是需要當前對應的Interceptor 的preHandle方法的返回值為true時才會執行。這個方法的主要作用是用於進行資源清理工作的,如性能監控中我們可以在此記錄結束時間並輸出消耗時間。
流程如下:
先聲明的Interceptor 的postHandle 方法反而會后執行。


有時候我們可能只需要實現三個回調方法中的某一個,如果實現HandlerInterceptor接口的話,三個方法必須實現。spring提供了一個HandlerInterceptorAdapter適配器(一種適配器設計模式的實現),允許我們只實現需要的回調方法。
HandlerInterceptor1,HandlerInterceptor2:
public class HandlerInterceptor1 extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("===========HandlerInterceptor1 preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("===========HandlerInterceptor1 postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("===========HandlerInterceptor1 afterCompletion"); } }
HandlerInterceptor2同理,只是輸出內容為“HandlerInterceptor2”。
TestController:
public class TestController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception { System.out.println("===========TestController"); return new ModelAndView("test"); } }
Spring配置文件:
<bean id="handlerInterceptor1" class="cn.javass.chapter5.web.interceptor.HandlerInterceptor1"/> <bean id="handlerInterceptor2" class="cn.javass.chapter5.web.interceptor.HandlerInterceptor2"/> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"> <property name="interceptors"> <list> //攔截器的執行順序就是此處添加攔截器的順序。 <ref bean="handlerInterceptor1"/> <ref bean="handlerInterceptor2"/> </list> </property> </bean>
如果使用了<mvc:annotation-driven />, 它會自動注冊BeanNameUrlHandlerMapping這兩個bean,所以就沒有機會再給它注入interceptors屬性,就無法指定攔截器。推薦使用mvc:interceptors標簽來聲明需要加入到SpringMVC攔截器鏈中的攔截器。
在SpringMVC的配置文件中加上支持MVC的schema:
<beans xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd" > <mvc:interceptors> <!-- 使用bean定義一個Interceptor,直接定義在mvc:interceptors根下面的Interceptor將攔截所有的請求 <bean class="com.host.app.web.interceptor.HandlerInterceptorAll"/> --> <mvc:interceptor> <mvc:mapping path="/test/number.do"/> <mvc:exclude-mapping path="/test/goLogin.*"/> <!-- 定義在mvc:interceptor下面的表示是對特定的請求才進行攔截的 --> <bean class="com.host.app.web.interceptor.HandlerInterceptor1"/> <!-- <ref bean="handlerInterceptor1"/> --> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/test/number.do"/> <mvc:exclude-mapping path="/test/goLogin.*"/> <bean class="com.host.app.web.interceptor.HandlerInterceptor2"/> <!-- <ref bean="handlerInterceptor2"/> --> </mvc:interceptor> </mvc:interceptors>
在mvc:interceptors標簽下聲明interceptor主要有兩種方式:
1.直接定義一個Interceptor實現類的bean對象。使用這種方式聲明的Interceptor攔截器將會對所有的請求進行攔截。
2.使用mvc:interceptor標簽進行聲明。這種方式進行聲明的Interceptor可以通過mvc:mapping子標簽來定義需要進行攔截的請求路徑。
視圖頁面WEB-INF/jsp/test.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%System.out.println("==========test.jsp");%>
轉:https://www.jianshu.com/p/685c65ed6944