最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot 攔截器 (Interceptor)與切面 (AOP)示例、作用及適用場景分析

 更新時(shí)間:2026年01月30日 11:19:24   作者:康小莊  
攔截器是SpringMVC框架的組件,基于Java動(dòng)態(tài)代理實(shí)現(xiàn),作用于Web層(Controller 層),僅能攔截HTTP請求的處理過程,生命周期與 SpringMVC的請求處理流程綁定,本文介紹SpringBoot攔截器 (Interceptor)與切面(AOP)示例、作用及適用場景分析,感興趣的朋友一起看看吧

SpringBoot 攔截器 (Interceptor) 與切面 (AOP):示例、作用、及適用場景

一、攔截器 (Interceptor):SpringMVC 層的請求攔截器

攔截器是SpringMVC 框架的組件,基于Java 動(dòng)態(tài)代理實(shí)現(xiàn),作用于Web 層(Controller 層),僅能攔截 HTTP 請求的處理過程,生命周期與 SpringMVC 的請求處理流程綁定。

核心作用

  1. 攔截 Controller 層的 HTTP 請求(如 GET/POST 請求);
  2. 實(shí)現(xiàn)請求前的預(yù)處理(如登錄校驗(yàn)、token 驗(yàn)證、跨域配置);
  3. 實(shí)現(xiàn)請求后的后置處理(如響應(yīng)數(shù)據(jù)統(tǒng)一封裝);
  4. 實(shí)現(xiàn)請求完成后的最終處理(如資源釋放、請求日志記錄)。

1.自定義攔截器:實(shí)現(xiàn)HandlerInterceptor接口

