1. 程式人生 > >springMVC4(16)攔截器解析與登陸攔截模擬

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]增強織入順序例項詳解》