springMVC4(16)攔截器解析與登陸攔截模擬
在SpringMVC中,我們會經常使用到攔截器,雖然SpringAOP也能幫我們實現強大的攔截器功能,但在Web資源供給上,卻沒有SpringMVC來得方便快捷。
使用SpringMVC攔截器的核心應用場景是根據我們的實際需求,個性化定製攔截器,再對特定url進行攔截處理。
而自定義攔截器,首先需要我們實現HandlerInterceptor攔截器介面,下面是它的定義:
package org.springframework.web.servlet;
public interface HandlerInterceptor {
//在控制器方法呼叫前執行
//返回值為是否中斷,true,表示繼續執行(下一個攔截器或處理器)
//false則會中斷後續的所有操作,所以我們需要使用response來響應請求
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;
}
很多時候,我們只需要實現以上三個方法的任意一個或兩個,這個時候我們可以選擇繼承HandlerInterceptorAdapter。它實現了AsyncHandlerInterceptor介面,為每個方法提供了空實現,這樣,我們就可以根據需求重寫自己用到的攔截方法即可。具體定義如下:
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
@Override
public void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
}
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
@Override
public void afterConcurrentHandlingStarted(
HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
}
}
相對於HandlerInterceptor,HandlerInterceptorAdapter多了一個實現方法afterConcurrentHandlingStarted(),它來自HandlerInterceptorAdapter的直接實現類AsyncHandlerInterceptor,AsyncHandlerInterceptor介面直接繼承了HandlerInterceptor,並新添了afterConcurrentHandlingStarted()方法用於處理非同步請求,當Controller中有非同步請求方法的時候會觸發該方法時,非同步請求先支援preHandle、然後執行afterConcurrentHandlingStarted。非同步執行緒完成之後執行preHandle、postHandle、afterCompletion。
下面我們以登陸請求為例,編寫我們的自定義攔截器:
public class LoginInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception {
// 獲得請求路徑的uri
String uri = request.getRequestURI();
// 進入登入頁面,判斷session中是否有key,有的話重定向到首頁,否則進入登入介面
if(uri.contains("login")) {
if(request.getSession().getAttribute("user") != null) {
response.sendRedirect(request.getContextPath());//預設跟路徑為首頁
} else {
return true;//繼續登陸請求
}
}
// 其他情況判斷session中是否有key,有的話繼續使用者的操作
if(request.getSession().getAttribute("user") != null) {
return true;
}
// 最後的情況就是進入登入頁面
response.sendRedirect(request.getContextPath() + "/login");
return false;
}
}
下面是我們的攔截器配置:
<mvc:interceptors>
<mvc:interceptor><!--配置區域性攔截器,需要滿足下列路徑條件-->
<mvc:exclude-mapping path="/user/logout"/><!--登出-->
<mvc:exclude-mapping path="/home/"/><!--在home中定義了無須登陸的方法請求,直接過濾攔截-->
<mvc:mapping path="/**"/>
<bean class="com.mvc.interceptor..LoginInterceptor"/><!--自定義攔截器註冊-->
</mvc:interceptor>
<!-- 我們可以直接在者註冊自定義攔截器Bean來配置全域性攔截器,會對所有請求攔截-->
</mvc:interceptors>
在我們的攔截中,如果配置了多個攔截器,會形成一條攔截器鏈,執行順序類似於AOP,前置攔截先定義的先執行,後置攔截和完結攔截(afterCompletion)後註冊的後執行,關於攔截器的執行順序的深入理解可參考我的另一篇文章《 spring學習筆記(12)@AspectJ研磨分析[3]增強織入順序例項詳解》