Spring Boot 攔截器:解鎖5大實用場景

一、Spring Boot中攔截器是什么

??在Spring Boot中,攔截器(Interceptor)是一種基于AOP(面向切面編程)思想的組件,用于在請求處理前后插入自定義邏輯,實現權限校驗、日志記錄、性能監控等非業務功能。

??其核心作用是在不修改業務代碼的前提下,對請求進行統一處理,類似于Servlet中的Filter,但更貼近Spring MVC的體系。

二、攔截器與過濾器的區別

在這里插入圖片描述

三、攔截器主要方法

在實現攔截器時,HandlerInterceptor接口提供了三個主要方法,它們在請求處理的不同階段發揮著重要作用。
?
preHandle
??這個方法在請求進入Controller之前被調用 。它的返回值是一個布爾類型,如果返回true,請求將繼續被處理,進入Controller。
?? 如果返回false,請求將被攔截,后續的Controller方法將不會被執行。在這個方法中,我們通常可以進行一些前置的處理操作,比如用戶認證、權限校驗、日志記錄等。?

postHandle
??當Controller方法執行完畢后,視圖渲染之前,這個方法會被調用 。

??在這個方法中,我們可以對ModelAndView進行一些操作,比如添加額外的模型數據,修改視圖名稱等。需要注意的是,如果在preHandle方法中返回了false,這個方法將不會被執行。?

afterCompletion
??在整個請求處理完成,包括視圖渲染之后,這個方法會被調用。無論請求處理過程中是否發生異常,只要preHandle方法返回true,這個方法就會被執行。

??我們可以在這個方法中進行一些資源清理、記錄日志等收尾工作。如果請求處理過程中發生了異常,異常信息會通過 ex 參數傳遞進來,我們可以根據這個參數進行相應的異常處理。

