spring mvc 攔截器的使用

週二發表於2019-07-19

Spring MVC 攔截器的使用

攔截器簡介

Spring MVC 中的攔截器(Interceptor)類似於 Servler 中的過濾器(Filter)。用於對處理器進行預處理和後處理。常用於日誌記錄、許可權管理、效能監控、通用行為等。

攔截器的實現

Spring MVC 中的攔截器需要我們手動實現和配置。攔截器可以通過以下兩種方式定義

  • 實現 HandleInterceptor 介面,或者繼承該介面的實現類如 HandleInterceptorAdapter 來定義一個攔截器;
  • 實現 WebRequestInterceptor 介面來定義一個攔截器;

HandleInterceptor 介面

我們主要講解下實現 HandleInterceptor 介面來建立攔截器。HandleInterceptor 介面定義了三個方法,分別為 preHandle() , postHandle() , afterCompletion(),我們需要重寫這三個方法,從而來實現我們定義攔截器的目的。

  • preHandle(HttpServletRequest request, HttpServletResponse response, Object handle):該方法在請求處理前呼叫。Spring MVC 中的攔截器是鏈式呼叫的,一個請求可以被多個攔截器攔截,但是 Interceptor 會根據被宣告的次序依次被呼叫執行,而不會同時去攔截。而且所有 Interceptor 中的 preHandle 函式都會最先被呼叫,所以這個方法中可以進行一些前置初始化操作或者是對當前請求的預處理,或者設定一些判斷來決定該請求是否執行下去。該方法的返回值是布林值,當它返回 true 時,之後的 Interceptor 和 controller 都不會執行下去了;當它返回 false 時,就會繼續呼叫下一個 Interceptor 的 preHandle 方法或者處理當前請求的 Controller

  • postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView):該方法只有在 perHandle 方法返回值為 true 時,在 Controller 執行完當前請求後才會執行。咋一看好像和之後要介紹的 afterCompletion 方法沒有不同,但是這個方法會在 DispatcherServlet 進行檢視渲染之前被呼叫,所以我們們可以在這個方法中對 Controller 處理之後的 ModelAndView 物件進行操作。

  • afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex):該方法在整個請求結束後,也就是 DispatcherServlet 渲染了對應檢視之後執行,這個方法的主要作用是用於進行資源清理的工作。

假設我們現在定義了兩個攔截器,xml 配置檔案中配置順序如下內容如下:

<!-- 攔截器1 -->
<mvc:interceptor>
    <!--配置攔截器的作用路徑-->
    <mvc:mapping path="/**"/>
    <bean class="com.jojo.test.interceptor.Intercptor1"/>
</mvc:interceptor>
<!--攔截器2-->
<mvc:interceptor>
    <mvc:mapping path="/hello"/>
    <bean class="com.jojo.test.interceptor.Interceptor2"/>
</mvc:interceptor>

那麼這兩個攔截器中的處理方法和請求的處理方法的順序如下圖:
spring mvc 攔截器的使用

實際應用舉例

實現開發中,我們會要求一些頁面需要登入後才能訪問。未登入狀態是無法得到訪問許可權的。這一小功能我們可以直接通過安全框架,類似 Spring Security 或者 shiro 來實現,不過我們現在利用 Spring MVC 這一功能來實現一下:

public class LoginInterceptor implements HandlerInterceptor {
    
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        
        User user = (User) httpServletRequest.getSession().getAttribute("user");

        if (user == null) {
            // 使用者未登入,重定向到登入頁
            httpServletResponse.sendRedirect("/login");
            return false;
        }

        return true;
    }

    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        
        }
    }

    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }
}

我們還需要在 spring-mvc 中配置攔截器

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <mvc:exclude-mapping path="/static/**"/>
        <mvc:exclude-mapping path="/login"/>
        <bean class="com.jojo.test.interceptor.LoginInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

相關配置說明:

  • mvc:interceptor:定義一個攔截器
    • mvc:mapping:定義需要被攔截的路徑
    • mvc:exclude-mapping:定義需要排除攔截的請求路徑
    • bean class:指定攔截器物件

相關文章