SpringBoot实现参数校验拦截(采用AOP方式)

一、AOP是什么?

目的:分离横切关注点(如日志记录、事务管理)与核心业务逻辑。

优势:提高代码的可读性和可维护性。

关键概念

  • 切面(Aspect):包含横切关注点代码的模块。
  • 通知(Advice):切面中的具体动作,比如方法调用之前或之后执行的代码。
  • 连接点(Join Point):程序执行的某个具体点,比如方法调用。
  • 切入点(Pointcut):定义在哪些连接点应用通知。

二、使用步骤

1.引入库

代码如下(示例):

<dependencies><!-- 引入SpringBoot Aop依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- 引入Aspectj依赖 --><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.7</version></dependency>
</dependencies>

2.定义注解

定义注解GlobalInterceptor

代码示例:如下

@Target({ElementType.METHOD})//注解的目标类型是方法
@Retention(RetentionPolicy.RUNTIME)//注解在运行的时候生效
@Documented
@Mapping
public @interface GlobalInterceptor {/*** 校验参数* @return*/boolean checkParams() default false;
}

 定义注解用来校验具体参数

@Retention(RetentionPolicy.RUNTIME)//运行时校验
@Target({ElementType.PARAMETER,ElementType.FIELD})// 指定该注解可以应用的目标类型为参数和字段
public @interface VerifyParam {int min() default -1;//校验最小长度int max() default -1;//检验最大长度boolean required() default false; //校验是否必传VerifyRegexEnum regex() default VerifyRegexEnum.NO;//校验正则,默认状态是不校验的}

 可以看到上方的VerifyRegexEnum,这里是一个枚举,主要是来校验参数的,那么枚举代码示例如下:

public enum VerifyRegexEnum {NO("","不校验"),EMAII("^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$","邮箱"),PASSWORD("^(?=.*\\d)(?=.*[a-zA-Z])[\\da-zA-Z~!@#$号^&* ]{8,}$","只能是数字,字母,特殊字符 8-18位");private String regex;private String desc;VerifyRegexEnum(String regex, String desc) {this.regex = regex;this.desc = desc;}public String getRegex() {return regex;}public String getDesc() {return desc;}
}

 由于这里我的项目中只是简单的校验了一下邮箱和密码,需要的话,大家可以自行加入校验方式

 3.定义切面类

@Aspect//表明这是一个切面类
@Component("globalOperatcionAspect")// 交给Spring管理
public class GlobalOperatcionAspect {private static final Logger logger = LoggerFactory.getLogger(GlobalOperatcionAspect.class);private static final String[] TYPE_BASE = {"java.lang.String","java.lang.Integer","java.lang.Long"};//@Pointcut 定义切入点表达式,用于匹配目标方法,此处匹配带有@GlobalInterceptor注解的方法@Pointcut("@annotation(com.easypan.annotation.GlobalInterceptor)")private void requestInterceptor(){// 方法体为空,只是作为一个切入点标识}//@Before 在目标方法执行前执行@Before("requestInterceptor()")public void interceptorDo(JoinPoint point) throws BusinessException {try {Object target = point.getTarget();// 获取目标对象Object[] arguments = point.getArgs(); // 获取方法参数String methodName = point.getSignature().getName(); // 获取方法名Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes(); // 获取方法参数类型Method method = target.getClass().getMethod(methodName, parameterTypes); // 获取目标方法GlobalInterceptor interceptor = method.getAnnotation(GlobalInterceptor.class); // 获取方法上的全局拦截器注解if (null == interceptor) { // 如果注解为空则不执行拦截器逻辑return;}/*** 检验参数*/if (interceptor.checkParams()) { // 如果需要检验参数validateParams(method, arguments); // 执行参数校验}} catch (BusinessException e) {logger.error("全局拦截器异常", e); // 记录异常日志throw e; // 抛出业务异常} catch (Exception e) {logger.error("全局拦截器异常", e); // 记录异常日志throw new BusinessException(ResponseCodeEnum.CODE_500); // 抛出业务异常} catch (Throwable e) {logger.error("全局拦截器异常", e); // 记录异常日志throw new BusinessException(ResponseCodeEnum.CODE_500); // 抛出业务异常}}/*** 检验规则* @param method 方法* @param arguments 参数列表*/private void validateParams(Method method, Object[] arguments) {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 (verifyParam == null) { // 如果注解为空则跳过continue;}if (ArrayUtils.contains(TYPE_BASE, parameter.getParameterizedType().getTypeName())) { // 如果是基本类型checkValue(value, verifyParam); // 执行值校验} else {checkBObjValue(parameter, value); // 执行对象值校验}}}/*** 对象值校验* @param parameter 参数* @param value 参数值*/private void checkBObjValue(Parameter parameter, Object value) {try {String typeName = parameter.getParameterizedType().getTypeName(); // 获取参数类型名Class classz = Class.forName(typeName); // 获取类对象Field[] fields = classz.getDeclaredFields(); // 获取类的所有字段for (Field field : fields) { // 遍历字段VerifyParam fieldVerifyParam = field.getAnnotation(VerifyParam.class); // 获取字段上的校验注解if (fieldVerifyParam == null) { // 如果注解为空则跳过continue;}field.setAccessible(true); // 设置字段可访问Object resultValue = field.get(value); // 获取字段值checkValue(resultValue, fieldVerifyParam); // 执行值校验}} catch (BusinessException e) {logger.error("校验参数失败", e); // 记录异常日志throw e; // 抛出业务异常} catch (Exception e) {logger.error("校验参数失败", e); // 记录异常日志throw new BusinessException(ResponseCodeEnum.CODE_600); // 抛出业务异常}}/*** 值校验* @param value 值* @param verifyParam 校验参数*/private void checkValue(Object value, VerifyParam verifyParam) {Boolean isEmpty = value == null || StringTools.isEmpty(value.toString()); // 判断值是否为空Integer length = value == null ? 0 : 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); // 抛出业务异常}}
}

总结