@Component
public class MyInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 在請求處理之前執行的邏輯System.out.println("preHandle被調用,請求即將進入Controller");return true; // 返回true表示放行請求,返回false則攔截請求}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {// 在請求處理之后,視圖渲染之前執行的邏輯System.out.println("postHandle被調用,Controller方法已執行完畢,視圖即將渲染");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 在整個請求處理完成,包括視圖渲染之后執行的邏輯System.out.println("afterCompletion被調用,整個請求已處理完畢");}
}
@Configuration
public class WebMvcConfig1 implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**") // 攔截所有請求.excludePathPatterns("/static/**"); // 排除/static目錄下的靜態資源請求}
}

四、5 種常見的攔截器使用場景

1.用戶認證攔截器

??用戶認證攔截器的作用就是在用戶請求進入 Controller 之前,驗證用戶的登錄狀態。如果用戶已經登錄,允許請求繼續處理。如果用戶未登錄,則返回錯誤信息或者重定向到登錄頁面。

@Component
public class JwtHandlerInterceptor implements HandlerInterceptor {@Autowiredprivate JwtTokenProvider jwtTokenProvider;@Autowiredprivate UserInfoService userInfoService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if (!(handler instanceof HandlerMethod)) {return true;}// 取出tokenString token = request.getHeader("token");if (!jwtTokenProvider.validateToken(token)) {response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);response.getWriter().write("{\"error\": \"Token已失效,請重新登錄\"}");return false;}HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();// 判斷方法上是否有NoAuth注解,如果有則跳過認證if (method.isAnnotationPresent(NoAuth.class)) {return true;}String username = jwtTokenProvider.getUsernameFromJWT(token);User user = userInfoService.getUserInfoByUserName(username);if (user == null) {response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);response.getWriter().write("{\"error\": \"用戶不存在\"}");return false;}// 判斷角色權限HasRoles hasRoles = handlerMethod.getMethodAnnotation(HasRoles.class);if (!Objects.isNull(hasRoles)) {// 檢查用戶是否有所需角色String[] roles = hasRoles.value();boolean hasRole = false;// 角色校驗 ...if (!hasRole) {response.setStatus(HttpServletResponse.SC_FORBIDDEN);response.getWriter().write("{\"error\": \"權限不足\"}");return false;}}// 將用戶信息放入請求屬性request.setAttribute("currentUser", user);return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {HandlerInterceptor.super.afterCompletion(request, response, handler, ex);}
}

??在WebMvcConfig配置類中,將JwtHandlerInterceptor注冊到Spring的攔截器鏈中,并設置攔截路徑為所有請求,排除了登錄和注冊接口,因為這兩個接口不需要用戶登錄就可以訪問。

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new JwtHandlerInterceptor()).addPathPatterns("/**")// 攔截所有請求.excludePathPatterns("/login","/register");// 排除登錄和注冊接口}}

??通過這樣的配置,就可以實現對用戶登錄狀態的驗證,確保只有登錄用戶才能訪問受保護的資源。

2.日志記錄攔截器

??日志記錄對于系統的運維和故障排查非常重要。日志記錄攔截器可以在請求處理的前后記錄請求的相關信息,比如請求的 URL、請求方法、請求參數、客戶端 IP 等。這些日志信息可以幫助我們了解系統的運行情況,分析用戶行為,在出現問題時快速定位問題。

@Component
public class RequestLoggingInterceptor implements HandlerInterceptor {private static final Logger logger = LoggerFactory.getLogger(RequestLoggingInterceptor.class);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {logger.info("Request URL: {}, Method: {}, IP: {}", request.getRequestURI(), request.getMethod(), request.getRemoteAddr());// 記錄請求參數Map<String, String[]> paramMap = request.getParameterMap();StringBuilder params = new StringBuilder();if (!paramMap.isEmpty()) {for (Map.Entry<String, String[]> entry : paramMap.entrySet()) {params.append(entry.getKey()).append("=").append(String.join(",", entry.getValue())).append("&");}if (params.length() > 0) {params.deleteCharAt(params.length() - 1);}}// 記錄請求體(僅POST/PUT/PATCH請求)String method = request.getMethod();String requestBody = "";if (HttpMethod.POST.matches(method) ||HttpMethod.PUT.matches(method) ||HttpMethod.PATCH.matches(method)) {// 使用包裝請求對象來多次讀取請求體ContentCachingRequestWrapper wrappedRequest =new ContentCachingRequestWrapper(request);// 為了觸發內容緩存,我們需要獲取一次輸入流if (wrappedRequest.getContentLength() > 0) {wrappedRequest.getInputStream().read();requestBody = new String(wrappedRequest.getContentAsByteArray(),wrappedRequest.getCharacterEncoding());}}logger.info("Request URL: {}, Method: {}, IP: {},params: {},requestBody: {}", request.getRequestURI(), request.getMethod(), request.getRemoteAddr(), params, requestBody);return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {logger.info("Request to {} has been completed", request.getRequestURI());if (ex != null) {logger.error("An exception occurred during request handling", ex);}}
}

3.性能監控攔截器

??性能監控對于優化系統性能至關重要。性能監控攔截器可以用來計算和記錄請求的處理時間,通過分析這些時間數據,我們可以找出系統中的性能瓶頸,進而進行針對性的優化。

@Component
public class PerformanceInterceptor implements HandlerInterceptor {private static final ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal<>();@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {long startTime = System.currentTimeMillis();startTimeThreadLocal.set(startTime);return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {// 計算請求處理時間long endTime = System.currentTimeMillis();long startTime = startTimeThreadLocal.get();long executeTime = endTime - startTime;System.out.println("Request URL: " + request.getRequestURL() + ", Execution Time: " + executeTime + "ms");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {startTimeThreadLocal.remove();}
}

4.接口限流攔截器
??在高并發場景下,接口限流是保護系統的重要手段 。接口限流攔截器可以限制單位時間內對某個接口的訪問次數,防止因大量請求導致系統資源耗盡,從而保證系統的穩定性和可用性 。

@Component
public class AccessLimitInterceptor implements HandlerInterceptor {@Autowiredprivate RedisTemplate<String, Integer> redisTemplate;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if (!(handler instanceof HandlerMethod)) {return true;}HandlerMethod handlerMethod = (HandlerMethod) handler;AccessLimit accessLimit = handlerMethod.getMethodAnnotation(AccessLimit.class);if (accessLimit == null) {return true;}int seconds = accessLimit.seconds();int maxCount = accessLimit.maxCount();boolean needLogin = accessLimit.needLogin();if (needLogin) {// 檢查用戶登錄狀態,這里省略具體實現// 如果未登錄,返回錯誤信息return false;}String key = request.getRemoteAddr() + request.getRequestURI();Integer count = redisTemplate.opsForValue().get(key);if (count == null) {redisTemplate.opsForValue().set(key, 1, seconds, TimeUnit.SECONDS);} else if (count < maxCount) {redisTemplate.opsForValue().increment(key, 1);} else {render(response, "請求過于頻繁,請稍后再試");return false;}return true;}private void render(HttpServletResponse response, String msg) throws IOException {response.setContentType("application/json;charset=UTF-8");PrintWriter out = response.getWriter();out.write(msg);out.flush();out.close();}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}}

5.數據加密解密攔截器
??在數據傳輸和存儲過程中,保護敏感數據的安全至關重要。數據加密解密攔截器可以在請求到達Controller之前對敏感數據進行加密,在響應返回給客戶端之前對加密數據進行解密,確保數據在傳輸和處理過程中的安全性。

??比如在用戶登錄時,對用戶輸入的密碼進行加密后再傳輸到服務器。在從數據庫中查詢用戶的身份證號、手機號等敏感信息時,對查詢結果進行解密后再返回給前端。

@Component
public class EncryptionInterceptor implements HandlerInterceptor {/*** 密鑰*/private static final String KEY = "secret_key";@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 假設請求參數中有一個名為"sensitiveData"的敏感數據需要加密String sensitiveData = request.getParameter("sensitiveData");if (sensitiveData != null) {SecretKey secretKey = new SecretKeySpec(KEY.getBytes(), "AES");byte[] encryptedData = AESUtil.encrypt(sensitiveData, secretKey);String encryptedDataStr = Base64.getEncoder().encodeToString(encryptedData);// 將加密后的數據重新放回請求參數中request.setAttribute("sensitiveData", encryptedDataStr);}return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// 假設響應中有一個名為"sensitiveResponseData"的敏感數據需要解密String sensitiveResponseData = (String) request.getAttribute("sensitiveResponseData");if (sensitiveResponseData != null) {SecretKey secretKey = new SecretKeySpec(KEY.getBytes(), "AES");byte[] decodedData = Base64.getDecoder().decode(sensitiveResponseData);String decryptedData = AESUtil.decrypt(decodedData, secretKey);// 將解密后的數據重新放回請求屬性中,方便后續處理request.setAttribute("sensitiveResponseData", decryptedData);}}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);}
}

