Spring Boot 攔截器實(shí)戰(zhàn)指南之登錄驗證、日志記錄、權(quán)限控制
在 Web 開發(fā)中,我們經(jīng)常需要對請求進(jìn)行統(tǒng)一處理,比如:
- 判斷用戶是否已登錄
- 記錄請求日志
- 實(shí)現(xiàn)接口權(quán)限校驗
- 防止重復(fù)提交
- 統(tǒng)一設(shè)置響應(yīng)頭信息
這些功能如果都寫在每個 Controller 里,不僅代碼冗余,還難以維護(hù)。而 Spring Boot 提供了強(qiáng)大的攔截器(Interceptor)機(jī)制,讓我們可以像 AOP 一樣,在請求到達(dá) Controller 之前或之后進(jìn)行統(tǒng)一處理。
本文將帶你從零開始掌握 Spring Boot 攔截器的使用,并通過多個實(shí)用案例展示其強(qiáng)大之處!
?? 一、什么是 Spring Boot 攔截器?
? 定義:
攔截器(HandlerInterceptor)是 Spring MVC 提供的一種用于攔截 HTTP 請求的機(jī)制。它可以在請求被 Controller 處理前后執(zhí)行特定邏輯。
? 與 Filter 的區(qū)別:
| 對比項 | Interceptor(攔截器) | Filter(過濾器) |
|---|---|---|
| 所屬框架 | Spring MVC | Servlet 標(biāo)準(zhǔn) |
| 精確度 | 可以精確到 Controller 方法級別 | 作用于所有請求 |
| 支持 Spring 注入 | ? 支持 | ? 不支持 |
| 執(zhí)行時機(jī) | preHandle -> Controller -> postHandle -> afterCompletion | doFilter |
?? 適用場景:
- 登錄狀態(tài)校驗
- 接口權(quán)限控制
- 請求日志記錄
- 統(tǒng)一返回格式封裝
- 防止重復(fù)提交
??? 二、自定義攔截器實(shí)現(xiàn)步驟
Step 1:創(chuàng)建攔截器類
實(shí)現(xiàn) HandlerInterceptor 接口,并重寫以下三個方法:
public class LoginInterceptor implements HandlerInterceptor {
// 請求進(jìn)入 Controller 之前執(zhí)行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (token == null || !token.equals("abc123")) {
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("{\"code\":401,\"message\":\"未登錄\"}");
return false; // 中斷請求
}
return true;
}
// Controller 方法執(zhí)行完成后執(zhí)行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 可選操作,如添加響應(yīng)頭
response.setHeader("X-Custom-Header", "interceptor-added");
}
// 整個請求完成(包括視圖渲染)后執(zhí)行
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 可用于資源清理、日志記錄等
System.out.println("【攔截器】請求結(jié)束:" + request.getRequestURI());
}
}Step 2:注冊攔截器
創(chuàng)建配置類,繼承 WebMvcConfigurer 并重寫 addInterceptors() 方法:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**") // 攔截所有路徑
.excludePathPatterns("/login", "/error"); // 排除不需要攔截的路徑
}
}?? 三、攔截器典型應(yīng)用場景實(shí)戰(zhàn)
? 場景一:登錄鑒權(quán)(Token 校驗)
攔截所有非登錄請求,判斷請求頭中是否攜帶有效 Token。
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (token == null || !isValidToken(token)) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
return false;
}
return true;
}? 場景二:請求日志記錄
記錄每次請求的 URL、IP、耗時、參數(shù)等信息。
private static final ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
startTimeThreadLocal.set(System.currentTimeMillis());
System.out.println("【請求開始】IP: " + request.getRemoteAddr() + ", URI: " + request.getRequestURI());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
long duration = System.currentTimeMillis() - startTimeThreadLocal.get();
System.out.println("【請求結(jié)束】耗時: " + duration + "ms");
startTimeThreadLocal.remove();
}? 場景三:接口權(quán)限控制(基于角色)
根據(jù)當(dāng)前用戶的角色判斷是否有權(quán)限訪問某個接口。
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
User user = getCurrentUser(request);
if (!user.hasPermission(request.getRequestURI())) {
response.getWriter().write("{\"code\":403,\"message\":\"無權(quán)限\"}");
return false;
}
return true;
}
? 場景四:防止重復(fù)提交
通過 Token 或 Redis 緩存來識別重復(fù)請求。
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getParameter("formToken");
if (StringUtils.isEmpty(token) || RedisUtil.exists(token)) {
response.getWriter().write("{\"code\":400,\"message\":\"請勿重復(fù)提交\"}");
return false;
}
RedisUtil.set(token, "submitted", 60); // 設(shè)置有效期
return true;
}
?? 四、攔截器使用注意事項
| 注意事項 | 說明 |
|---|---|
| 攔截器順序問題 | 多個攔截器按照注冊順序依次執(zhí)行 preHandle,逆序執(zhí)行 afterCompletion |
| 不要阻塞主線程 | 如需異步處理,請使用線程池 |
| 避免頻繁調(diào)用耗時操作 | 如數(shù)據(jù)庫查詢、遠(yuǎn)程調(diào)用等,可能影響性能 |
| 使用 ThreadLocal 要注意內(nèi)存泄漏 | 每次請求結(jié)束后記得 remove 清理 |
| 不建議替代 Filter | 如跨域、編碼處理等仍推薦使用 Filter |
?? 五、總結(jié)對比表
| 功能 | 說明 |
|---|---|
| preHandle | 在 Controller 執(zhí)行前調(diào)用,可中斷請求 |
| postHandle | 在 Controller 執(zhí)行后、視圖渲染前調(diào)用 |
| afterCompletion | 請求完全結(jié)束后調(diào)用,可用于資源釋放 |
| 應(yīng)用場景 | 登錄校驗、權(quán)限控制、日志記錄、防重提交 |
| 優(yōu)點(diǎn) | 解耦業(yè)務(wù)邏輯、統(tǒng)一處理請求 |
| 缺點(diǎn) | 濫用會影響性能、增加系統(tǒng)復(fù)雜度 |
?? 六、結(jié)語
Spring Boot 攔截器是構(gòu)建高質(zhì)量 Web 應(yīng)用不可或缺的利器之一。通過合理使用攔截器,我們可以優(yōu)雅地實(shí)現(xiàn)登錄驗證、權(quán)限控制、日志記錄等通用功能,使代碼更簡潔、系統(tǒng)更健壯。
無論你是開發(fā)企業(yè)級后臺管理系統(tǒng),還是搭建高并發(fā) API 接口平臺,都應(yīng)該掌握攔截器的使用技巧。
到此這篇關(guān)于Spring Boot 攔截器實(shí)戰(zhàn)指南之登錄驗證、日志記錄、權(quán)限控制的文章就介紹到這了,更多相關(guān)Spring Boot 攔截器實(shí)戰(zhàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot登錄驗證token攔截器的實(shí)現(xiàn)
- Java SpringBoot 使用攔截器作為權(quán)限控制的實(shí)現(xiàn)方法
- SpringBoot集成MyBatis實(shí)現(xiàn)SQL攔截器的實(shí)戰(zhàn)指南
- SpringBoot集成MyBatis中SQL攔截器的實(shí)戰(zhàn)指南
- Spring?Boot攔截器Interceptor與過濾器Filter實(shí)戰(zhàn)指南
- Spring?Boot攔截器和監(jiān)聽器實(shí)現(xiàn)對請求和響應(yīng)處理實(shí)戰(zhàn)
- Spring Boot項目實(shí)戰(zhàn)之?dāng)r截器與過濾器
相關(guān)文章
使用Springboot注入帶參數(shù)的構(gòu)造函數(shù)實(shí)例
這篇文章主要介紹了使用Springboot注入帶參數(shù)的構(gòu)造函數(shù)實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04
EasyExcel自定義下拉注解的三種實(shí)現(xiàn)方式總結(jié)
使用EasyExcel設(shè)置下拉數(shù)據(jù)時,每次都要創(chuàng)建一個SheetWriteHandler組件確實(shí)比較繁瑣,為了優(yōu)化這個過程,我們可以通過自定義注解來簡化操作,下面就來看看具體實(shí)現(xiàn)方法吧2024-10-10
SpringSecurity的TokenStore四種實(shí)現(xiàn)方式小結(jié)
本文主要介紹了SpringSecurity的TokenStore四種實(shí)現(xiàn)方式小結(jié),分別是InMemoryTokenStore,JdbcTokenStore,JwkTokenStore,RedisTokenStore,具有一定的參考價值,感興趣的可以了解一下2024-01-01