@Component
@Slf4j
public class CompanyContextInterceptor implements HandlerInterceptor {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    private static final String REDIS_TOKEN_KEY_PREFIX = "login:";
    // 請求開始前:解析 Header,設(shè)置公司編碼到上下文
    @Override
    public boolean preHandle(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception {
        // 1. 從請求頭獲取Token(Bearer Token格式)
        String authHeader = request.getHeader("Authorization");
        if (StringUtils.isBlank(authHeader) || !authHeader.startsWith("Bearer ")) {
            // 未攜帶Token,直接通過(或返回401,根據(jù)業(yè)務(wù)需求)
            return true;
        }
        String token = authHeader.substring(7); // 截取Bearer后的Token
        // 2. 從Redis查詢登錄用戶信息
        String redisKey = REDIS_TOKEN_KEY_PREFIX + token;
        LoginController.LoginWxUser loginWxUser = (LoginController.LoginWxUser) redisTemplate.opsForValue().get(redisKey);
        if (loginWxUser == null || StringUtils.isBlank(loginWxUser.getPhone())) {
            // Token無效/過期,直接通過(或返回401)
            return true;
        }
        // 3. 核心:將loginWxUser存入request,key必須是「loginWxUser」(和接口一致?。?
        request.setAttribute("loginWxUser", loginWxUser);
        // 可選:Token續(xù)期
        redisTemplate.expire(redisKey, 7, TimeUnit.DAYS);
        // 獲取請求路徑
        String requestURI = request.getRequestURI();
        // 檢查是否為需要忽略的登錄接口
        if (requestURI.equals("/workaffairs/api/user/loginByPhone") ||
                requestURI.startsWith("/workaffairs/api/user/loginByPhone")) {
            return true; // 直接放行,不設(shè)置公司編碼
        }
        // 從 Header 獲取公司編碼
        String companyCode = request.getHeader("x-Company-Code");
        if (companyCode != null && !companyCode.isEmpty()) {
            CompanyContextHolder.setCompanyCode(companyCode);
            log.info("獲取到公司編碼----" + companyCode);
        }
        return true; // 放行請求
    }
    // 請求結(jié)束后:清理上下文(必須執(zhí)行,避免內(nèi)存泄漏)
    @Override
    public void afterCompletion(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, Exception ex) throws Exception {
        CompanyContextHolder.clear();
    }
}

2.攔截器配置類:實(shí)現(xiàn)WebMvcConfigurer接口

/**
 * 攔截器配置類:注冊攔截器并配置攔截規(guī)則
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    // 注入自定義攔截器
    @Resource
    private CompanyContextInterceptor companyContextInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(companyContextInterceptor)
                // 攔截所有需要切換數(shù)據(jù)源的業(yè)務(wù)接口(根據(jù)你的實(shí)際路徑調(diào)整)
                .addPathPatterns("/purchase/**", "/delivery/**","/api/user/getSupplierByCompany")
                // 排除不需要攔截的接口(比如登錄接口)
                .excludePathPatterns("/api/user/loginByPhone");
    }
}

二、切面 (AOP):面向切面的通用橫切邏輯實(shí)現(xiàn)

核心概念

切面是Spring AOP 框架的核心,基于JDK 動(dòng)態(tài)代理(針對接口)+CGLIB 動(dòng)態(tài)代理(針對類) 實(shí)現(xiàn),是面向切面編程的落地方式,可作用于Spring 容器管理的所有 Bean(Controller、Service、Dao、普通組件等),無層級限制。

核心作用

  1. 提取通用橫切邏輯(與業(yè)務(wù)無關(guān)、可復(fù)用的邏輯),如日志記錄、事務(wù)管理、耗時(shí)統(tǒng)計(jì)、異常統(tǒng)一捕獲;
  2. 實(shí)現(xiàn)業(yè)務(wù)代碼與橫切邏輯的解耦,無需在業(yè)務(wù)方法中硬編碼通用邏輯;
  3. 可對任意方法進(jìn)行增強(qiáng)(前置增強(qiáng)、后置增強(qiáng)、環(huán)繞增強(qiáng)、異常增強(qiáng)等),支持靈活的切點(diǎn)表達(dá)式配置。

1.自定義切面

@Aspect // 聲明為切面類
@Component // 交給Spring容器管理
@Slf4j
public class DbOperationLogAspect {
    /**
     * 定義切點(diǎn):指定切面作用的目標(biāo)方法
     * 表達(dá)式規(guī)則:execution(訪問修飾符 返回值 包名.類名.方法名(參數(shù)類型))
     * 示例:匹配com.tgerp.workaffairs.mapper包下所有類的所有方法
     */
    @Pointcut("execution(* com.tgerp.workaffairs.mapper..*(..))")
    public void dbOperationPointCut() {
    }
    @Around("dbOperationPointCut()")
    public Object aroundDbOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        // 1. 此時(shí)controller已經(jīng)執(zhí)行了setDbName,能拿到正確的數(shù)據(jù)庫名
        String currentDbName = DynamicDataSourceContextHolder.peek(); // 從數(shù)據(jù)源上下文拿
//        }
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        // 打印日志
        log.info("[workaffairs-數(shù)據(jù)庫: {}] 執(zhí)行數(shù)據(jù)庫操作 - 類:{},方法:{}", currentDbName, className, methodName);
        try {
            return joinPoint.proceed();
        } catch (Exception e) {
            log.error("[workaffairs-數(shù)據(jù)庫: {}] 數(shù)據(jù)庫操作失敗 - 類:{},方法:{},異常信息:{}",
                    currentDbName, className, methodName, e.getMessage(), e);
            throw e;
        }
    }
}

三、攔截器與切面的適用場景

選型核心原則:根據(jù)橫切邏輯的「作用范圍」和「是否與 Web 請求相關(guān)」判斷

攔截器 (Interceptor):僅適用于Web 相關(guān)的橫切邏輯

