詳述 Spring MVC 框架中攔截器 Interceptor 的使用方法

1 前言

  昨天新接了一個須要,「攔截 XXX,而後 OOO」,好吧,說白了就是要用攔截器乾點事(實現一個具體的功能)。以前,也在網絡上搜了不少關於Interceptor的文章,但感受內容都大同小異,並且知識點零零散散,不太方便閱讀。所以,正好藉此機會,整理一篇關於攔截器的文章,在此分享給你們,以供你們參考閱讀。java

2 攔截器

2.1 概念

  Java 裏的攔截器是動態攔截 action 調用的對象。它提供了一種機制可使開發者能夠定義在一個 action 執行的先後執行的代碼,也能夠在一個 action 執行前阻止其執行,同時也提供了一種能夠提取 action 中可重用部分的方式。在AOP(Aspect-Oriented Programming,面向切面編程)中攔截器用於在某個方法或字段被訪問以前進行攔截,而後在以前或以後加入某些操做。web

2.2 原理

  攔截器 Interceptor 的攔截功能是基於 Java 的動態代理來實現的,具體能夠參考博文「 用 Java 實現攔截器 Interceptor 的攔截功能 」,也能夠經過閱讀 Spring 源代碼來了解更爲權威的實現細節。spring

3 實現方法

  在 Spring 框架之中,我們要想實現攔截器的功能,主要經過兩種途徑,第一種是實現HandlerInterceptor接口,第二種是實現WebRequestInterceptor接口。接下來,我們分別詳細的介紹二者的實現方法。apache

3.1 HandlerInterceptor 接口

HandlerInterceptor接口中,定義了 3 個方法,分別爲preHandle()postHandle()afterCompletion(),我們就是經過複寫這 3 個方法來對用戶的請求進行攔截處理的。所以,我們能夠經過直接實現HandlerInterceptor接口來實現攔截器的功能。不過在 Spring 框架之中,其還提供了另一個接口和一個抽象類,實現了對HandlerInterceptor接口的功能擴展,分別爲:AsyncHandlerInterceptorHandlerInterceptorAdapter.編程

對於AsyncHandlerInterceptor接口,其在繼承HandlerInterceptor接口的同時,又聲明瞭一個新的方法afterConcurrentHandlingStarted();而HandlerInterceptorAdapter抽象類,則是更進一步,在其繼承AsyncHandlerInterceptor接口的同時,又複寫了preHandle方法。所以,AsyncHandlerInterceptor更像是一個過渡的接口。spring-mvc

在實際應用中,我們通常都是經過實現HandlerInterceptor接口或者繼承HandlerInterceptorAdapter抽象類,複寫preHandle()postHandle()afterCompletion()這 3 個方法來對用戶的請求進行攔截處理的。下面,我們就詳細介紹這個 3 個方法。網絡

  • preHandle(HttpServletRequest request, HttpServletResponse response, Object handle)方法,該方法在請求處理以前進行調用。SpringMVC 中的 Interceptor 是鏈式調用的,在一個應用中或者說是在一個請求中能夠同時存在多個 Interceptor 。每一個 Interceptor 的調用會依據它的聲明順序依次執行,並且最早執行的都是 Interceptor 中的 preHandle 方法,因此能夠在這個方法中進行一些前置初始化操做或者是對當前請求作一個預處理,也能夠在這個方法中進行一些判斷來決定請求是否要繼續進行下去。該方法的返回值是布爾值 Boolean 類型的,當它返回爲 false 時,表示請求結束,後續的 Interceptor 和 Controller 都不會再執行;當返回值爲 true 時,就會繼續調用下一個 Interceptor 的 preHandle 方法,若是已是最後一個 Interceptor 的時候,就會是調用當前請求的 Controller 中的方法。
  • postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView)方法,經過 preHandle 方法的解釋我們知道這個方法包括後面要說到的 afterCompletion 方法都只能在當前所屬的 Interceptor 的 preHandle 方法的返回值爲 true 的時候,才能被調用。postHandle 方法在當前請求進行處理以後,也就是在 Controller 中的方法調用以後執行,可是它會在 DispatcherServlet 進行視圖返回渲染以前被調用,因此我們能夠在這個方法中對 Controller 處理以後的 ModelAndView 對象進行操做。postHandle 方法被調用的方向跟 preHandle 是相反的,也就是說,先聲明的 Interceptor 的 postHandle 方法反而會後執行。這和 Struts2 裏面的 Interceptor 的執行過程有點類型,Struts2 裏面的 Interceptor 的執行過程也是鏈式的,只是在 Struts2 裏面須要手動調用 ActionInvocation 的 invoke 方法來觸發對下一個 Interceptor 或者是 action 的調用,而後每個 Interceptor 中在 invoke 方法調用以前的內容都是按照聲明順序執行的,而 invoke 方法以後的內容就是反向的。
  • afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)方法,也是須要當前對應的 Interceptor 的 preHandle 方法的返回值爲 true 時纔會執行。所以,該方法將在整個請求結束以後,也就是在 DispatcherServlet 渲染了對應的視圖以後執行,這個方法的主要做用是用於進行資源清理的工做。

