訊聯云庫項目開發日志(二)AOP參數攔截

目錄

利用AOP實現參數攔截:

一、??HTTP請求進入Controller?(發送郵件驗證碼)

二、AOP切面觸發

1. 切面攔截(GlobalOperactionAspect.class)

method.getAnnotation()??

?null == interceptor?判斷??

2.參數校驗注解

3. 參數校驗入口??(valiadateParams方法)

三. 對象類型遞歸校驗??(checkObValue方法)[這段代碼沒有調用這個方法,下面有解釋]

四. 基礎類型校驗??(checkValue方法)

五、工具類調用

六、流程圖?

?編輯

七、典型校驗失敗場景示例

六、設計亮點解析

總結流程

疑問:


利用AOP實現參數攔截:

一、??HTTP請求進入Controller?(發送郵件驗證碼)

@RequestMapping("/sendEmailCode")
@GloballInterceptor(checkParams=true) // 觸發AOP攔截
public ResponseVO sendEmailCode(HttpSession session, @VerifyParam(required = true) String email,@VerifyParam(required = true) String checkCode,@VerifyParam(required = true) Integer type){// 實際方法體執行前會先被AOP攔截
}

二、AOP切面觸發

0.首先我們先定義一個切點方法

    @Pointcut("@annotation(com.cjl.annotation.GloballInterceptor)")//  表示下面方法為切點方法private void requestIntercector() {System.out.println("請求攔截");}
  1. 切點(@Pointcut)??:定義“在哪里攔截”,不包含邏輯。
  2. ??增強(@Before/@Around)??:定義“攔截后做什么”,需引用切點。
  3. ??注解匹配??:通過?@annotation?實現聲明式攔截,避免硬編碼。
1. 切面攔截(GlobalOperactionAspect.class)

這是一個全局攔截器

