在spring-boot工程中添加spring mvc攔截器
1. 認(rèn)識(shí)攔截器
Spring MVC的攔截器(Interceptor)不是Filter,同樣可以實(shí)現(xiàn)請(qǐng)求的預(yù)處理、后處理。使用攔截器僅需要兩個(gè)步驟:
- 實(shí)現(xiàn)攔截器
- 注冊(cè)攔截器
1.1 實(shí)現(xiàn)攔截器
實(shí)現(xiàn)攔截器可以自定義實(shí)現(xiàn)HandlerInterceptor接口,也可以通過(guò)繼承HandlerInterceptorAdapter類,后者是前者的實(shí)現(xiàn)類。下面是攔截器的一個(gè)實(shí)現(xiàn)的例子,目的是判斷用戶是否登錄。如果preHandle方法return true,則繼續(xù)后續(xù)處理。
public class LoginInterceptor extends HandlerInterceptorAdapter {
/**
*預(yù)處理回調(diào)方法,實(shí)現(xiàn)處理器的預(yù)處理(如登錄檢查)。
*第三個(gè)參數(shù)為響應(yīng)的處理器,即controller。
*返回true,表示繼續(xù)流程,調(diào)用下一個(gè)攔截器或者處理器。
*返回false,表示流程中斷,通過(guò)response產(chǎn)生響應(yīng)。
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
System.out.println("-------------------preHandle");
// 驗(yàn)證用戶是否登陸
Object obj = request.getSession().getAttribute("username");
if (obj == null || !(obj instanceof String)) {
response.sendRedirect(request.getContextPath() + "/index.html");
return false;
}
return true;
}
/**
*當(dāng)前請(qǐng)求進(jìn)行處理之后,也就是Controller 方法調(diào)用之后執(zhí)行,
*但是它會(huì)在DispatcherServlet 進(jìn)行視圖返回渲染之前被調(diào)用。
*此時(shí)我們可以通過(guò)modelAndView對(duì)模型數(shù)據(jù)進(jìn)行處理或?qū)σ晥D進(jìn)行處理。
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("-------------------postHandle");
}
/**
*方法將在整個(gè)請(qǐng)求結(jié)束之后,也就是在DispatcherServlet 渲染了對(duì)應(yīng)的視圖之后執(zhí)行。
*這個(gè)方法的主要作用是用于進(jìn)行資源清理工作的。
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
System.out.println("-------------------afterCompletion");
}
}
1.2 注冊(cè)攔截器
為了使自定義的攔截器生效,需要注冊(cè)攔截器到spring容器中,具體的做法是繼承WebMvcConfigurerAdapter類,覆蓋其addInterceptors(InterceptorRegistry registry)方法。最后別忘了把Bean注冊(cè)到Spring容器中,可以選擇@Component 或者 @Configuration。
@Component
public class InterceptorConfiguration extends WebMvcConfigurerAdapter{
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注冊(cè)攔截器
InterceptorRegistration ir = registry.addInterceptor(new LoginInterceptor());
// 配置攔截的路徑
ir.addPathPatterns("/**");
// 配置不攔截的路徑
ir.excludePathPatterns("/**.html");
// 還可以在這里注冊(cè)其它的攔截器
//registry.addInterceptor(new OtherInterceptor()).addPathPatterns("/**");
}
}
1.3 攔截器的應(yīng)用場(chǎng)景
攔截器本質(zhì)上是面向切面編程(AOP),符合橫切關(guān)注點(diǎn)的功能都可以放在攔截器中來(lái)實(shí)現(xiàn),主要的應(yīng)用場(chǎng)景包括:
- 登錄驗(yàn)證,判斷用戶是否登錄。
- 權(quán)限驗(yàn)證,判斷用戶是否有權(quán)限訪問(wèn)資源。
- 日志記錄,記錄請(qǐng)求日志,以便統(tǒng)計(jì)請(qǐng)求訪問(wèn)量。
- 處理cookie、本地化、國(guó)際化、主題等。
- 性能監(jiān)控,監(jiān)控請(qǐng)求處理時(shí)長(zhǎng)等。
2. 原理
2.1 工作原理
攔截器不是Filter,卻實(shí)現(xiàn)了Filter的功能,其原理在于:
- 所有的攔截器(Interceptor)和處理器(Handler)都注冊(cè)在HandlerMapping中。
- Spring MVC中所有的請(qǐng)求都是由DispatcherServlet分發(fā)的。
- 當(dāng)請(qǐng)求進(jìn)入DispatcherServlet.doDispatch()時(shí)候,首先會(huì)得到處理該請(qǐng)求的Handler(即Controller中對(duì)應(yīng)的方法)以及所有攔截該請(qǐng)求的攔截器。攔截器就是在這里被調(diào)用開始工作的。
2.2 攔截器工作流程
一個(gè)攔截器,只有preHandle方法返回true,postHandle、afterCompletion才有可能被執(zhí)行;如果preHandle方法返回false,則該攔截器的postHandle、afterCompletion必然不會(huì)被執(zhí)行。
假設(shè)我們有兩個(gè)攔截器,例如叫Interceptor1和Interceptor2,當(dāng)一個(gè)請(qǐng)求過(guò)來(lái),正常的流程和中斷的流程分別如下。
2.2.1正常流程
注意兩個(gè)攔截器在執(zhí)行preHandle方法和執(zhí)行postHandle、afterCompletion方法時(shí),順序是顛倒的。
- Interceptor1.preHandle
- Interceptor2.preHandle
- Controller處理請(qǐng)求
- Interceptor2.postHandle
- Interceptor1.postHandle
- 渲染視圖
- Interceptor2.afterCompletion
- Interceptor1.afterCompletion
2.2.2 中斷流程
假設(shè)執(zhí)行Interceptor2.preHandle中報(bào)錯(cuò),那么流程被中斷,之前被執(zhí)行過(guò)的攔截器的afterCompletion仍然會(huì)執(zhí)行。在本例中,即執(zhí)行了Interceptor1.afterCompletion。
1. Interceptor1.preHandle 2. Interceptor2.preHandle //中間流程被中斷,不再執(zhí)行 3. Interceptor1.afterCompletion
2.3 和Filter共存時(shí)的執(zhí)行順序
攔截器是在DispatcherServlet這個(gè)servlet中執(zhí)行的,因此所有的請(qǐng)求最先進(jìn)入Filter,最后離開Filter。其順序如下。
Filter->Interceptor.preHandle->Handler->Interceptor.postHandle->Interceptor.afterCompletion->Filter
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot 項(xiàng)目中的圖片處理策略之本地存儲(chǔ)與路徑映射
在SpringBoot項(xiàng)目中,靜態(tài)資源存放在static目錄下,使得前端可以通過(guò)URL來(lái)訪問(wèn)這些資源,我們就需要將文件系統(tǒng)的文件路徑與URL建立一個(gè)映射關(guān)系,把文件系統(tǒng)中的文件當(dāng)成我們的靜態(tài)資源即可,本文給大家介紹SpringBoot本地存儲(chǔ)與路徑映射的相關(guān)知識(shí),感興趣的朋友一起看看吧2023-12-12
Java實(shí)現(xiàn)文件上傳服務(wù)器和客戶端
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)文件上傳服務(wù)器和客戶端,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01
spring定時(shí)器定時(shí)任務(wù)到時(shí)間未執(zhí)行問(wèn)題的解決
這篇文章主要介紹了spring定時(shí)器定時(shí)任務(wù)到時(shí)間未執(zhí)行問(wèn)題的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
實(shí)例講解Java設(shè)計(jì)模式編程中的OCP開閉原則
這篇文章主要介紹了Java設(shè)計(jì)模式編程中的開閉原則,開閉原則的大意被作者總結(jié)為用抽象構(gòu)建框架,用實(shí)現(xiàn)擴(kuò)展細(xì)節(jié),需要的朋友可以參考下2016-02-02
Spring中使用JSR303請(qǐng)求約束判空的實(shí)現(xiàn)
這篇文章主要介紹了Spring中使用JSR303請(qǐng)求約束判空的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
Gradle相對(duì)于Maven有哪些優(yōu)點(diǎn)
這篇文章主要介紹了Gradle相對(duì)于Maven有哪些優(yōu)點(diǎn),幫助大家選擇合適的自動(dòng)構(gòu)建工具,更好的構(gòu)建項(xiàng)目,感興趣的朋友可以了解下2020-10-10
java實(shí)現(xiàn)簡(jiǎn)易版簡(jiǎn)易版dubbo
dubbo是阿里開源的rpc框架,目前是apache頂級(jí)開源項(xiàng)目,可以用來(lái)構(gòu)建微服務(wù)。本文主要介紹了如何通過(guò)java實(shí)現(xiàn)簡(jiǎn)易版的dubbo,感興趣的小伙伴可以了解一下2021-11-11