所有與 HTTP 請求強(qiáng)綁定的場景,優(yōu)先使用攔截器,因?yàn)榭芍苯荧@取 Web 上下文(Request/Response),無需額外處理:

  1. 登錄 / 權(quán)限校驗(yàn):基于請求頭 / 參數(shù)驗(yàn)證 token、會話、用戶身份;
  2. 跨域配置:統(tǒng)一設(shè)置響應(yīng)頭(Access-Control-Allow-Origin 等);
  3. 請求參數(shù)預(yù)處理:統(tǒng)一解析請求頭、請求參數(shù),如防 XSS 處理;
  4. 響應(yīng)數(shù)據(jù)統(tǒng)一封裝:對 Controller 返回的結(jié)果統(tǒng)一添加 code/msg/data 格式;
  5. Web 層日志記錄:記錄請求 URI、請求方式、IP、響應(yīng)狀態(tài)等 Web 相關(guān)信息;
  6. 接口限流:基于 IP / 請求頻率限制 HTTP 請求(如每秒最大請求數(shù))。

切面 (AOP):適用于通用、跨層的橫切邏輯

所有與業(yè)務(wù)無關(guān)、需要在多層級復(fù)用的通用橫切邏輯,優(yōu)先使用切面,解耦效果最佳,無環(huán)境依賴:

  1. 全局日志記錄:記錄方法的入?yún)ⅰ⒊鰠?、?zhí)行耗時(shí)(適用于 Service/Dao 層);
  2. 事務(wù)管理:通過@Transactional(底層基于 AOP)實(shí)現(xiàn)方法級事務(wù)控制;
  3. 方法級權(quán)限校驗(yàn):基于自定義注解(如 @RequiresPermission)實(shí)現(xiàn)方法訪問控制;
  4. 異常統(tǒng)一捕獲:捕獲指定層的異常,統(tǒng)一封裝異常響應(yīng)(如 Service 層業(yè)務(wù)異常);
  5. 緩存控制:實(shí)現(xiàn)方法級緩存(如查詢方法結(jié)果緩存,避免重復(fù)查詢);
  6. 性能監(jiān)控:統(tǒng)計(jì)指定方法的執(zhí)行耗時(shí)、調(diào)用次數(shù),做系統(tǒng)性能分析;
  7. 非 Web 環(huán)境的橫切邏輯:如定時(shí)任務(wù)、后臺服務(wù)的方法增強(qiáng)(無 Web 上下文,攔截器無法使用)。

實(shí)際項(xiàng)目中,攔截器和切面并非互斥,而是協(xié)同工作,各自負(fù)責(zé)專屬領(lǐng)域的橫切邏輯,形成完整的橫切體系:

例如:一個(gè)接口的完整處理流程中:

  1. 攔截器:在請求進(jìn)入 Controller 前,完成登錄校驗(yàn)、token 驗(yàn)證(Web 層專屬);
  2. 切面:在 Service 層方法執(zhí)行時(shí),完成耗時(shí)統(tǒng)計(jì)、事務(wù)管理、異常捕獲(通用跨層);
  3. 攔截器:在請求完成后,完成響應(yīng)數(shù)據(jù)封裝、Web 日志記錄(Web 層專屬)。

這種協(xié)同模式既保證了 Web 相關(guān)邏輯的高效處理,又實(shí)現(xiàn)了通用邏輯的跨層復(fù)用,是 SpringBoot 項(xiàng)目的標(biāo)準(zhǔn)實(shí)踐。

