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");%>
參考:
http://983836259.blog.51cto.com/7311475/1880286
http://www.cnblogs.com/dreamroute/p/4198087.html
http://www.cnblogs.com/ctxsdhy/p/6421067.html