關(guān)于Spring MVC框架中攔截器Interceptor的使用解讀
1 前言
網(wǎng)絡(luò)上關(guān)于Interceptor的文章,但感覺(jué)內(nèi)容都大同小異,而且知識(shí)點(diǎn)零零散散,不太方便閱讀。
因此,整理一篇關(guān)于攔截器的文章,在此分享給大家,以供大家參考閱讀。
2 攔截器
2.1 概念
Java 里的攔截器是動(dòng)態(tài)攔截action調(diào)用的對(duì)象。它提供了一種機(jī)制可以使開發(fā)者可以定義在一個(gè)action執(zhí)行的前后執(zhí)行的代碼,也可以在一個(gè)action執(zhí)行前阻止其執(zhí)行,同時(shí)也提供了一種可以提取action中可重用部分的方式。
在 AOP(Aspect-Oriented Programming,面向切面編程)中攔截器用于在某個(gè)方法(包括構(gòu)造器)或字段被訪問(wèn)之前進(jìn)行攔截,然后在之前或之后加入某些操作。
特別地,現(xiàn)階段 Spring 自身僅支持基于方法的攔截操作!如果基于方法的攔截操作不能滿足需求,可以使用 AspectJ 與 Spring 進(jìn)行集成,以實(shí)現(xiàn)更細(xì)粒度或更多方面的攔截操作。
2.2 原理
攔截器Interceptor的攔截功能是基于 Java 的動(dòng)態(tài)代理來(lái)實(shí)現(xiàn)的,具體可以參考博文「用 Java 實(shí)現(xiàn)攔截器 Interceptor 的攔截功能 」,也可以通過(guò)閱讀 Spring 源代碼來(lái)了解更為權(quán)威的實(shí)現(xiàn)細(xì)節(jié)。
3 實(shí)現(xiàn)方法
在 Spring 框架之中,我們要想實(shí)現(xiàn)攔截器的功能,主要通過(guò)兩種途徑,第一種是實(shí)現(xiàn)HandlerInterceptor接口,第二種是實(shí)現(xiàn)WebRequestInterceptor接口。接下來(lái),我們分別詳細(xì)的介紹兩者的實(shí)現(xiàn)方法。
3.1 HandlerInterceptor 接口
在HandlerInterceptor接口中,定義了 3 個(gè)方法,分別為preHandle()、postHandle()和afterCompletion(),我們就是通過(guò)復(fù)寫這 3 個(gè)方法來(lái)對(duì)用戶的請(qǐng)求進(jìn)行攔截處理的。
因此,我們可以通過(guò)直接實(shí)現(xiàn)HandlerInterceptor接口來(lái)實(shí)現(xiàn)攔截器的功能。不過(guò)在 Spring 框架之中,其還提供了另外一個(gè)接口和一個(gè)抽象類,實(shí)現(xiàn)了對(duì)HandlerInterceptor接口的功能擴(kuò)展,分別為:AsyncHandlerInterceptor和HandlerInterceptorAdapter.
對(duì)于AsyncHandlerInterceptor接口,其在繼承HandlerInterceptor接口的同時(shí),又聲明了一個(gè)新的方法afterConcurrentHandlingStarted();而HandlerInterceptorAdapter抽象類,則是更進(jìn)一步,在其繼承AsyncHandlerInterceptor接口的同時(shí),又復(fù)寫了preHandle方法。因此,AsyncHandlerInterceptor更像是一個(gè)過(guò)渡的接口。
在實(shí)際應(yīng)用中,我們一般都是通過(guò)實(shí)現(xiàn)HandlerInterceptor接口或者繼承HandlerInterceptorAdapter抽象類,復(fù)寫preHandle()、postHandle()和afterCompletion()這 3 個(gè)方法來(lái)對(duì)用戶的請(qǐng)求進(jìn)行攔截處理的。
下面,我們就詳細(xì)介紹這個(gè) 3 個(gè)方法。
preHandle(HttpServletRequest request, HttpServletResponse response, Object handle)方法
該方法在請(qǐng)求處理之前進(jìn)行調(diào)用。
Spring MVC 中的Interceptor是鏈?zhǔn)秸{(diào)用的,在一個(gè)應(yīng)用中或者說(shuō)是在一個(gè)請(qǐng)求中可以同時(shí)存在多個(gè)Interceptor。
每個(gè)Interceptor的調(diào)用會(huì)依據(jù)它的聲明順序依次執(zhí)行,而且最先執(zhí)行的都是Interceptor中的preHandle方法,所以可以在這個(gè)方法中進(jìn)行一些前置初始化操作或者是對(duì)當(dāng)前請(qǐng)求做一個(gè)預(yù)處理,也可以在這個(gè)方法中進(jìn)行一些判斷來(lái)決定請(qǐng)求是否要繼續(xù)進(jìn)行下去。
該方法的返回值是布爾(Boolean)類型的,當(dāng)它返回為false時(shí),表示請(qǐng)求結(jié)束,后續(xù)的Interceptor和控制器(Controller)都不會(huì)再執(zhí)行;當(dāng)返回值為true時(shí),就會(huì)繼續(xù)調(diào)用下一個(gè)Interceptor的preHandle方法,如果已經(jīng)是最后一個(gè)Interceptor的時(shí)候,就會(huì)是調(diào)用當(dāng)前請(qǐng)求的控制器中的方法。
postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView)方法
通過(guò)preHandle方法的解釋,我們知道這個(gè)方法包括后面要說(shuō)到的afterCompletion方法都只能在當(dāng)前所屬的Interceptor的preHandle方法的返回值為true的時(shí)候,才能被調(diào)用。
postHandle方法在當(dāng)前請(qǐng)求進(jìn)行處理之后,也就是在控制器中的方法調(diào)用之后執(zhí)行,但是它會(huì)在DispatcherServlet進(jìn)行視圖返回渲染之前被調(diào)用,所以我們可以在這個(gè)方法中對(duì)控制器處理之后的ModelAndView對(duì)象進(jìn)行操作。
postHandle方法被調(diào)用的方向跟preHandle是相反的,也就是說(shuō),先聲明的Interceptor的postHandle方法反而會(huì)后執(zhí)行。
這和 Struts2 里面的Interceptor的執(zhí)行過(guò)程有點(diǎn)類似,Struts2 里面的Interceptor的執(zhí)行過(guò)程也是鏈?zhǔn)降?,只是?Struts2 里面需要手動(dòng)調(diào)用ActionInvocation的invoke方法來(lái)觸發(fā)對(duì)下一個(gè)Interceptor或者是action的調(diào)用,然后每一個(gè)Interceptor中在invoke方法調(diào)用之前的內(nèi)容都是按照聲明順序執(zhí)行的,而invoke方法之后的內(nèi)容就是反向的。
afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)方法
也是需要當(dāng)前對(duì)應(yīng)的Interceptor的preHandle方法的返回值為true時(shí)才會(huì)執(zhí)行。
因此,該方法將在整個(gè)請(qǐng)求結(jié)束之后,也就是在DispatcherServlet渲染了對(duì)應(yīng)的視圖之后執(zhí)行,這個(gè)方法的主要作用是用于進(jìn)行資源清理的工作。
接下來(lái),我們?cè)诳纯匆陨辖涌诤统橄箢惖木唧w代碼:
HandlerInterceptor接口:
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;
}AsyncHandlerInterceptor接口:
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;
}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 {
}
}如上面的代碼所示,其實(shí)在HandlerInterceptor和AsyncHandlerInterceptor中還有很多的代碼注釋,只是博主感覺(jué)太多了,就將其全部刪除了。
如果大家對(duì)這些注釋感興趣的話,可以自行查看源代碼。
下面,我們以繼承HandlerInterceptorAdapter抽象類為例進(jìn)行演示:
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......");
}
}3.2 WebRequestInterceptor 接口
在WebRequestInterceptor接口中也定義了 3 個(gè)方法,同HandlerInterceptor接口完全相同,我們也是通過(guò)復(fù)寫這 3 個(gè)方法來(lái)對(duì)用戶的請(qǐng)求進(jìn)行攔截處理的。
而且這 3 個(gè)方法都傳遞了同一個(gè)參數(shù)WebRequest,那么這個(gè)WebRequest到底是什么呢?
其實(shí)這個(gè)WebRequest是 Spring 中定義的一個(gè)接口,它里面的方法定義跟HttpServletRequest類似,在WebRequestInterceptor中對(duì)WebRequest進(jìn)行的所有操作都將同步到HttpServletRequest中,然后在當(dāng)前請(qǐng)求中依次傳遞。
在 Spring 框架之中,還提供了一個(gè)和WebRequestInterceptor接口長(zhǎng)的很像的抽象類,那就是:WebRequestInterceptorAdapter,其實(shí)現(xiàn)了AsyncHandlerInterceptor接口,并在內(nèi)部調(diào)用了WebRequestInterceptor接口。
接下來(lái),我們主要講一下WebRequestInterceptor接口的 3 個(gè)函數(shù):
preHandle(WebRequest request)方法
該方法在請(qǐng)求處理之前進(jìn)行調(diào)用,也就是說(shuō),其會(huì)在控制器中的方法調(diào)用之前被調(diào)用。
這個(gè)方法跟HandlerInterceptor中的preHandle不同,主要區(qū)別在于該方法的返回值是void類型的,也就是沒(méi)有返回值,因此我們主要用它來(lái)進(jìn)行資源的準(zhǔn)備工作,比如我們?cè)谑褂?Hibernate 的時(shí)候,可以在這個(gè)方法中準(zhǔn)備一個(gè) Hibernate 的Session對(duì)象,然后利用WebRequest的setAttribute(name, value, scope)把它放到WebRequest的屬性中。
在這里,進(jìn)一步說(shuō)說(shuō)setAttribute方法的第三個(gè)參數(shù)scope,該參數(shù)是一個(gè)Integer類型的。
在WebRequest的父層接口RequestAttributes中對(duì)它定義了三個(gè)常量,
分別為:
SCOPE_REQUEST,它的值是0,表示只有在request中可以訪問(wèn)。
SCOPE_SESSION,它的值是1,如果環(huán)境允許的話,它表示的是一個(gè)局部的隔離的session,否則就代表普通的session,并且在該session范圍內(nèi)可以訪問(wèn)。
SCOPE_GLOBAL_SESSION,它的值是2,如果環(huán)境允許的話,它表示的是一個(gè)全局共享的session,否則就代表普通的session,并且在該session范圍內(nèi)可以訪問(wèn)。
postHandle(WebRequest request, ModelMap model)方法
該方法在請(qǐng)求處理之后,也就是在控制器中的方法調(diào)用之后被調(diào)用,但是會(huì)在視圖返回被渲染之前被調(diào)用,所以可以在這個(gè)方法里面通過(guò)改變數(shù)據(jù)模型ModelMap來(lái)改變數(shù)據(jù)的展示。該方法有兩個(gè)參數(shù),WebRequest對(duì)象是用于傳遞整個(gè)請(qǐng)求數(shù)據(jù)的,比如在preHandle中準(zhǔn)備的數(shù)據(jù)都可以通過(guò)WebRequest來(lái)傳遞和訪問(wèn);ModelMap就是控制器處理之后返回的Model對(duì)象,我們可以通過(guò)改變它的屬性來(lái)改變返回的Model模型。
afterCompletion(WebRequest request, Exception ex)方法
該方法會(huì)在整個(gè)請(qǐng)求處理完成,也就是在視圖返回并被渲染之后執(zhí)行。因此可以在該方法中進(jìn)行資源的釋放操作。而WebRequest參數(shù)就可以把我們?cè)?code>preHandle中準(zhǔn)備的資源傳遞到這里進(jìn)行釋放。
Exception參數(shù)表示的是當(dāng)前請(qǐng)求的異常對(duì)象,如果在控制器中拋出的異常已經(jīng)被 Spring 的異常處理器給處理了的話,那么這個(gè)異常對(duì)象就是是null。
接下來(lái),我們?cè)诳纯匆陨辖涌诤统橄箢惖木唧w代碼:
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;
}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);
}
}
}如上面的代碼所示,展示了WebRequestInterceptor接口和WebRequestInterceptorAdapter抽象類的源碼。
下面,我們以實(shí)現(xiàn)WebRequestInterceptor接口為例進(jìn)行演示:
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......");
}
}3.3 AbstractInterceptor 抽象類
除了上面3.2 和3.3所講的內(nèi)容,我們還可以通過(guò)繼承 Struts2 框架提供的AbstractInterceptor抽象類來(lái)實(shí)現(xiàn)攔截的功能。如果我們?cè)谏钊胍稽c(diǎn)研究,會(huì)發(fā)現(xiàn)AbstractInterceptor實(shí)現(xiàn)了Interceptor接口,而Interceptor接口又繼承了Serializable接口。
在Interceptor接口中,提供了 3 個(gè)方法供我們使用,分別為init()、destroy()和intercept(),由于AbstractInterceptor實(shí)現(xiàn)了Interceptor接口,因此我們就可以直接繼承AbstractInterceptor,然后復(fù)寫方法就可以啦!
至于為什么繼承AbstractInterceptor而不是直接實(shí)現(xiàn)Interceptor接口,是因?yàn)?code>AbstractInterceptor已經(jīng)幫我們實(shí)現(xiàn)了空的init()和destroy()方法,不需要我們自己去復(fù)寫了,我們直接復(fù)寫intercept()方法就可以了。
現(xiàn)在,我們大致了解一下這 3 個(gè)方法的作用:
init()方法,一般用來(lái)進(jìn)行初始化操作;destroy()方法,一般用來(lái)進(jìn)行釋放資源的操作;intercept()方法,該方法是實(shí)現(xiàn)攔截功能的主要方法,我們就在該方法中編寫攔截的邏輯。
接下來(lái),我們?cè)倏纯匆陨辖涌诤统橄箢惖木唧w代碼:
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;
}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;
}如上面的代碼所示,展示了Interceptor接口和AbstractInterceptor抽象類的源碼。
下面,我們以繼承AbstractInterceptor抽象類為例進(jìn)行演示:
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 {
/**
* 通過(guò)攔截功能,驗(yàn)證用戶是否登錄
*/
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";
}
}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;
}
}4 配置攔截器
在前面,我們用了很大篇幅的內(nèi)容講述了攔截器如何實(shí)現(xiàn),因此,我相信大家對(duì)于如何實(shí)現(xiàn)攔截器已經(jīng)沒(méi)有問(wèn)題啦!
接下來(lái),我們?cè)诳纯?,如何?XML 文件中配置攔截器,以使我們的攔截器生效。
在配置攔截器之前,有 4 個(gè)名稱的概念需要大家先了解一下,分別為:Join Point、Pointcut、Advice和Advisor:
Join Point,表示“連接點(diǎn)”,它是程序運(yùn)行中的某個(gè)階段點(diǎn),比如方法的調(diào)用、異常的拋出等;Advice,表示“通知”,它是某個(gè)連接點(diǎn)所采用的處理邏輯,也就是向連接點(diǎn)注入的代碼;Pointcut,表示“切入點(diǎn)”,它是“連接點(diǎn)”的集合,是程序中需要注入Advice的位置的集合,指明Advice要在什么樣的條件下才能被觸發(fā);Advisor,它是Pointcut和Advice的配置器,包括Pointcut和Advice,是將Advice注入程序中Pointcut位置的代碼。
接下來(lái),給出 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"> 在 XML 文件的頭部聲明完成之后,我們就可以在 Spring 的配置文件中使用mvc標(biāo)簽啦!
而在mvc標(biāo)簽中有一個(gè)名為mvc:interceptors的標(biāo)簽,該標(biāo)簽就是用于聲明 Spring 攔截器的。
下面,給出一個(gè)配置示例:
<mvc:interceptors>
<!-- 使用 bean 定義一個(gè) Interceptor,直接定義在 mvc:interceptors 下面的 Interceptor 將攔截所有的請(qǐng)求 -->
<bean class="com.hit.interceptor.WrongCodeInterceptor"/>
<mvc:interceptor>
<mvc:mapping path="/demo/hello.do"/>
<!-- 定義在 mvc:interceptor 下面的 Interceptor,表示對(duì)特定的請(qǐng)求進(jìn)行攔截 -->
<bean class="com.hit.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors> 在 Spring 的XML 配置文件中,我們可以通過(guò)mvc:interceptors標(biāo)簽聲明一系列的攔截器,例如:
<mvc:interceptors>
<bean class="com.hit.interceptor.ContextInterceptor"/>
<bean class="com.hit.interceptor.LoginInterceptor"/>
<bean class="com.hit.interceptor.WrongCodeInterceptor"/>
</mvc:interceptors>如上所示,這些攔截器就構(gòu)成了一個(gè)攔截器鏈,或者稱之為攔截器棧。這些攔截器的執(zhí)行順序是按聲明的先后順序執(zhí)行的,即:先聲明的攔截器先執(zhí)行,后聲明的攔截器后執(zhí)行。
在mvc:interceptors標(biāo)簽下聲明interceptor標(biāo)簽主要有兩種方式:
- 直接定義一個(gè)
Interceptor實(shí)現(xiàn)類的bean對(duì)象,使用這種方式聲明的Interceptor攔截器將會(huì)對(duì)所有的請(qǐng)求進(jìn)行攔截; - 使用
mvc:interceptor標(biāo)簽進(jìn)行聲明,使用這種方式進(jìn)行聲明的Interceptor可以通過(guò)mvc:mapping子標(biāo)簽來(lái)定義需要進(jìn)行攔截的請(qǐng)求路徑。
此外,由于攔截器是 AOP 編程思想的典型應(yīng)用,也就意味著我們可以“切”到具體的“面”進(jìn)行某些操作。例如,
<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..*.*(..)) " /> <aop:advisor advice-ref="loginInterceptor" pointcut="execution(* com.hit.*.demo..*.*(..))" /> </aop:config>
如上所示,我們實(shí)現(xiàn)了切入到“面”進(jìn)行特定的攔截功能,其中pointcut表示“切入點(diǎn)”,advisor表示要注入到pointcut的代碼。
實(shí)際上,如果在多個(gè)攔截器配置中,pointcut表達(dá)式都相同,我們可以將其抽取出來(lái),單獨(dú)聲明,然后通過(guò)pointcut-ref標(biāo)簽進(jìn)行引用,這樣可以稍微簡(jiǎn)化一些配置!
除此之外,大家可能會(huì)對(duì)pointcut中的*符號(hào)有所疑惑,它是“通配符”,表示可以匹配該位置上的任何名稱。
當(dāng)然,如果我們要想使用aop標(biāo)簽,就得先在配置文件中進(jìn)行聲明啦!
最后,如果大家想進(jìn)一步了解切入點(diǎn)pointcut表達(dá)式的話,可以參考「Spring 框架中切入點(diǎn) pointcut 表達(dá)式的常用寫法 」。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Jdbc的步驟以及簡(jiǎn)單實(shí)現(xiàn)代碼
下面小編就為大家?guī)?lái)一篇Jdbc的步驟以及簡(jiǎn)單實(shí)現(xiàn)代碼。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-07-07
解決Spring Batch框架job任務(wù)只跑一次的問(wèn)題
這篇文章主要介紹了解決Spring Batch框架job任務(wù)只跑一次的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
Java中的break和continue關(guān)鍵字的使用方法總結(jié)
下面小編就為大家?guī)?lái)一篇Java中的break和continue關(guān)鍵字的使用方法總結(jié)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-11-11
SpringBoot中使用Session共享實(shí)現(xiàn)分布式部署的示例代碼
這篇文章主要介紹了SpringBoot中使用Session共享實(shí)現(xiàn)分布式部署的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
Java實(shí)現(xiàn)監(jiān)聽UDP協(xié)議的指定端口并收到數(shù)據(jù)按照十六進(jìn)制輸出方式
這篇文章主要介紹了Java實(shí)現(xiàn)監(jiān)聽UDP協(xié)議的指定端口并收到數(shù)據(jù)按照十六進(jìn)制輸出方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04
Java 實(shí)戰(zhàn)項(xiàng)目錘煉之網(wǎng)上圖書館管理系統(tǒng)的實(shí)現(xiàn)流程
讀萬(wàn)卷書不如行萬(wàn)里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用Java+jsp+servlet+mysql+ajax實(shí)現(xiàn)一個(gè)網(wǎng)上圖書館管理系統(tǒng),大家可以在過(guò)程中查缺補(bǔ)漏,提升水平2021-11-11

