Java里的攔截器是動態攔截Action調用的對象。它提供了一種機制可以使開發者可以定義在一個action執行的前後執行的代碼,也可以在一個action執行前阻止其執行,同時也提供了一種可以提取action中可重用部分的方式。在AOP(Aspect-Oriented Programming)中攔截器... ...
Java里的攔截器是動態攔截Action調用的對象。它提供了一種機制可以使開發者可以定義在一個action執行的前後執行的代碼,也可以在一個action執行前阻止其執行,同時也提供了一種可以提取action中可重用部分的方式。在AOP(Aspect-Oriented Programming)中攔截器用於在某個方法或欄位被訪問之前,進行攔截然後在之前或之後加入某些操作。
spring mvc中的攔截器概念和struts2的攔截器概念是一樣的,這裡先用struts2的攔截器原理來理解。
大部分時候,攔截器方法都是通過代理的方式來調用的。Struts 2的攔截器實現相對簡單。當請求到達Struts 2的ServletDispatcher時,Struts 2會查找配置文件,並根據其配置實例化相對的攔截器對象,然後串成一個列表(list),最後一個一個地調用列表中的攔截器。Struts2攔截器是可插拔的,攔截器是AOP的一種實現。Struts2攔截器棧就是將攔截器按一定的順序聯結成一條鏈。在訪問被攔截的方法或欄位時,Struts2攔截器鏈中的攔截器就會按其之前定義的順序被調用。
spring mvc中自定義一個攔截器需要三步:
- 自定義攔截器,這個攔截器實現HandlerInterceptor介面。
- 在spring-mvc.xml配置文件中配置攔截器。
- 在自定義攔截器中做攔截處理。
實現攔截器
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class MyInterceptor implements HandlerInterceptor {
/**
* 在DispatcherServlet處理後執行,清理工作
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception)
throws Exception {
System.out.println("-----------------------清理工作------------------------");
}
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object object, ModelAndView modelAndView) throws Exception {
System.out.println("處理請求");
}
/**
* 在請求方法處理前執行
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object object) throws Exception {
System.out.println("---------------------攔截器之前先攔截--------------------");
return true;
}
}
HandlerInterceptor需要實現3個方法,preHandle()方法在調用controller前就調用,postHandle(),afterCompletion()在調用controller之後調用。在preHandle()方法中,如果返回true,那麼執行下一個攔截器,如果返回false,那麼不執行攔截器。
配置攔截器
<!-- 攔截器配置 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="com.shizongger.ssm.controller.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
mvc:mapping標簽的path屬性中,配置的攔截路徑,/**包括路徑的子路勁,如果是/admin*攔截的是/admin/add, /admin/list等,/admin/user/add不被攔截。
在ide打上斷點,瀏覽器輸入url,就會進入這個攔截器裡面來。這裡有個思考題:如果被攔截,能否到達指定的頁面?答案是:使用HttpServletResponse或者HttpServletRequest可以實現轉發或者重定向。
攔截器的應用:登錄攔截器
web開發中,只要有登錄用戶這一模塊幾乎都需要許可權驗證。這裡先配置一個登陸攔截器,預設登錄地址不攔截,登錄過的用戶也不需要攔截,每個url都允許通過。只有未登錄的用戶,直接訪問非登錄地址,這是不允許的是,需要攔截。
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class LoginInterceptor implements HandlerInterceptor {
private List<String> allawedPass;
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object object, Exception exception)
throws Exception {
}
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object object, ModelAndView mav) throws Exception {
}
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object object) throws Exception {
String url = request.getRequestURL().toString().trim();
String loginName = (String) request.getSession().getAttribute("loginName");
if(loginName != null) {
return true;
}
for(String temp : allawedPass) {
if(url.endsWith(temp)) {
return true;
}
}
response.sendRedirect(request.getContextPath() + "/user/loginUI");
return false;
}
public void setAllawedPass(List<String> allawedPass) {
this.allawedPass = allawedPass;
}
}
<!-- 攔截器配置 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="com.shizongger.ssm.controller.MyInterceptor" />
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="com.shizongger.ssm.controller.LoginInterceptor">
<property name="allawedPass">
<list>
<value>/user/loginUI</value>
<value>/user/login</value>
</list>
</property>
</bean>
</mvc:interceptor>
</mvc:interceptors>
在攔截器中,定義一個List的變數這個變數預設哪些地址不需要攔截,賦值是通過配置文件中
<list>
<value>/user/loginUI</value>
<value>/user/login</value>
</list>
中設置,當前端訪問url時,在進入controller方法前,先來到登錄攔截器的preHandle()方法,這個方法的處理邏輯是:先從session中獲取登錄用戶名,如果session中存在用戶,那麼通過。如果session中沒有用戶名,但是url尾碼在白名單中,也讓它通過,只有那些既沒有登錄過,也不是白名單地址在這裡被強制返回到登錄頁面。
攔截器與過濾器區別
過濾器可以簡單理解為“取你所想取”,忽視掉那些你不想要的東西;攔截器可以簡單理解為“拒你所想拒”,關心你想要拒絕掉哪些東西,比如一個BBS論壇上攔截掉敏感辭彙。
1.攔截器是基於java反射機制的,而過濾器是基於函數回調的。
2.過濾器依賴於servlet容器,而攔截器不依賴於servlet容器。
3.攔截器只對action起作用,而過濾器幾乎可以對所有請求起作用。
4.攔截器可以訪問action上下文、值棧里的對象,而過濾器不能。
5.在action的生命周期里,攔截器可以多起調用,而過濾器只能在容器初始化時調用一次。