五、總結

??在 Spring Boot 開發中,攔截器就像是一把 “萬能鑰匙”,為我們提供了豐富的功能擴展和業務處理的可能性。

??希望大家在實際項目中,能夠根據業務需求,靈活地運用這些攔截器,讓我們的 Spring Boot 應用更加健壯、高效、安全。

??同時,攔截器還有很多值得深入探討的地方,比如如何在攔截器中優雅地處理事務、如何實現更加復雜的動態攔截規則等 ,后續我們可以一起繼續探索。

??如果大家在使用攔截器的過程中有任何問題或心得,歡迎在留言區分享交流。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/80530.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/80530.shtml
英文地址,請注明出處:http://en.pswp.cn/web/80530.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Vue百日學習計劃Day24-28天詳細計劃-Gemini版

總目標: 在 Day 24-27 熟練掌握 Vue.js 的各種模板語法&#xff0c;包括文本插值、屬性綁定、條件渲染、列表渲染、事件處理和表單綁定&#xff0c;并能結合使用修飾符。 所需資源: Vue 3 官方文檔 (模板語法): https://cn.vuejs.org/guide/essentials/template-syntax.htmlVu…

分布式微服務系統架構第125集:AI大模型

加群聯系作者vx&#xff1a;xiaoda0423 倉庫地址&#xff1a;https://webvueblog.github.io/JavaPlusDoc/ https://1024bat.cn/ 一、user 表&#xff08;用戶表&#xff09; sql 復制編輯 create table if not exists user (id bigint auto_increment comment id pri…