@Before("requestIntercector()") // 聲明在切點方法執行前運行
public void interceptor(JoinPoint point) throws BusinessException {try {// 1. 獲取目標方法元信息Object target = point.getTarget(); // 獲取被代理的目標對象實例Object[] arguments = point.getArgs(); // 獲取方法調用參數值數組String methodName = point.getSignature().getName(); // 獲取目標方法名稱// 2. 通過方法簽名獲取精確的方法定義(考慮方法重載情況)MethodSignature signature = (MethodSignature) point.getSignature();Class<?>[] parameterTypes = signature.getMethod().getParameterTypes();Method method = target.getClass().getMethod(methodName, parameterTypes);// 3. 檢查方法上的攔截器注解GloballInterceptor interceptor = method.getAnnotation(GloballInterceptor.class);if (null == interceptor) {return; // 無攔截注解則直接放行}// 4. 執行參數校驗(根據注解配置決定)if (interceptor.checkParams()) {valiadateParams(method, arguments); // 進入核心校驗流程}} catch (BusinessException e) {// 業務級異常處理(如參數校驗失敗)log.error("全局攔截器攔截到業務異常", e);throw e; // 原樣拋出保持異常鏈} catch (Exception e) {// 系統級異常處理(如反射異常)log.error("全局攔截器發生系統異常", e);throw new BusinessException("系統繁忙,請稍后重試");} catch (Throwable e) {// 兜底處理所有錯誤(包括Error)log.error("全局攔截器捕獲不可預期錯誤", e);throw new BusinessException("系統服務不可用");}
}
method.getAnnotation()??
  • ??作用??:通過反射獲取方法上的?@GloballInterceptor?注解實例
?null == interceptor?判斷??
  • ??條件成立??:表示該方法??沒有標注???@GloballInterceptor
  • ??執行邏輯??:直接退出攔截器,??不進行任何校驗??,讓方法正常執行

2.參數校驗注解
@Retention(RetentionPolicy.RUNTIME)//  表示注解在運行時存在
@Target({ElementType.PARAMETER,ElementType.FIELD})//  表示該注解用于方法參數和字段上
public @interface VerifyParam {int min() default -1;int max() default -1;boolean required() default true; //  是否必傳//正則校驗VerifyRegexEnum regex() default VerifyRegexEnum.NO;//默認不校驗
}
3. 參數校驗入口??(valiadateParams方法)
private void valiadateParams(Method method, Object[] arguments) throws BusinessException {// 獲取方法的所有參數定義Parameter[] parameters = method.getParameters();// 遍歷每個參數for (int i = 0; i < parameters.length; i++) {Parameter parameter = parameters[i];Object value = arguments[i];// 獲取參數上的校驗注解VerifyParam verifyParam = parameter.getAnnotation(VerifyParam.class);if (null == verifyParam) {continue; // 無校驗注解則跳過}// 基本數據類型校驗(String/Long/Integer)if (TyPE_STRING.equals(parameter.getType().getName())|| TyPE_LONG.equals(parameter.getType().getName())|| TyPE_INTEGER.equals(parameter.getType().getName())) {checkValue(value, verifyParam);}// 對象類型校驗else {checkObValue(parameter, value);}}}

三. 對象類型遞歸校驗??(checkObValue方法)[這段代碼沒有調用這個方法,下面有解釋]

    private void checkObValue(Parameter parameter, Object value) throws BusinessException {try {// 1. 獲取參數的實際類型(支持泛型)String typeName = parameter.getParameterizedType().getTypeName();Class<?> classz = Class.forName(typeName); // 加載類定義// 2. 遍歷對象的所有字段Field[] fields = classz.getDeclaredFields();for (Field field : fields) {// 3. 檢查字段上的校驗注解VerifyParam fieldVerifyParam = field.getAnnotation(VerifyParam.class);if (fieldVerifyParam == null) {continue; // 無注解字段跳過}// 4. 獲取字段值(突破private限制)field.setAccessible(true);Object resultValue = field.get(value);// 5. 遞歸校驗字段值checkValue(resultValue, fieldVerifyParam); // 調用基礎校驗方法}} catch (BusinessException e) {// 透傳業務校驗異常log.error("對象參數校驗業務異常", e);throw e;} catch (Exception e) {// 處理反射等系統異常log.error("對象參數校驗系統異常", e);throw new BusinessException(ResponseCodeEnum.CODE_600);}}

四. 基礎類型校驗??(checkValue方法)

private void checkValue(Object value, VerifyParam verifyParam) throws BusinessException {/*** 空值檢測準備*/Boolean isEmpty = value==null || StringTools.isEmpty(value.toString());Integer length  = value==null?null:value.toString().length();/*** 校驗空*/if(isEmpty && verifyParam.required()){throw new BusinessException(ResponseCodeEnum.CODE_600);}/*** 校驗長度*/if(!isEmpty && (verifyParam.max() != -1&& verifyParam.max()< length || verifyParam.min() != -1 && verifyParam.min()>length)){throw new BusinessException(ResponseCodeEnum.CODE_600);}/*** 校驗正則*/if(!isEmpty && !StringTools.isEmpty(verifyParam.regex().getRegex())&& !VerifyUtils.verify(verifyParam.regex(),String.valueOf(value))){throw new BusinessException(ResponseCodeEnum.CODE_600);}}


五、工具類調用

1.空值判斷(StringTools)?

public static boolean verify(VerifyRegexEnum regex, String value) {// 調用重載方法(圖片中定義的EMAIL/PASSWORD規則在此生效)return verify(regex.getRegex(), value); // ← 使用枚舉中的正則表達式
}private static boolean verify(String regex, String value) {Pattern p = Pattern.compile(regex); // ← 編譯正則表達式(如EMAIL的復雜規則)return p.matcher(value).matches();  // ← 執行實際匹配
}

2.正則校驗(VerifyUtils)?

// 圖片中定義的枚舉校驗規則
public enum VerifyRegexEnum {EMAIL("^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$", "郵箱格式錯誤"),PASSWORD("^(?=.*\\d)(?=.*[a-zA-Z]).{8,18}$", "需包含字母和數字,8-18位");// 當@VerifyParam(regex=VerifyRegexEnum.EMAIL)時:// 實際使用的正則表達式就是EMAIL枚舉實例中的regex值
}

六、流程圖?

七、典型校驗失敗場景示例

  1. ??空值校驗失敗??

    • 調用:sendEmailCode(null, "123", 0)
    • 拋出:BusinessException("參數不能為空")
  2. ??郵箱格式錯誤??

    • 調用:sendEmailCode("invalid#email", "123", 0)
    • 匹配:EMAIL正則表達式失敗
    • 拋出:BusinessException("郵箱格式錯誤")(消息來自枚舉的desc字段)

八、設計亮點解析

  1. ??雙校驗層設計??

    • 前端:基礎非空校驗(快速反饋)
    • 后端:AOP+正則深度校驗(安全兜底)
  2. ??規則集中管理??

    // 修改密碼規則只需調整枚舉即可全局生效
    PASSWORD("^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,20}$", "需包含大小寫字母和數字")

  3. ??遞歸對象校驗??
    支持對嵌套對象的字段級校驗:

    public void update(@VerifyParam UserDTO user) {// 會自動校驗UserDTO中所有帶@VerifyParam的字段
    }

總結流程

🔀 ??參數校驗流程全鏈路總結??:

HTTP請求 → @GloballInterceptor觸發AOP?
→ 解析@VerifyParam注解?
→ 分發校驗(基本類型→checkValue() / 對象類型→遞歸checkObValue())?
→ 調用StringTools/VerifyRegexEnum工具
→ 校驗失敗拋BusinessException?
→ 校驗通過執行業務邏

??核心箭頭圖??:

Controller 
→ 🌐 AOP切面 
→ 🔍 參數掃描 
→ ?? 規則匹配 
→ ?/? 校驗結果 
→ ? 業務邏輯/異常返回  

疑問:

1.為什么遍歷對象所有帶@VerifyParam注解的字段進行校驗為什么是遞歸?

答:遍歷對象字段校驗”本身不是遞歸,但當字段本身又是對象時,需要再次觸發相同的校驗流程??,這才是遞歸的本質

如果變量是普通字段(checkvalue(user對象)),會采取普通字段校驗,比如:

// 簡單User對象(無嵌套)
public class User {@VerifyParam String name; // 基本類型字段@VerifyParam Integer age; // 基本類型字段
}

如果變量是??嵌套對象字段->觸發遞歸,比如:

// 嵌套的Order對象,里面有User
public class Order {@VerifyParam User user; // 對象類型字段!
}

校驗流程??:

  1. checkObValue(Order對象)?→ 發現user字段是對象類型
  2. ??遞歸調用???checkObValue(user)?→ 進入User類的字段校驗
  3. 如果User類中還有對象字段,繼續向下遞歸
    🔁 ??這才是真正的遞歸調用鏈!

2.@Pointcut切點和@GloballInterceptor是什么關系?

🔍 ??準確關系說明??:

@Pointcut?和?@GloballInterceptor?是??觀察者與被觀察者??的關系,具體流程如下:

  1. ??你在方法上標注?@GloballInterceptor?→ 聲明"這個方法需要被攔截

  2. @Pointcut?像掃描儀一樣持續監控所有方法

  3. 通過表達式?@annotation(com.cjl.annotation.GloballInterceptor)?專門尋找帶該注解的方法

  4. // 切面內部工作原理
    if (當前方法有@GloballInterceptor注解) {
    ? ? 執行@Before/...增強邏輯(interceptor方法);
    }

3.這個JoinPoint point參數傳進來的是什么?

@Before("requestIntercector()")?public void interceptorDO(JoinPoint point) throws BusinessException {...
}

解析一下:

@Before("requestIntercector()")
public void interceptorDO(JoinPoint point) {// 1. 獲取目標方法實例Method method = ((MethodSignature) point.getSignature()).getMethod();// 輸出:public com.cjl.vo.ResponseVO com.cjl.controller.SessionController.sendEmailCode(...)// 2. 獲取方法參數值數組(按聲明順序)Object[] args = point.getArgs(); // 內容:[HttpSession實例, "user@example.com", "A7b9", 1]// 3. 獲取具體參數HttpSession session = (HttpSession) args[0]; // 第一個參數String email = (String) args[1];            // 第二個參數String checkCode = (String) args[2];        // 第三個參數Integer type = (Integer) args[3];           // 第四個參數// 4. 獲取注解配置VerifyParam emailVerify = method.getParameters()[1].getAnnotation(VerifyParam.class);// 獲取email參數的@VerifyParam(required=true)注解
}

4.它怎么知道我要不要攔截檢驗

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

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

相關文章

用OBD部署OceanBase社區版的避坑指南

以下是用OBD黑屏部署 OceanBase社區版時容易碰到的幾個問題及解決思路&#xff0c;供大家參考。 一、 遇坑步驟&#xff1a;用yaml文件部署集群&#xff1a; obd cluster deploy obtest -c mini-single-example.yaml 報錯&#xff1a; Package oceanbase-ce-4.2.1.8-108000…

無錫哲訊科技:引領芯片封裝SAP系統的智能化革命

芯片封裝行業的數字化轉型 在全球半導體產業高速發展的今天&#xff0c;芯片封裝作為產業鏈的關鍵環節&#xff0c;直接影響著芯片的性能、可靠性和成本。隨著5G、人工智能、物聯網等技術的普及&#xff0c;市場對芯片的需求激增&#xff0c;封裝企業面臨著效率提升、良率優…

從海洋生物找靈感:造個機器人RoboPteropod,它能在水下干啥?

大家好&#xff01;在如今人類對水下環境探索不斷深入的時代&#xff0c;從水下考古到珊瑚礁考察&#xff0c;各種任務都離不開水下機器人的助力。但傳統水下機器人尺寸較大&#xff0c;在狹窄的水下空間施展不開。今天&#xff0c;我們就來認識一款受海洋小生物啟發而設計的仿…

區塊鏈blog1__合作與信任

&#x1f342;我們的世界 &#x1f33f;不是孤立的&#xff0c;而是網絡化的 如果是單獨孤立的系統&#xff0c;無需共識&#xff0c;而我們的社會是網絡結構&#xff0c;即結點間不是孤立的 &#x1f33f;網絡化的原因 而目前并未發現這樣的理想孤立系統&#xff0c;即現實中…

Linux服務之lvs+keepalived nginx+keepalived負載均衡實例解析

目錄 一.LVSKeepAlived高可用負載均衡集群的部署 二.NginxKeepAlived高可用負載均衡集群的部署 一.LVSKeepAlived高可用負載均衡集群的部署 實驗環境 主keepalived&#xff1a;192.168.181.10 lvs &#xff08;7-1&#xff09; 備keepalived&#xff1a;192.168.181.10…

50天50個小項目 (Vue3 + Tailwindcss V4) ? |搭建項目框架

&#x1f5a4; 一個專注于「Vue3 TailwindCSS」的 50 天極簡開發挑戰&#xff0c;探索組件邊界&#xff0c;打磨技術鋒芒。 &#x1f389; 歡迎來到 50 個小項目的第一天&#xff01;今天我們將從零開始搭建一個 Vue3 項目&#xff0c;并引入 Tailwind CSS v4&#xff0c;為后…

Android 中 網絡圖片加載庫 Glide 簡介

Glide 是一個功能強大且廣泛使用的圖片加載庫,適用于 Android 應用程序。它提供了簡單易用的 API,用于從網絡、本地存儲或資源中加載圖片,并支持圖片的緩存、轉換、占位圖、動畫等功能。 一、Glide 主要特點 簡單易用 提供簡潔的 API,一行代碼即可加載圖片。 支持多種數據…

07 web 自動化之 Unittest 應用:測試報告裝飾器斷言

文章目錄 一、常見的第三方庫結合 unittest 生產 html 格式測試報告1、HtmlTestRunner2、BeatifulReport 二、裝飾器 unittest.skip 強制跳過&條件跳過三、unittest的常用斷言方法 一、常見的第三方庫結合 unittest 生產 html 格式測試報告 1、HtmlTestRunner 官網下載 …

【Python 面向對象】

Python 的面向對象編程&#xff08;OOP&#xff09;通過類&#xff08;Class&#xff09;和對象&#xff08;Object&#xff09;實現代碼結構化&#xff0c;支持封裝、繼承和多態三大特性。以下是系統化指南&#xff1a; 一、類與對象基礎 1. 定義類 class Dog:# 類屬性&…

STM32F103_LL庫+寄存器學習筆記23 - PWM波形輸出及軟件方式調整周期與占空比

導言 脈寬調制&#xff08;PWM&#xff09;是 STM32 定時器最常用的輸出模式之一&#xff0c;廣泛應用于電機驅動、LED 調光、伺服控制和功率管理等場景。本篇文章將以 TIM5 為例&#xff0c;從寄存器層面深入剖析 PWM 輸出的原理與實現步驟。通過本篇博客&#xff0c;你不僅能…

堆(Heap)

1. 堆&#xff08;Heap&#xff09; 1.1. Python實現堆的插入、堆頂刪除和排序 class MaxHeap:def __init__(self):# 初始化空堆&#xff0c;使用列表表示self.heap []def insert(self, val):# 插入元素并執行上浮self.heap.append(val)self._sift_up(len(self.heap) - 1)de…

Spring類

BeanDefinition BeanDefinition表示Bean定義&#xff0c;BeanDefinition中存在很多屬性用來描述一個Bean的特點。比如&#xff1a; class&#xff0c;表示Bean類型scope&#xff0c;表示Bean作用域&#xff0c;單例或原型等lazyInit&#xff1a;表示Bean是否是懶加載initMeth…

在vue中this.$emit有哪些作用,事件監控具體含義,以及這些子組件能封裝哪些功能組件

this.$emit 的作用 this.$emit 的作用是觸發一個自定義事件&#xff0c;并將數據傳遞給父組件。父組件可以通過 v-on&#xff08;或 &#xff09;監聽這個事件&#xff0c;并在事件觸發時執行相應的處理函數。 this.content 的作用 this.content 是子組件的 props&#xff0…

前端流行框架Vue3教程:16. 組件事件配合`v-model`使用

組件事件配合v-model使用 如果是用戶輸入&#xff0c;我們希望在獲取數據的同時發送數據配合v-model 來使用&#xff0c;幫助理解組件間的通信和數據綁定。 &#x1f9e9; 第一步&#xff1a;創建子組件&#xff08;SearchComponent.vue&#xff09; 這個組件用于處理用戶的搜…

《Navicat之外的新選擇:實測支持國產數據庫的SQLynx核心功能解析》

數據庫工具生態的新變量 在數據庫管理工具領域&#xff0c;Navicat長期占據開發者心智。但隨著國產數據庫崛起和技術信創需求&#xff0c;開發者對工具的兼容性、輕量化和本土化適配提出了更高要求。近期體驗了一款名為SQLynx的國產數據庫管理工具&#xff08;麥聰旗下產品&am…

AgenticSeek開源的完全本地的 Manus AI。無需 API,享受一個自主代理,它可以思考、瀏覽 Web 和編碼,只需支付電費。

?一、軟件介紹 文末提供程序和源碼下載 AgenticSeek開源的完全本地的 Manus AI。無需 API&#xff0c;享受一個自主代理&#xff0c;它可以思考、瀏覽 Web 和編碼&#xff0c;只需支付電費。這款支持語音的 AI 助手是 Manus AI 的 100% 本地替代品 &#xff0c;可自主瀏覽網頁…

vue3.0的name屬性插件——vite-plugin-vue-setup-extend

安裝 這個由于是在開發環境下的一個插件 幫助我們支持name屬性 所以需要是-D npm i vite-plugin-vue-setup-extend -D在pasckjson中無法注釋每個插件的用處 可以在vscode中下載一個JsonComments這樣可以在json中添加注釋方便日后維護和查閱API 引入 在vite.config.js中 im…

Linux基礎 -- 在內存中使用chroot修復eMMC

Linux基礎 – 在內存中使用chroot修復eMMC 概述 本教程將介紹如何在Linux系統中&#xff0c;使用chroot在內存中構建一個臨時系統&#xff0c;并在不依賴原有系統的情況下修復eMMC&#xff08;如/dev/mmcblk2&#xff09;磁盤。該方法適用于嵌入式系統修復、磁盤清理以及離線…

人工智能、深度學習、機器學習的聯系與區別

定義 人工智能&#xff08;AI - Artificial Intelligence&#xff09; &#xff1a;是研究、開發用于模擬、延伸和擴展人的智能的理論、方法、技術及應用系統的一門新的技術科學。它旨在讓計算機能夠像人類一樣思考、學習和決策&#xff0c;涉及到諸如計算機視覺、自然語言處理…

web第二次課后作業--設計一個注冊登錄系統

一、頁面展示 登錄頁面 提交頁面 二、代碼 2.1 登錄頁面 <% page language"java" contentType"text/html; charsetUTF-8"pageEncoding"UTF-8"%><html> <head><meta http-equiv"Content-Type" content"…