 去浏览器直接调用这个路径,没有传参数的话,报错

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/24397.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【面试干货】索引的优缺点

【面试干货】索引的优缺点 1、创建索引可以大大提高系统的性能&#xff08;**优点**&#xff09;2、增加索引也有许多不利的方面&#xff08;**缺点**&#xff09; &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 1、创建索引可以大大提高系…

LiDAR360MLS 7.2.0 雷达点云数据处理软件功能介绍

新增模块和功能: 支持手持、背包数据的解算 SLAM解算成功率提升 SLAM解算效率提升 采集端与后处理端保持一致 赋色优化 新增平面图模块 新增平面图全自动矢量化功能 新增平面图矢量一键导出DXF功能 新增平面图正射影像一键导出功能 支持交叉、垂直绘制 支…

添加west扩展命令

使用west工具的帮助命令&#xff0c;west -h&#xff0c;不仅可以列出west工具的内置命令&#xff0c;也可以列举当前工程中实现的扩展命令&#xff0c;如build&#xff0c;flash等。 本文将介绍如何添加扩展命令。 west扩展命令的位置通过以下方式查找&#xff1a; 1. 首先找…

Python 机器学习 基础 之 【实战案例】轮船人员获救预测实战

Python 机器学习 基础 之 【实战案例】轮船人员获救预测实战 目录 Python 机器学习 基础 之 【实战案例】轮船人员获救预测实战 一、简单介绍 二、轮船人员获救预测实战 三、数据处理 1、导入数据 2、对缺失数据的列进行填充 3、属性转换&#xff0c;把某些列的字符串值…

数组中寻找符合条件元素的位置(np.argwhere,nonzero)

今天遇到一个问题&#xff0c;就是寻找符合条件的元素所在的位置&#xff0c;主要使用np.argwhere和nonzero函数 比如给我一个二维数组&#xff0c;我想知道其中元素大于15的位置 方法1 import numpy as np exnp.arange(30) enp.reshape(ex,[3,10]) print(e) print(e>15…

南山代理记账,为您提供专业、高效的服务和全方位的支持

随着商业活动的不断深化和扩展&#xff0c;企业的会计工作越来越重要&#xff0c;而作为一家专业的代理记账公司&#xff0c;“南山代理记账”始终致力于为客户提供专业、高效的服务&#xff0c;帮助他们在经营过程中更好地管理和运用资金。 南山代理记账公司的服务范围广泛&am…

【日记】遇到了一个 “不愿睁眼看世界也没受过社会毒打” 的逆天群友(464 字)

正文 今天坐在柜台玩了一天手机…… 手机都玩没电了快。下午在劝一个群友睁眼看世界&#xff0c;实在劝不动。他真的太逆天了&#xff0c;我不清楚这么高学历的人&#xff0c;怎么能说出这么天真的话。逆天又离谱。 晚上的时间几乎全在做家务。平时晚上都是跳舞来着&#xff0c…

mac安装brew遇到的一些问题

mac终端执行命令/bin/bash -c “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)”&#xff0c;无法建立连接或连接超时错误&#xff0c;错误信息如下&#xff1a; curl: (28) Failed to connect to raw.githubusercontent.com port 443 af…

标准价与移动平均价简介