機器學習 Day16 聚類算法 ,數據降維

聚類算法 1.簡介 1.1 聚類概念 無監督學習&#xff1a;聚類是一種無監督學習算法&#xff0c;不需要預先標記的訓練數據 相似性分組&#xff1a;根據樣本之間的相似性自動將樣本歸到不同類別 相似度度量&#xff1a;常用歐式距離作為相似度計算方法 1.2 聚類vs分類 聚類&…

【Linux】第十八章 調優系統性能

1. 系統管理員可以使用哪個命令來更改tuned守護進程的設置&#xff1f; tuned 的調優配置集存儲在 /usr/lib/tuned&#xff08;默認&#xff09; 和 /etc/tuned&#xff08;自定義 或當前有效&#xff09;目錄下。每個配置集都有一個單獨的目錄&#xff0c;目錄中包含 tuned.c…

【JVS更新日志】企業文檔AI助手上線、低代碼、智能BI、智能APS、AI助手5.14更新說明!

項目介紹 JVS是企業級數字化服務構建的基礎腳手架&#xff0c;主要解決企業信息化項目交付難、實施效率低、開發成本高的問題&#xff0c;采用微服務配置化的方式&#xff0c;提供了低代碼數據分析物聯網的核心能力產品&#xff0c;并構建了協同辦公、企業常用的管理工具等&…

ollama調用千問2.5-vl視頻圖片UI界面小程序分享

1、問題描述&#xff1a; ollama調用千問2.5-vl視頻圖片內容&#xff0c;通常用命令行工具不方便&#xff0c;于是做了一個python UI界面與大家分享。需要提前安裝ollama&#xff0c;并下載千問qwen2.5vl:7b 模型&#xff0c;在ollama官網即可下載。 &#xff08;8G-6G 顯卡可…

Web 架構之會話保持深度解析

文章目錄 一、引言二、會話保持的基本概念2.1 什么是會話2.2 為什么需要會話保持 三、會話保持的常見實現方式3.1 基于客戶端的會話保持3.1.1 Cookie 方式3.1.2 URL 重寫方式 3.2 基于服務器端的會話保持3.2.1 負載均衡器會話保持3.2.2 會話共享 四、會話保持可能遇到的問題及解…

Maven 項目中將本地依賴庫打包到最終的 JAR 中

文章目錄 前言詳細步驟 前言 在現代后端開發中&#xff0c;構建高效且可擴展的 Web 應用程序通常依賴于多種第三方庫和內部依賴。這些依賴可以來自公共倉庫&#xff0c;也可能是公司內部自研的庫或尚未發布到公共倉庫的 JAR 包。本文將詳細介紹如何在 Maven 項目中處理本地依賴…

快速定位到源碼位置的插件 - vite/webpack

