SpringBoot 攔截器妙用你真的了解嗎
HandlerInterceptor 詳解
HandlerInterceptor
允許定制 handler
處理器執(zhí)行鏈的工作流接口。我們可以自定義攔截器用于攔截 handlers 處理器(你可以理解為 controller 層的接口),從而可以添加一些共同的重復(fù)性的處理行為(例如接口鑒權(quán),接口日志記錄,性能監(jiān)控等),而不用修改每一個(gè) handler 的實(shí)現(xiàn)。
注意,此基于 SpringBoot 2.3.12.RELEASE
版本講解。
HandlerInterceptor 接口只有三個(gè)默認(rèn)空實(shí)現(xiàn)方法,在低版本中這三個(gè)方法不是默認(rèn)方法,而是抽象方法。
public interface HandlerInterceptor { default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } }
這三個(gè)方法的執(zhí)行順序圖如下:
preHandle
preHandle
前置處理,攔截一個(gè)處理器(handler)的執(zhí)行,preHandle 方法會(huì)在 HandlerMapping
確定一個(gè)適當(dāng)?shù)奶幚砥鲗?duì)象之后,但在 HandlerAdapter
調(diào)用處理器之前被調(diào)用??梢院?jiǎn)單理解為 controller 接口被調(diào)用之前執(zhí)行。
Intercepter 是鏈?zhǔn)降模褪且粋€(gè)接著一個(gè)執(zhí)行。如果此方法返回 true,則會(huì)執(zhí)行下一個(gè)攔截器或者直接執(zhí)行處理器。如果此方法返回 false 或者拋出異常則終止執(zhí)行鏈,也不再調(diào)用處理器。
注意,此方法如果不返回 true,那么 postHandle
和 afterCompletion
不會(huì)被執(zhí)行。
那這個(gè)方法有什么用呢?其實(shí)可以做一些接口被調(diào)用前的預(yù)處理,例如用戶權(quán)限校驗(yàn)。
package com.chenpi; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; /** * @Description 用戶權(quán)限驗(yàn)證攔截 * @Author 陳皮 * @Date 2021/6/27 * @Version 1.0 */ @Component public class UserPermissionInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; // 獲取用戶權(quán)限校驗(yàn)注解 UserAuthenticate userAuthenticate = handlerMethod.getMethod().getAnnotation(UserAuthenticate.class); if (null == userAuthenticate) { userAuthenticate = handlerMethod.getMethod().getDeclaringClass() .getAnnotation(UserAuthenticate.class); } if (userAuthenticate != null && userAuthenticate.permission()) { // 驗(yàn)證用戶信息 UserContext userContext = userContextManager.getUserContext(request); if (null == userContext) { return false; } } } return true; } }
postHandle
postHandle
后置處理,會(huì)在 HandlerAdapter
調(diào)用處理器之后,但在 DispatcherServlet
渲染視圖之前被調(diào)用??梢栽诖藢?duì) ModelAndView
做一些額外的處理??梢院?jiǎn)單理解為 controller 接口被調(diào)用之后執(zhí)行。
注意,此方法在執(zhí)行鏈中的執(zhí)行順序是倒著執(zhí)行的,即先聲明的攔截器后執(zhí)行。
afterCompletion
afterCompletion 完成之后,在請(qǐng)求處理完之后被執(zhí)行,也就是渲染完視圖之后。一般用于做一些資源的清理工作,配合 preHandle 計(jì)算接口執(zhí)行時(shí)間等。
注意,和 postHandle 一樣,此方法在執(zhí)行鏈中的執(zhí)行順序也是倒著執(zhí)行的,即先聲明的攔截器后執(zhí)行。
@Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) { // 請(qǐng)求完后,清除當(dāng)前線程的用戶信息 UserContextHolder.removeUserContext(); }
注冊(cè)攔截器
注意,我們自定義的攔截器要通過 WebMvcConfigurer
的實(shí)現(xiàn)類進(jìn)行注冊(cè),才能生效。
package com.yzj.ehr.common.config; import com.yzj.ehr.common.context.UserContextResolver; import org.springframework.stereotype.Component; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.yzj.ehr.common.interceptor.UserPermissionInterceptor; /** * @Description 注冊(cè)攔截器 * @Author 陳皮 * @Date 2021/6/27 * @Version 1.0 */ @Component public class WebAppConfigurer implements WebMvcConfigurer { private UserPermissionInterceptor userPermissionInterceptor; public WebAppConfigurer(final UserPermissionInterceptor userPermissionInterceptor) { this.userPermissionInterceptor = userPermissionInterceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { // 匹配所有接口,排除/base/test接口 registry.addInterceptor(userPermissionInterceptor).addPathPatterns("/**") .excludePathPatterns("/base/test"); } }
到此這篇關(guān)于SpringBoot 攔截器妙用你真的了解嗎的文章就介紹到這了,更多相關(guān)SpringBoot 攔截器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Spring 基于 Aspect 注解的增強(qiáng)實(shí)現(xiàn)
本篇文章主要介紹了詳解Spring 基于 Aspect 注解的增強(qiáng)實(shí)現(xiàn),非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-04-04springboot使用@KafkaListener監(jiān)聽多個(gè)kafka配置實(shí)現(xiàn)
當(dāng)服務(wù)中需要監(jiān)聽多個(gè)kafka時(shí),?需要配置多個(gè)kafka,本文主要介紹了springboot使用@KafkaListener監(jiān)聽多個(gè)kafka配置實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-04-04Java實(shí)現(xiàn)輸出回環(huán)數(shù)(螺旋矩陣)的方法示例
這篇文章主要介紹了Java實(shí)現(xiàn)輸出回環(huán)數(shù)(螺旋矩陣)的方法,涉及java針對(duì)數(shù)組的遍歷、判斷、輸出等相關(guān)操作技巧,需要的朋友可以參考下2017-12-12利用JAVA反射,讀取數(shù)據(jù)庫表名,自動(dòng)生成對(duì)應(yīng)實(shí)體類的操作
這篇文章主要介紹了利用JAVA反射,讀取數(shù)據(jù)庫表名,自動(dòng)生成對(duì)應(yīng)實(shí)體類的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08Netty實(shí)戰(zhàn)入門教程之?什么是Netty
Java中支持三種網(wǎng)絡(luò)編程IO模型,BIO、NIO、AIO,Netty對(duì)NIO又做了一層封裝,本文帶領(lǐng)我們了解Netty到底是什么,Netty入門案例,感興趣的朋友跟隨小編一起看看吧2022-02-02java實(shí)現(xiàn)列表、集合與數(shù)組之間轉(zhuǎn)化的方法
這篇文章主要介紹了java實(shí)現(xiàn)列表、集合與數(shù)組之間轉(zhuǎn)化的方法,涉及java中列表、集合與數(shù)組相互轉(zhuǎn)換的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-03-03