接下來,我們在看看以上接口和抽象類的具體代碼:session

HandlerInterceptor 接口:mvc

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface HandlerInterceptor {

    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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

AsyncHandlerInterceptor 接口:app

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface AsyncHandlerInterceptor extends HandlerInterceptor {

    void afterConcurrentHandlingStarted(
            HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

HandlerInterceptorAdapter 抽象類:

package org.springframework.web.servlet.handler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * Abstract adapter class for the HandlerInterceptor interface,
 * for simplified implementation of pre-only/post-only interceptors.
 *
 * @author Juergen Hoeller
 * @since 05.12.2003
 */
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {

    /**
     * This implementation always returns {@code true}.
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
        return true;
    }

    /**
     * This implementation is empty.
     */
    public void postHandle(
            HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception {
    }

    /**
     * This implementation is empty.
     */
    public void afterCompletion(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
    }

    /**
     * This implementation is empty.
     */
    public void afterConcurrentHandlingStarted(
            HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

如上面的代碼所示,其實在HandlerInterceptorAsyncHandlerInterceptor中還有不少的代碼註釋,只是博主感受太多了,就將其所有刪除啦!若是你們對這些註釋感興趣的話,能夠自行查看源代碼。下面,我們以繼承HandlerInterceptorAdapter抽象類爲例進行演示:

package com.hit.interceptor;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author 維C果糖
 * @create 2017-03-31
 */

public class WrongCodeInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("WrongCodeInterceptor, preHandle......");
        return true;
    }

    @Override
    public void postHandle(
            HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception {
        System.out.println("WrongCodeInterceptor, postHandle......");
    }

    @Override
    public void afterCompletion(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("WrongCodeInterceptor, afterCompletion......");
    }

    @Override
    public void afterConcurrentHandlingStarted(
            HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("WrongCodeInterceptor, afterConcurrentHandlingStarted......");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

3.2 WebRequestInterceptor 接口

WebRequestInterceptor接口中也定義了 3 個方法,同HandlerInterceptor接口徹底相同,我們也是經過複寫這 3 個方法來用戶的請求進行攔截處理的。並且這 3 個方法都傳遞了同一個參數 WebRequest,那麼這個 WebRequest 究竟是什麼呢?其實這個 WebRequest 是 Spring 中定義的一個接口,它裏面的方法定義跟 HttpServletRequest 相似,在WebRequestInterceptor中對 WebRequest 進行的全部操做都將同步到 HttpServletRequest 中,而後在當前請求中依次傳遞。

在 Spring 框架之中,還提供了一個和WebRequestInterceptor接口長的很像的抽象類,那就是:WebRequestInterceptorAdapter,其實現了AsyncHandlerInterceptor接口,並在內部調用了WebRequestInterceptor接口。

接下來,我們主要講一下WebRequestInterceptor接口的 3 個函數:

  • preHandle(WebRequest request)方法,該方法在請求處理以前進行調用,也就是說,其會在 Controller 中的方法調用以前被調用。這個方法跟 HandlerInterceptor 中的 preHandle 不一樣,主要區別在於該方法的返回值是void 類型的,也就是沒有返回值,所以咱們主要用它來進行資源的準備工做,好比咱們在使用 Hibernate 的時候,能夠在這個方法中準備一個 Hibernate 的Session 對象,而後利用 WebRequest 的 setAttribute(name, value, scope) 把它放到 WebRequest 的屬性中。在這裏,進一步說說 setAttribute 方法的第三個參數 scope ,該參數是一個Integer 類型的。在 WebRequest 的父層接口 RequestAttributes 中對它定義了三個常量,分別爲:
    • SCOPE_REQUEST ,它的值是 0,表示只有在 request 中能夠訪問。
    • SCOPE_SESSION,它的值是1,若是環境容許的話,它表示的是一個局部的隔離的 session,不然就表明普通的 session,而且在該 session 範圍內能夠訪問。
    • SCOPE_GLOBAL_SESSION,它的值是 2,若是環境容許的話,它表示的是一個全局共享的 session,不然就表明普通的 session,而且在該 session 範圍內能夠訪問。
  • postHandle(WebRequest request, ModelMap model)方法,該方法在請求處理以後,也就是在 Controller 中的方法調用以後被調用,可是會在視圖返回被渲染以前被調用,因此能夠在這個方法裏面經過改變數據模型 ModelMap 來改變數據的展現。該方法有兩個參數,WebRequest 對象是用於傳遞整個請求數據的,好比在 preHandle 中準備的數據均可以經過 WebRequest 來傳遞和訪問;ModelMap 就是 Controller 處理以後返回的 Model 對象,我們能夠經過改變它的屬性來改變返回的 Model 模型。
  • afterCompletion(WebRequest request, Exception ex)方法,該方法會在整個請求處理完成,也就是在視圖返回並被渲染以後執行。所以能夠在該方法中進行資源的釋放操做。而 WebRequest 參數就能夠把我們在 preHandle 中準備的資源傳遞到這裏進行釋放。Exception 參數表示的是當前請求的異常對象,若是在 Controller 中拋出的異常已經被 Spring 的異常處理器給處理了的話,那麼這個異常對象就是是 null.

接下來,我們在看看以上接口和抽象類的具體代碼:

WebRequestInterceptor 接口:

package org.springframework.web.context.request;

import org.springframework.ui.ModelMap;

public interface WebRequestInterceptor {

    void preHandle(WebRequest request) throws Exception;

    void postHandle(WebRequest request, ModelMap model) throws Exception;

    void afterCompletion(WebRequest request, Exception ex) throws Exception;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

WebRequestInterceptorAdapter 抽象類:

package org.springframework.web.servlet.handler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.util.Assert;
import org.springframework.web.context.request.AsyncWebRequestInterceptor;
import org.springframework.web.context.request.WebRequestInterceptor;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * Adapter that implements the Servlet HandlerInterceptor interface
 * and wraps an underlying WebRequestInterceptor.
 *
 * @author Juergen Hoeller
 * @since 2.0
 * @see org.springframework.web.context.request.WebRequestInterceptor
 * @see org.springframework.web.servlet.HandlerInterceptor
 */
public class WebRequestHandlerInterceptorAdapter implements AsyncHandlerInterceptor {

    private final WebRequestInterceptor requestInterceptor;


    /**
     * Create a new WebRequestHandlerInterceptorAdapter for the given WebRequestInterceptor.
     * @param requestInterceptor the WebRequestInterceptor to wrap
     */
    public WebRequestHandlerInterceptorAdapter(WebRequestInterceptor requestInterceptor) {
        Assert.notNull(requestInterceptor, "WebRequestInterceptor must not be null");
        this.requestInterceptor = requestInterceptor;
    }


    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        this.requestInterceptor.preHandle(new DispatcherServletWebRequest(request, response));
        return true;
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception {

        this.requestInterceptor.postHandle(new DispatcherServletWebRequest(request, response),
                (modelAndView != null && !modelAndView.wasCleared() ? modelAndView.getModelMap() : null));
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {

        this.requestInterceptor.afterCompletion(new DispatcherServletWebRequest(request, response), ex);
    }

    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (this.requestInterceptor instanceof AsyncWebRequestInterceptor) {
            AsyncWebRequestInterceptor asyncInterceptor = (AsyncWebRequestInterceptor) this.requestInterceptor;
            DispatcherServletWebRequest webRequest = new DispatcherServletWebRequest(request, response);
            asyncInterceptor.afterConcurrentHandlingStarted(webRequest);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

如上面的代碼所示,展現了WebRequestInterceptor接口和WebRequestInterceptorAdapter抽象類的源碼。下面,我們以實現WebRequestInterceptor接口爲例進行演示:

package com.hit.interceptor;

import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;

/**
 * @author 維C果糖
 * @create 2017-03-31
 */

public class WrongCodeInterceptor implements WebRequestInterceptor {

    @Override
    public void preHandle(WebRequest request) throws Exception {
        System.out.println("WrongCodeInterceptor, preHandle......");
    }

    @Override
    public void postHandle(WebRequest request, ModelMap model) throws Exception {
        System.out.println("WrongCodeInterceptor, postHandle......");
    }

    @Override
    public void afterCompletion(WebRequest request, Exception ex) throws Exception {
        System.out.println("WrongCodeInterceptor, afterCompletion......");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

3.3 AbstractInterceptor 抽象類

除了上面3.2 和3.3所講的內容,我們還能夠經過繼承 Struts2 框架提供的AbstractInterceptor抽象類來實現攔截的功能。若是我們在深刻一點研究,會發現AbstractInterceptor實現了Interceptor接口,而Interceptor接口又繼承了Serializable接口。

Interceptor接口中,提供了 3 個方法供我們使用,分別爲init()destroy()intercept(),因爲AbstractInterceptor實現了Interceptor接口,所以我們就能夠直接繼承AbstractInterceptor,而後複寫方法就能夠啦!至於爲何繼承AbstractInterceptor而不是直接實現Interceptor接口,是由於AbstractInterceptor已經幫我們實現了空的init()destroy()方法,不須要我們本身去複寫了,我們直接複寫intercept()方法就能夠啦!如今,我們大體瞭解一下這 3 個方法的做用:

  • init()方法,通常用來進行初始化操做;
  • destroy()方法,通常用來進行釋放資源的操做;
  • intercept()方法,該方法是實現攔截功能的主要方法,我們就在該方法中編寫攔截的邏輯。

接下來,我們在看看以上接口和抽象類的具體代碼:

Interceptor 接口:

package com.opensymphony.xwork2.interceptor;

import com.opensymphony.xwork2.ActionInvocation;

import java.io.Serializable;

public interface Interceptor extends Serializable {

    /**
     * Called to let an interceptor clean up any resources it has allocated.
     */
    void destroy();

    /**
     * Called after an interceptor is created, but before any requests are processed using
     * {@link #intercept(com.opensymphony.xwork2.ActionInvocation) intercept} , giving
     * the Interceptor a chance to initialize any needed resources.
     */
    void init();

    /**
     * Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the
     * request by the {@link ActionInvocation} or to short-circuit the processing and just return a String return code.
     *
     * @param invocation the action invocation
     * @return the return code, either returned from {@link ActionInvocation#invoke()}, or from the interceptor itself.
     * @throws Exception any system-level error, as defined in {@link com.opensymphony.xwork2.Action#execute()}.
     */
    String intercept(ActionInvocation invocation) throws Exception;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

AbstractInterceptor 接口:

package com.opensymphony.xwork2.interceptor;

import com.opensymphony.xwork2.ActionInvocation;

/**
 * Provides default implementations of optional lifecycle methods
 */
public abstract class AbstractInterceptor implements Interceptor {

    /**
     * Does nothing
     */
    public void init() {
    }

    /**
     * Does nothing
     */
    public void destroy() {
    }

    /**
     * Override to handle interception
     */
    public abstract String intercept(ActionInvocation invocation) throws Exception;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

如上面的代碼所示,展現了Interceptor接口和AbstractInterceptor抽象類的源碼。下面,我們以繼承AbstractInterceptor抽象類爲例進行演示:

package com.hit.interceptor;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import org.apache.struts2.ServletActionContext;


/**
 * @author 維C果糖
 * @create 2017-03-31
 */

public class WrongCodeInterceptor  extends AbstractInterceptor {

    /**
     * 經過攔截功能,驗證用戶是否登陸
     */
    public String intercept(ActionInvocation invocation) throws Exception {

        UserInfo info = (UserInfo) ServletActionContext.getRequest().getSession().getAttribute("user");

        if(info != null && !info.getName().equals("") && !info.getPwd().equals(""))
        {
            return invocation.invoke();
        }
        return "login";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

UserInfo 類文件:

/**
 * @author 維C果糖
 * @create 2017-03-31
 */

public class UserInfo {
    String name;
    String pwd;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

4 配置攔截器

在前面,我們用了很大篇幅的內容講述了攔截器如何實現,所以,我相信你們實現攔截器已經沒有問題啦!接下來,我們在看看,如何在 XML 文件中配置攔截器,使我們的攔截器生效。

在配置攔截器以前,有 4 個名稱的概念須要你們先了解一下,分別爲:Join PointPointcutAdviceAdvisor.

  • Join Point,表示「鏈接點」,它是程序運行中的某個階段點,好比方法的調用、異常的拋出等;
  • Advice,表示「通知」,它是某個鏈接點所採用的處理邏輯,也就是向鏈接點注入的代碼;
  • Pointcut,表示「切入點」,它是「鏈接點」的集合,是程序中須要注入 Advice 的位置的集合,指明 Advice 要在什麼樣的條件下才能被觸發;
  • Advisor,它是 Pointcut 和 Advice 的配置器,包括 Pointcut 和 Advice,是將 Advice 注入程序中 Pointcut 位置的代碼。

接下來,給出 XML 配置文件的聲明:

<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:mvc="http://www.springframework.org/schema/mvc"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
     http://www.springframework.org/schema/context  
     http://www.springframework.org/schema/context/spring-context-3.0.xsd  
     http://www.springframework.org/schema/mvc  
     http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在 XML 文件的頭部聲明完以後,我們就能夠在 Spring 的配置文件中就可使用mvc標籤啦!而在mvc標籤中有一個名爲mvc:interceptors的標籤,該標籤就是用於聲明 Spring 攔截器的。下面,給出一個配置示例:

<mvc:interceptors>  
    <!-- 使用 bean 定義一個 Interceptor,直接定義在 mvc:interceptors 下面的 Interceptor 將攔截全部的請求 -->  
    <bean class="com.hit.interceptor.WrongCodeInterceptor"/>  
    <mvc:interceptor>  
        <mvc:mapping path="/demo/hello.do"/>  
        <!-- 定義在 mvc:interceptor 下面的 Interceptor,表示對特定的請求進行攔截 -->  
        <bean class="com.hit.interceptor.LoginInterceptor"/>  
    </mvc:interceptor>  
</mvc:interceptors>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在 Spring 的XML 配置文件中,我們能夠經過mvc:interceptors標籤聲明一系列的攔截器,例如:

<mvc:interceptors>
        <bean class="com.hit.interceptor.ContextInterceptor"/>
        <bean class="com.hit.interceptor.LoginInterceptor"/>
        <bean class="com.hit.interceptor.WrongCodeInterceptor"/>
    </mvc:interceptors>
  • 1
  • 2
  • 3
  • 4
  • 5

如上所示,這些攔截器就夠成了一個攔截器鏈,或者稱之爲攔截器棧。而這些攔截器的執行順序是按聲明的前後順序執行的,即:先聲明的攔截器先執行,後聲明的攔截器後執行。在mvc:interceptors標籤下聲明interceptor標籤主要有兩種方式:

  • 直接定義一個 Interceptor 實現類的 bean 對象,使用這種方式聲明的 Interceptor 攔截器將會對全部的請求進行攔截;
  • 使用mvc:interceptor標籤進行聲明,使用這種方式進行聲明的 Interceptor 能夠經過mvc:mapping子標籤來定義須要進行攔截的請求路徑。

此外,因爲攔截器是 AOP 編程思想的典型應用,也就意味着我們能夠「切」到具體的「面」進行某些操做。例如,

<bean id="WrongCodeInterceptor" class="com.hit.interceptor.WrongCodeInterceptor">
        <property name="userName" value="user-module"></property>
</bean>

<bean id="loginInterceptor" class="com.hit.interceptor.LoginInterceptor">
    <property name="excludePackages">
       <list>
          <value>com.hit.user.exception</value>
          <value>com.hit.order.exception</value>
       </list>
    </property>
</bean>

<aop:config>
    <aop:advisor advice-ref="WrongCodeInterceptor" pointcut="execution(* com.hit.*.demo..*.*(..)) || execution(* com.hit.*.demo..*.*(..)) " />
    <aop:advisor advice-ref="loginInterceptor" pointcut="execution(* com.hit.*.demo..*.*(..))" />
</aop:config>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

如上所示,我們實現了切入到「面」進行特定的攔截功能,其中pointcut表示「切入點」,advisor表示要注入到pointcut的代碼。你們可能會對pointcut中的*符合有所疑惑,它是「通配符」,表示能夠匹配該位置上的任何名稱。固然,若是我們要想使用aop標籤,就得先在配置文件中就得進行聲明啦!此外,若是你們想進一步瞭解切入點pointcut的表達式的話,能夠參考博文「 Spring 框架中切入點 pointcut 表達式的經常使用寫法 」。

相關文章
相關標籤/搜索