1. vite-plugin-vue-devtools npm i vite-plugin-vue-devtools -D vite.config.js中配置 import vueDevTools from vite-plugin-vue-devtoolsexport default defineConfig({server: {port: 5173,host: 0.0.0.0},plugins: [vue(),vueJsx(),vueDevTools({componentInspector: t…

基于AH1101芯片的5V升18.6V LED恒流背光供電方案設計

基于AH1101芯片的5V升18.6V LED恒流背光供電方案設計 在現代電子設備中&#xff0c;LED背光技術因其高效、節能、壽命長等優點被廣泛應用于各類顯示設備。本文將詳細介紹如何利用AH1101高效升壓恒流驅動芯片&#xff0c;實現從5V輸入電壓升壓至18.6V&#xff0c;為LED背光板提供…

16.1 - VDMA視頻轉發實驗之TPG

文章目錄 1 實驗任務2 系統框圖3 硬件設計3.1 IP核配置3.2 注意事項 4 軟件設計4.1 注意事項4.2 工程源碼4.2.1 main.c文件 1 實驗任務 基于14.1&#xff0c;使用Xilinx TPG&#xff08;Test Pattern Generator&#xff09; IP提供視頻源&#xff0c;將視頻數據通過VDMA寫入PS…

認識Docker/安裝Docker

一、認識Docker Docker的定義 Docker 是一個開源的應用容器引擎&#xff0c;允許開發者將應用及其依賴打包到一個輕量級、可移植的容器中。容器化技術使得應用可以在任何支持 Docker 的環境中運行&#xff0c;確保環境一致性。 Docker的核心組件 Docker Engine&#xff1a;負責…

實用工具:微軟軟件PowerToys(完全免費),實現多臺電腦共享鼠標和鍵盤(支持window系統)

實用工具&#xff1a;微軟軟件 PowerToys 讓多臺電腦共享鼠標和鍵盤 在如今的數字化辦公與生活場景中&#xff0c;我們常常會面臨同時使用多臺電腦的情況。例如&#xff0c;辦公時可能一臺電腦用于處理工作文檔&#xff0c;另一臺用于運行專業軟件或查看資料&#xff1b;家庭環…

西門子 Teamcenter13 Eclipse RCP 開發 1.1 工具欄 普通按鈕

西門子 Teamcenter13 Eclipse RCP 開發 1.1 工具欄 普通按鈕 1 配置文件2 插件控制3 命令框架 位置locationURI備注菜單欄menu:org.eclipse.ui.main.menu添加到傳統菜單工具欄toolbar:org.eclipse.ui.main.toolbar添加到工具欄 style 值含義顯示效果push普通按鈕&#xff08;默…

React中巧妙使用異步組件Suspense優化頁面性能。

文章目錄 前言一、為什么需要異步組件&#xff1f;1. 性能瓶頸分析2. 異步組件的價值 二、核心實現方式1. React.lazy Suspense&#xff08;官方推薦&#xff09;2. 路由級代碼分割&#xff08;React Router v6&#xff09; 總結 前言 在 React 應用中&#xff0c;隨著功能復…

現在環保方面有什么新的技術動態

環保領域的技術發展迅速&#xff0c;尤其在“雙碳”目標、數字化轉型和可持續發展背景下&#xff0c;涌現出許多創新技術和應用。以下是當前環保領域的新技術動態&#xff08;截至2024年&#xff09;&#xff1a; 一、碳中和與碳減排技術 CCUS&#xff08;碳捕集、利用與封存&a…

solidwors插件 開發————仙盟創夢IDE

SolidWorks VBS SolidWorks 支持通過 VBScript&#xff08;.vbs&#xff09;腳本 進行簡單的二次開發&#xff08;如自動化建模、批量操作等&#xff09;&#xff0c;但嚴格來說這屬于 腳本編程&#xff0c;而非傳統的插件&#xff08;Plug-in&#xff09;開發&#xff08;插件…

docker(二)初識 docker

在第一章的容器化架構中&#xff0c;我們已經了解到了 docker 是一個容器化技術&#xff0c;本章將詳細介紹什么是虛擬化、容器化技術&#xff0c;以及什么是 docker。 一、物理機 VS 虛擬化 VS 容器化 物理機&#xff1a; 實際的服務器或者計算機。是相對于虛擬機而言的對實體…

ChatGPT + DeepSeek 聯合潤色的 Prompt 模板指令合集,用來潤色SCI論文太香了!

對于非英語母語的作者來說,寫SCI論文的時候經常會碰到語法錯誤、表達不夠專業、結構不清晰以及術語使用不準確等問題。傳統的潤色方式要么成本高、效率低,修改過程又耗時又費力。雖然AI工具可以幫助我們來潤色論文,但單獨用ChatGPT或DeepSeek都會存在內容泛泛、專業性不足的…

python打包exe報錯:處理文件時錯誤:Excel xlsx file; not supported

背景&#xff1a;最近用python寫一個excel解析工具&#xff0c;然后打包成exe可執行文件的時候&#xff0c;遇到這樣的問題 1.在我自己編譯器運行是可以正常將上傳后的excel進行解析&#xff0c;但是在打包成exe后&#xff0c;就無法正常解析excel 問題排查&#xff1a; 1.切換…