到此這篇關(guān)于SpringBoot 攔截器 (Interceptor)與切面 (AOP)示例、作用及適用場景分析的文章就介紹到這了,更多相關(guān)SpringBoot 攔截器和切面內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java語法關(guān)于泛型與類型擦除的分析

    Java語法關(guān)于泛型與類型擦除的分析

    泛型沒有其看起來那么深不可測,它并不神秘與神奇,泛型是Java 中一個(gè)很小巧的概念,但同時(shí)也是一個(gè)很容易讓人迷惑的知識點(diǎn),它讓人迷惑的地方在于它的許多表現(xiàn)有點(diǎn)違反直覺
    2021-09-09
  • Java向kettle8.0傳遞參數(shù)的方式總結(jié)

    Java向kettle8.0傳遞參數(shù)的方式總結(jié)

    介紹了如何在Kettle中傳遞參數(shù)到轉(zhuǎn)換和作業(yè)中,包括設(shè)置全局properties、使用TransMeta和JobMeta的parameterValue,以及通過EL表達(dá)式獲取參數(shù)值
    2025-01-01
  • 詳解Java線程池隊(duì)列中的延遲隊(duì)列DelayQueue

    詳解Java線程池隊(duì)列中的延遲隊(duì)列DelayQueue

    這篇文章主要為大家詳細(xì)介紹了Java線程池隊(duì)列中的延遲隊(duì)列DelayQueue的相關(guān)資料,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-12-12
  • 一文教你利用Stream?API批量Mock數(shù)據(jù)的方法

    一文教你利用Stream?API批量Mock數(shù)據(jù)的方法

    在日常開發(fā)的過程中我們經(jīng)常會遇到需要mock一些數(shù)據(jù)的場景,比如說?mock?一些接口的返回或者說?mock?一些測試消息用于隊(duì)列生產(chǎn)者發(fā)送消息。本文將教你如何通過?Stream?API?批量?Mock?數(shù)據(jù),需要的可以參考一下
    2022-09-09
  • SpringBoot實(shí)現(xiàn)數(shù)據(jù)轉(zhuǎn)換的四種對象映射方案

    SpringBoot實(shí)現(xiàn)數(shù)據(jù)轉(zhuǎn)換的四種對象映射方案

    在項(xiàng)目開發(fā)中,對象之間的相互轉(zhuǎn)換是一個(gè)高頻操作,尤其在分層架構(gòu)的系統(tǒng)中,數(shù)據(jù)在實(shí)體對象(Entity)、數(shù)據(jù)傳輸對象(DTO)、值對象(VO)之間的轉(zhuǎn)換尤為常見,選擇一個(gè)高效、可靠的對象映射方案對提高系統(tǒng)性能和開發(fā)效率至關(guān)重要,本文將介紹4種對象映射方案
    2025-06-06
  • 解決springboot遇到autowire注入為null的問題

    解決springboot遇到autowire注入為null的問題

    這篇文章主要介紹了解決springboot遇到autowire注入為null的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • Java中ArrayList集合的常用方法大全

    Java中ArrayList集合的常用方法大全

    這篇文章主要給大家介紹了關(guān)于Java中ArrayList集合的常用方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Java中如何實(shí)現(xiàn)不可變Map詳解

    Java中如何實(shí)現(xiàn)不可變Map詳解

    這篇文章主要給大家介紹了關(guān)于Java中如何實(shí)現(xiàn)不可變Map的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作工具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-12-12
  • SpringBoot讀取Resource目錄文件的五種常見方式

    SpringBoot讀取Resource目錄文件的五種常見方式

    在Spring Boot開發(fā)中,我們經(jīng)常需要讀取src/main/resources目錄下的文件,src/main/resources 目錄下通常存放配置文件、模板、靜態(tài)資源、SQL腳本等,本文給大家介紹了SpringBoot讀取Resource目錄文件的五種常見方式,需要的朋友可以參考下
    2025-07-07
  • Spring中自定義Schema如何解析生效詳解

    Spring中自定義Schema如何解析生效詳解

    Spring2.5在2.0的基于Schema的Bean配置的基礎(chǔ)之上,再增加了擴(kuò)展XML配置的機(jī)制。通過該機(jī)制,我們可以編寫自己的Schema,并根據(jù)自定義的Schema用自定的標(biāo)簽配置Bean,下面這篇文章主要介紹了關(guān)于Spring中自定義Schema如何解析生效的相關(guān)資料,需要的朋友可以參考下
    2018-07-07

最新評論

平舆县| 浮梁县| 航空| 台南市| 凤阳县| 玉田县| 平武县| 静乐县| 洞口县| 广安市| 台中市| 阿拉善左旗| 吴桥县| 永年县| 宁城县| 土默特右旗| 乐清市| 南昌市| 衢州市| 西平县| 梅河口市| 徐闻县| 济宁市| 和林格尔县| 建阳市| 南丰县| 湖北省| 磐石市| 中西区| 临朐县| 化隆| 长宁县| 奉化市| 山丹县| 沙雅县| 林周县| 如皋市| 延长县| 阳信县| 正定县| 全南县|