一、移动平均价 移动平均价优点&#xff1a; a.移动平均价格可反应”实时的”加权平均价格,特别是物料价格涨跌幅度大时物料的价格不会被差异扭曲。 b.因为是基于交易的实时加权平均计算价格,一般情况下,移动平均价不产生差异&#xff0c;价格相对真实。 c.如果所有的物料都使用…

mqtt-emqx:keepAlive机制测试

mqtt keepAlive原理详见【https://www.emqx.com/zh/blog/mqtt-keep-alive】 # 下面开始写测试代码 【pom.xml】 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2…

Ubuntu项目部署

解压jdk tar -zxvf jdk-8u151-linux-x64.tar.gz 配置Java环境变量&#xff1a; vim ~/.bashrc export JAVA_HOME/root/soft/jdk1.8.0_151 export JRE_HOME${JAVA_HOME}/jre export CLASSPATH.:${JAVA_HOME}/lib:${JRE_HOME}/lib export PATH${JAVA_HOME}/bin:$PATH 设置环境变…

武汉理工大学 云计算与服务计算 期末复习

云计算与的定义 长定义是&#xff1a;“云计算是一种商业计算模型。它将计算任务分布在大量计算机构成的资源池上&#xff0c;使各种应用系统能够根据需要获取计算力、存储空间和信息服务。” 短定义是&#xff1a;“云计算是通过网络按需提供可动态伸缩的廉价计算服务。 云计…

Lecture1——对最优化的介绍

一&#xff0c;简介——什么是最优化&#xff1f; 1&#xff0c;三种问题&#xff1a; 用80米的围栏尽可能的围成一个面积最大的矩形如何规划产品的生产&#xff0c;使得公司获得的利润最大给你一个图&#xff08;Graph&#xff09;&#xff0c;如何获得最短的距离 2&#xf…

MATLAB基础应用精讲-【数模应用】主成分(pca)分析(补充篇)(附MATLAB、R语言和python代码实现)

目录 前言 几个高频面试题目 主成分分析(PCA)与独立成分分析(ICA) 1. 技术背景 2. 主成分分析 3. 独立成分分析 算法原理 数据降维 PCA 涉及的主要问题 PCA 的优化目标 主成分分析(PCA)的基本思想 数学模型 协方差和散度矩阵 PCA的推导:基于最小投影距离 ​…

matlab BP神经网络

clear clc % 准备数据 inputs rand(10, 100); % 100组输入&#xff0c;每组10个特征 outputs rand(1, 100); % 100组输出&#xff0c;每组1个输出值 % 将数据分成训练集和测试集 trainRatio 0.8; valRatio 0.1; testRatio 0.1; [trainInd, valInd, testInd] divid…

数据结构笔记2 栈和队列

为什么在循环队列中&#xff0c;判断队满的条件是&#xff08;Q.rear1&#xff09;模maxqsize? 取模运算&#xff08;%&#xff09;在循环队列中起到关键作用&#xff0c;主要是因为它能确保索引值在数组的有效范围内循环。具体来说&#xff0c;取模运算有以下几个重要作用&am…

【Go语言精进之路】构建高效Go程序:了解切片实现原理并高效使用

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 引言一、切片究竟是什么&#xff1f;1.1 基础的创建数组示例1.2 基础的创建切片示例1.3 切片与数组的关系 二、切片的高级特性&#xff1a;动态扩容2.1 使用 append 函数扩容2.2 容量管理与性能考量2.3 切片的截取与缩容 三…

底板外设倒灌到处理器分析

在嵌入式系统中&#xff0c;底板外设通常与处理器通过各种接口&#xff08;如UART、SPI、I2C、GPIO等&#xff09;进行连接。这些外设可能包括传感器、执行器、存储器、通信模块等。倒灌是指当外设向处理器提供的信号电平超出了处理器能够接受的范围&#xff0c;导致处理器无法…

无锡哲讯——机械行业ERP管理系统,引领智能制造新纪元

机械行业作为现代工业的基石&#xff0c;正面临着前所未有的变革。随着智能制造的兴起&#xff0c;ERP管理系统在机械行业中的作用日益凸显。无锡哲讯智能科技有限公司&#xff0c;凭借其在ERP领域的专业实力和丰富经验&#xff0c;为机械行业客户提供定制化的ERP解决方案&…

【Python错误】:AttributeError: ‘generator‘ object has no attribute ‘next‘解决办法

【Python错误】&#xff1a;AttributeError: ‘generator’ object has no attribute next’解决办法 在Python中&#xff0c;生成器是一种使用yield语句的特殊迭代器&#xff0c;它允许你在函数中产生一个值序列&#xff0c;而无需一次性创建并返回整个列表。然而&#xff0c;…