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,一经查实,立即删除!

相关文章

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 运输时间(200分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 📎在线评测链接 运输时间(200分) 🌍 评测功能需要订阅专栏后私信联系清隆解…

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

【面试干货】索引的优缺点 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. 首先找…

kafka消息积压处理方案

背景&#xff1a; 某值班的一天&#xff0c;生产出现消息积压问题&#xff0c;对此类的问题做出快速应对方案来避免同类型问题&#xff0c;防止影响范围进一步的扩大。 出现消费积压后如何处理&#xff1a; 首先优先处理消息积压&#xff0c;如果代码逻辑问题&#xff0c;立…

【第12章】SpringBoot实战篇之文件上传(含阿里云OSS上传)

文章目录 前言一、本地文件上传二、阿里云OSS上传1. 环境准备2.安装SDK3.使用长期访问凭证3.1 获取RAM用户的访问密钥3.2 配置RAM用户的访问密钥(Linux)3.3 从环境变量中获取RAM用户的访问密钥 4. 工具类5.使用 总结 前言 本章节介绍本地文件上传和阿里云OSS上传。 一、本地文…

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

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

LSTM-Adaboost基于双向长短期记忆网络结合集成学习实现股价预测附matlab代码

% 股价预测 - LSTM-Adaboost集成学习 % 加载股价数据 load(‘stock_data.mat’); % 假设数据已经存储在stock_data.mat文件中 prices stock_data.prices; % 假设股价数据存储在名为prices的变量中 % 数据预处理 normalized_prices (prices - mean(prices)) / std(prices); …

数组中寻找符合条件元素的位置(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.如果所有的物料都使用…

module ‘django_cas_ng.views‘ has no attribute ‘login‘

这个错误表明你正在尝试从django_cas_ng.views模块中访问一个名为login的属性&#xff0c;但是这个模块中并没有名为login的属性或方法。 解决这个问题&#xff0c;你需要确认你的代码中是否有错误的引用。django_cas_ng是一个CAS&#xff08;Central Authentication Service&…

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 设置环境变…

Python中的面向对象编程(OOP):概念、实践与优势

Python中的面向对象编程(OOP):概念、实践与优势 面向对象编程(Object-Oriented Programming,简称OOP)是一种程序设计模型,它将对象作为程序的基本单元,以提高代码的可重用性、灵活性和扩展性。Python作为一种高级编程语言,对OOP提供了强大的支持。本文将详细阐述Pyth…

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

云计算与的定义 长定义是&#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的推导:基于最小投影距离 ​…