如何處理器攔截器(HandlerInterceptor)
簡(jiǎn)介
SpringWebMVC的處理器攔截器,類似于Servlet開發(fā)中的過濾器Filter,用于處理器進(jìn)行預(yù)處理和后處理。
應(yīng)用場(chǎng)景
1、日志記錄,可以記錄請(qǐng)求信息的日志,以便進(jìn)行信息監(jiān)控、信息統(tǒng)計(jì)等。
2、權(quán)限檢查:如登陸檢測(cè),進(jìn)入處理器檢測(cè)是否登陸,如果沒有直接返回到登陸頁面。
3、性能監(jiān)控:典型的是慢日志。
HandlerInterceptor
public interface HandlerInterceptor { ? ?/** ? ? ?* 預(yù)處理回調(diào)方法,實(shí)現(xiàn)處理器的預(yù)處理(如檢查登陸),第三個(gè)參數(shù)為響應(yīng)的處理器,自定義Controller ? ? ?* 返回值:true表示繼續(xù)流程(如調(diào)用下一個(gè)攔截器或處理器);false表示流程中斷 (如登錄檢查失?。粫?huì)繼續(xù)調(diào)用其他的攔截器或處理器,此時(shí)我們需要通過response來產(chǎn)生響應(yīng); ? ?*/ ? ? boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) ? ? ? ? ? ? throws Exception; ? ?/** ? ? ?* 后處理回調(diào)方法,實(shí)現(xiàn)處理器的后處理(但在渲染視圖之前),此時(shí)我們可以 通過modelAndView(模型和視圖對(duì)象)對(duì)模型數(shù)據(jù)進(jìn)行處理或?qū)σ晥D進(jìn)行處理,modelAndView也可能為null。 ? ?*/ ? ? void postHandle( ? ? ? ? ? ? HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) ? ? ? ? ? ? throws Exception; ? ?/** ? ? * 整個(gè)請(qǐng)求處理完畢回調(diào)方法,即在視圖渲染完畢時(shí)回調(diào),如性能監(jiān)控中我們可以在此記錄結(jié)束時(shí)間并輸出消耗時(shí)間,還可以進(jìn)行一些資源清理,類似于try-catch-finally中的finally,但僅調(diào)用處理器執(zhí)行鏈中 ? ?*/ ? ? void afterCompletion( ? ? ? ? ? ? HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) ? ? ? ? ? ? throws Exception; }
攔截器適配器HandlerInterceptorAdapter
有時(shí)候我們可能只需要實(shí)現(xiàn)三個(gè)回調(diào)方法中的某一個(gè),如果實(shí)現(xiàn)HandlerInterceptor接口的話,三個(gè)方法必須實(shí)現(xiàn),不管你需不需要,此時(shí)spring提供了一個(gè)HandlerInterceptorAdapter適配器(種適配器設(shè)計(jì)模式的實(shí)現(xiàn)),允許我們只實(shí)現(xiàn)需要的回調(diào)方法。
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor { ? ? /** ? ? ?* 默認(rèn)是true ? ? ?*/ ? ? @Override ? ? public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) ? ? ? ? ? ? throws Exception { ? ? ? ? return true; ? ? } ? ? /** ? ? ?* This implementation is empty. ? ? ?*/ ? ? @Override ? ? public void postHandle( ? ? ? ? ? ? HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) ? ? ? ? ? ? throws Exception { ? ? } ? ? /** ? ? ?* This implementation is empty. ? ? ?*/ ? ? @Override ? ? public void afterCompletion( ? ? ? ? ? ? HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) ? ? ? ? ? ? throws Exception { ? ? } ? ? /** ? ? ?* 不是HandlerInterceptor的接口實(shí)現(xiàn),是AsyncHandlerInterceptor的,AsyncHandlerInterceptor實(shí)現(xiàn)了HandlerInterceptor ? ? ?*/ ? ? @Override ? ? public void afterConcurrentHandlingStarted( ? ? ? ? ? ? HttpServletRequest request, HttpServletResponse response, Object handler) ? ? ? ? ? ? throws Exception { ? ? } }
這樣在我們業(yè)務(wù)中比如要記錄系統(tǒng)日志,日志肯定是在afterCompletion之后記錄的,否則中途失敗了,也記錄了,那就扯淡了。
一定是程序正常跑完后,我們記錄下那些對(duì)數(shù)據(jù)庫做個(gè)增刪改的操作日志進(jìn)數(shù)據(jù)庫。
所以我們只需要繼承HandlerInterceptorAdapter,并重寫afterCompletion一個(gè)方法即可,因?yàn)閜reHandle默認(rèn)是true。
運(yùn)行流程總結(jié)如下
1、攔截器執(zhí)行順序是按照Spring配置文件中定義的順序而定的。
2、會(huì)先按照順序執(zhí)行所有攔截器的preHandle方法,一直遇到return false為止,比如第二個(gè)preHandle方法是return false,則第三個(gè)以及以后所有攔截器都不會(huì)執(zhí)行。若都是return true,則按順序加載完preHandle方法。
3、然后執(zhí)行主方法(自己的controller接口),若中間拋出異常,則跟return false效果一致,不會(huì)繼續(xù)執(zhí)行postHandle,只會(huì)倒序執(zhí)行afterCompletion方法。
4、在主方法執(zhí)行完業(yè)務(wù)邏輯(頁面還未渲染數(shù)據(jù))時(shí),按倒序執(zhí)行postHandle方法。若第三個(gè)攔截器的postHandle方法return false,則會(huì)執(zhí)行第二個(gè)和第一個(gè)的postHandle方法和afterCompletion(postHandle都執(zhí)行完才會(huì)執(zhí)行這個(gè),也就是頁面渲染完數(shù)據(jù)后,執(zhí)行after進(jìn)行清理工作)方法。(postHandle和afterCompletion都是倒序執(zhí)行)
正常流程Demo
package com.bshf.recipe.demo.syslog; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class SyslogInterceptor implements HandlerInterceptor { ? ? /** ? ? ?* 預(yù)處理回調(diào)方法,實(shí)現(xiàn)處理器的預(yù)處理(如檢查登陸),第三個(gè)參數(shù)為響應(yīng)的處理器,自定義Controller ? ? ?* 返回值:true表示繼續(xù)流程(如調(diào)用下一個(gè)攔截器或處理器);false表示流程中斷(如登錄檢查失?。?,不會(huì)繼續(xù)調(diào)用其他的攔截器或處理器,此時(shí)我們需要通過response來產(chǎn)生響應(yīng); ? ? ?*/ ? ? @Override ? ? public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) ? ? ? ? ? ? throws Exception { ? ? ? ? System.out.println("==========================================1================================================"); ? ? ? ? return true; ? ? } ? ? /** ? ? ?* 后處理回調(diào)方法,實(shí)現(xiàn)處理器的后處理(但在渲染視圖之前),此時(shí)我們可以通過modelAndView(模型和視圖對(duì)象)對(duì)模型數(shù)據(jù)進(jìn)行處理或?qū)σ晥D進(jìn)行處理,modelAndView也可能為null。 ? ? ?*/ ? ? @Override ? ? public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ? ? ? ? ? ? ModelAndView modelAndView) throws Exception { ? ? ? ? System.out.println("==========================================post1================================================"); ? ? } ? ? /** ? ? ?* 整個(gè)請(qǐng)求處理完畢回調(diào)方法,即在視圖渲染完畢時(shí)回調(diào),如性能監(jiān)控中我們可以在此記錄結(jié)束時(shí)間并輸出消耗時(shí)間,還可以進(jìn)行一些資源清理,類似于try-catch-finally中的finally,但僅調(diào)用處理器執(zhí)行鏈中 ? ? ?*/ ? ? @Override ? ? public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) ? ? ? ? ? ? throws Exception { ? ? ? ? System.out.println("==========================================after1================================================"); ? ? } }
package com.bshf.recipe.demo.syslog; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class SyslogInterceptor2 implements HandlerInterceptor { ? ? /** ? ? ?* 預(yù)處理回調(diào)方法,實(shí)現(xiàn)處理器的預(yù)處理(如檢查登陸),第三個(gè)參數(shù)為響應(yīng)的處理器,自定義Controller ? ? ?* 返回值:true表示繼續(xù)流程(如調(diào)用下一個(gè)攔截器或處理器);false表示流程中斷(如登錄檢查失?。粫?huì)繼續(xù)調(diào)用其他的攔截器或處理器,此時(shí)我們需要通過response來產(chǎn)生響應(yīng); ? ? ?*/ ? ? @Override ? ? public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) ? ? ? ? ? ? throws Exception { ? ? ? ? System.out.println("==========================================2================================================"); ? ? ? ? return true; ? ? } ? ? /** ? ? ?* 后處理回調(diào)方法,實(shí)現(xiàn)處理器的后處理(但在渲染視圖之前),此時(shí)我們可以通過modelAndView(模型和視圖對(duì)象)對(duì)模型數(shù)據(jù)進(jìn)行處理或?qū)σ晥D進(jìn)行處理,modelAndView也可能為null。 ? ? ?*/ ? ? @Override ? ? public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ? ? ? ? ? ? ModelAndView modelAndView) throws Exception { ? ? ? ? System.out.println("==========================================post2================================================"); ? ? } ? ? /** ? ? ?* 整個(gè)請(qǐng)求處理完畢回調(diào)方法,即在視圖渲染完畢時(shí)回調(diào),如性能監(jiān)控中我們可以在此記錄結(jié)束時(shí)間并輸出消耗時(shí)間,還可以進(jìn)行一些資源清理,類似于try-catch-finally中的finally,但僅調(diào)用處理器執(zhí)行鏈中 ? ? ?*/ ? ? @Override ? ? public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) ? ? ? ? ? ? throws Exception { ? ? ? ? System.out.println("==========================================after2================================================"); ? ? } }
package com.bshf.recipe.demo.syslog; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class SyslogInterceptor3 implements HandlerInterceptor { ? ? /** ? ? ?* 預(yù)處理回調(diào)方法,實(shí)現(xiàn)處理器的預(yù)處理(如檢查登陸),第三個(gè)參數(shù)為響應(yīng)的處理器,自定義Controller ? ? ?* 返回值:true表示繼續(xù)流程(如調(diào)用下一個(gè)攔截器或處理器);false表示流程中斷(如登錄檢查失?。?,不會(huì)繼續(xù)調(diào)用其他的攔截器或處理器,此時(shí)我們需要通過response來產(chǎn)生響應(yīng); ? ? ?*/ ? ? @Override ? ? public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) ? ? ? ? ? ? throws Exception { ? ? ? ? System.out.println("==========================================3================================================"); ? ? ? ? return true; ? ? } ? ? /** ? ? ?* 后處理回調(diào)方法,實(shí)現(xiàn)處理器的后處理(但在渲染視圖之前),此時(shí)我們可以通過modelAndView(模型和視圖對(duì)象)對(duì)模型數(shù)據(jù)進(jìn)行處理或?qū)σ晥D進(jìn)行處理,modelAndView也可能為null。 ? ? ?*/ ? ? @Override ? ? public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ? ? ? ? ? ? ModelAndView modelAndView) throws Exception { ? ? ? ? System.out.println("==========================================post3================================================"); ? ? } ? ? /** ? ? ?* 整個(gè)請(qǐng)求處理完畢回調(diào)方法,即在視圖渲染完畢時(shí)回調(diào),如性能監(jiān)控中我們可以在此記錄結(jié)束時(shí)間并輸出消耗時(shí)間,還可以進(jìn)行一些資源清理,類似于try-catch-finally中的finally,但僅調(diào)用處理器執(zhí)行鏈中 ? ? ?*/ ? ? @Override ? ? public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) ? ? ? ? ? ? throws Exception { ? ? ? ? System.out.println("==========================================after3================================================"); ? ? } }
<mvc:interceptors> ? ? ? ? <mvc:interceptor> ? ? ? ? ? ? <mvc:mapping path="/**"/> ? ? ? ? ? ? <bean class="com.bshf.recipe.demo.syslog.SyslogInterceptor" /> ? ? ? ? </mvc:interceptor> ? ? ? ? <mvc:interceptor> ? ? ? ? ? ? <mvc:mapping path="/**"/> ? ? ? ? ? ? <bean class="com.bshf.recipe.demo.syslog.SyslogInterceptor2" /> ? ? ? ? </mvc:interceptor> ? ? ? ? <mvc:interceptor> ? ? ? ? ? ? <mvc:mapping path="/**"/> ? ? ? ? ? ? <bean class="com.bshf.recipe.demo.syslog.SyslogInterceptor3" /> ? ? ? ? </mvc:interceptor> </mvc:interceptors>
<mvc:mapping path="/**"/>需要攔截的路徑,這里匹配所有。
這里的配置順序?qū)⑹菙r截器執(zhí)行順序。
輸出結(jié)果:
==========================================1================================================
==========================================2================================================
==========================================3================================================
==========================================post3================================================
==========================================post2================================================
==========================================post1================================================
==========================================after3================================================
==========================================after2================================================
==========================================after1================================================
post和after是倒序的?。。?!
中斷流程Demo
將SyslogInterceptor3的preHandle方法返回false。
其他不變,再看輸出結(jié)果
==========================================1================================================
==========================================2================================================
==========================================3================================================
==========================================after2================================================
==========================================after1================================================
發(fā)現(xiàn)沒有了post,post方法一個(gè)都沒有輸出。
不僅如此,你的主程序代碼(xxx.controller的一個(gè)接口)都不會(huì)被執(zhí)行,所以只要遇到return false,則直接進(jìn)行after清理工作,post和自己主程序代碼都將被略過。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
springboot如何接收get和post請(qǐng)求參數(shù)
這篇文章主要介紹了springboot如何接收get和post請(qǐng)求參數(shù),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06詳解Java中while和do-while循環(huán)、break的使用
本文介紹了循環(huán)結(jié)構(gòu)語句while和do-while循環(huán)、break的使用,while循環(huán)語句通過流程圖和語法語句結(jié)合一個(gè)求1~10的整數(shù)和的例子來幫助大家理解while循環(huán)的用法,感興趣的朋友跟隨小編來看看吧2020-11-11淺談StringEntity 和 UrlEncodedFormEntity之間的區(qū)別
這篇文章主要介紹了StringEntity 和 UrlEncodedFormEntity之間的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06java門禁系統(tǒng)面向?qū)ο蟪绦蛟O(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了java門禁系統(tǒng)面向?qū)ο蟪绦蛟O(shè)計(jì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01Springboot日期轉(zhuǎn)換器實(shí)現(xiàn)代碼及示例
這篇文章主要介紹了Springboot日期轉(zhuǎn)換器實(shí)現(xiàn)代碼及示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08Java獲取漢字拼音的全拼和首拼實(shí)現(xiàn)代碼分享
這篇文章主要介紹了Java獲取漢字拼音的全拼和首拼實(shí)現(xiàn)代碼分享,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-06-06idea創(chuàng)建JAVA Class時(shí)自動(dòng)生成頭部文檔注釋的方法
這篇文章主要介紹了idea創(chuàng)建JAVA Class時(shí)自動(dòng)生成頭部文檔注釋的方法,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12