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.rhkb.cn/news/344037.html

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

相关文章

leetcode-04-[24]两两交换链表中的节点[19]删除链表的倒数第N个节点[160]相交链表[142]环形链表II

一、[24]两两交换链表中的节点 重点&#xff1a;暂存节点 class Solution {public ListNode swapPairs(ListNode head) {ListNode dummyHeadnew ListNode(-1);dummyHead.nexthead;ListNode predummyHead;//重点&#xff1a;存节点while(pre.next!null&&pre.next.next…

视频去水印电脑版,视频去水印软件

视频去水印怎么去&#xff0c;一直是视频编辑者们的热门话题。那么&#xff0c;如何去除频水印呢&#xff1f;接下来&#xff0c;我们将为您详细介绍视频去水印方法。 第一种方法&#xff1a; 首先通过浏览器打开 “ 51视频处理官网” 的网站。打开网站后&#xff0c;我们上传…

第一个小爬虫_爬取 股票数据

前言 爬取 雪球网的股票数据 [环境使用]&#xff1a;python 3.12 解释器pycharm 编辑器 【模块使用】&#xff1a;import requests -->数据请求模块 要安装 命令 pip install requestsimport csv -->将数据保存到CSV表格中import pandas -->也可以将数据保…

VS2019 QT无法打开 源 文件 “QTcpSocket“

VS2019 QT无法打开 源 文件 "QTcpSocket" QT5.15.2_msvc2019_64 严重性 代码 说明 项目 文件 行 禁止显示状态 错误(活动) E1696 无法打开 源 文件 "QTcpSocket" auto_pack_line_demo D:\vs_qt_project\auto_pack_line_de…

【启明智显分享】基于工业级芯片Model3A的7寸彩色触摸屏应用于智慧电子桌牌方案

一场大型会议的布置&#xff0c;往往少不了制作安放参会人物的桌牌。制作、打印、裁剪&#xff0c;若有临时参与人员变更&#xff0c;会务方免不了手忙脚乱更新桌牌。由此&#xff0c;智能电子桌牌应运而生&#xff0c;工作人员通过系统操作更新桌牌信息&#xff0c;解决了传统…

地图之战争迷雾/地图算法/自动导航(一)

战争迷雾 TiledMap 创建黑色覆盖块&#xff0c;然后使用碰撞组件&#xff0c;控制黑色块的显示和隐藏 地图算法 在有些游戏中&#xff0c;地图需要随机生成&#xff0c;比如游戏中的迷宫等&#xff0c;这就需要地图生成的算法&#xff1b;在角色扮演类游戏中&#xff0c;角色…

python数据分析-心脏衰竭分析与预测

研究背景 人的心脏有四个瓣膜&#xff0c;主动脉银、二尖、肺动脉和三尖源 不管是那一个膜发生了病变&#xff0c;都会导致心脏内的血流受到影响&#xff0c;这就是通常所说的心脏期膜病&#xff0c;很多是需要通过手术的方式进行改善的。随着人口老龄化的加剧,&#xff0c;心…

限时限量!6.18云服务器大促盘点,错过一次,再等一年!

随着云计算技术的飞速发展&#xff0c;云服务器已成为企业和个人构建和扩展在线业务的首选平台。特别是在大型促销活动如618年中大促期间&#xff0c;云服务提供商纷纷推出极具吸引力的优惠&#xff0c;以降低用户上云的门槛。以下是对当前市场上几个主流云服务提供商的优惠活动…

【设计模式】JAVA Design Patterns——Servant(服务模式)

&#x1f50d;目的 仆人类被用于向一组类提供一些行为&#xff0c;区别于在每个类定义行为-或者当我们无法排除 公共父类中的这种行为&#xff0c;这些行为在仆人类被定义一次 &#x1f50d;解释 真实世界例子 国王、王后和其他宫廷皇室成员需要仆人为他们提供饮食、准备饮料等…

【TB作品】MSP430F5529 单片机,简单电子琴

使用MSP430制作一个简单电子琴 作品功能 这个项目基于MSP430单片机&#xff0c;实现了一个简单的电子琴。通过按键输入&#xff0c;电子琴可以发出对应的音符声音。具体功能包括&#xff1a; 按下按键时发出对应音符的声音。松开按键时停止发声。支持C调低音、中音和高音。 …

算法:226. 翻转二叉树

给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a;root [2,1,3] 输出&#xff1a;[2,3,1]示例 3&#x…

带池化注意力 Strip Pooling | Rethinking Spatial Pooling for Scene Parsing

论文地址:https://arxiv.org/abs/2003.13328 代码地址:https://github.com/houqb/SPNet 空间池化已被证明在捕获像素级预测任务的长距离上下文信息方面非常有效,如场景解析。在本文中,我们超越了通常具有N N规则形状的常规空间池化,重新思考空间池化的构成,引入了一种…

Ruoyi-Vue-Plus 下载启动后菜单无法点击展开,

1.Ruoyi-Vue-Plus框架下载后运行 2.使用mock数据 3.进入页面后无法点击菜单 本以为是动态路由或者菜单逻辑出了问题&#xff0c;最后发现是websocket的问题 解决办法 把这两行代码注释 页面菜单即可点击。 以上。

安徽代理记账公司的专业服务和创新理念

在当今竞争激烈的市场环境中&#xff0c;为了提升企业的运营效率&#xff0c;许多企业开始寻找专业的代理记账公司进行财务管理和记账&#xff0c;本文将介绍一家名为安徽代理记账公司的专业服务和创新理念。 安徽代理记账公司是一家专注于为企业提供全方位会计服务的公司&…

开关电源RCD吸收电路解析与设计

开关电源RCD吸收电路解析与设计 引言 在电源设计中,RCD电路以其出色的能量吸收能力,有效降低电阻损耗,从而被广泛应用。然而,对于新手来说,理解和掌握开关电源中的RCD吸收电路可能是一个挑战。本文旨在深入剖析RCD吸收电路的设计原理和步骤,帮助读者更好地理解和应用这…

如何在快团团上找到优质的供货团长和挑选合适的产品进行推广?

在快团团上找到优质的供货团长和挑选合适的产品进行推广的方法如下&#xff1a; 筛选优质供货团长&#xff1a; 选择专业品类&#xff1a;根据你熟悉的领域和目标客户的需求&#xff0c;选择相应的专业供货团长。查看帮卖口碑标签&#xff1a;通过查看团长的帮卖口碑标签&#…

css3 都有哪些新属性

1. css3 都有哪些新属性 1.1. 圆角边框 (border-radius)1.2. 盒子阴影 (box-shadow)1.3. 文本阴影 (text-shadow)1.4. 响应式设计相关属性1.5. 渐变背景 (gradient backgrounds)1.6. 透明度 (opacity 和 rgba/hsla)1.7. 多列布局 (column-count, column-gap, etc.)1.8. 变换 (t…

常见八大排序(纯C语言版)

目录 基本排序 一.冒泡排序 二.选择排序 三.插入排序 进阶排序&#xff08;递归实现&#xff09; 一.快排hoare排序 1.单趟排序 快排步凑 快排的优化 &#xff08;1&#xff09;三数取中 &#xff08;2&#xff09;小区间优化 二.前后指针法(递归实现) 三.快排的非…

SpringCloud整合OpenFeign实现微服务间的通信

1. 前言 1.1 为什么要使用OpenFeign&#xff1f; 虽说RestTemplate 对HTTP封装后, 已经⽐直接使⽤HTTPClient简单⽅便很多, 但是还存在⼀些问题. 需要拼接URL, 灵活性⾼, 但是封装臃肿, URL复杂时, 容易出错. 代码可读性差, ⻛格不统⼀。 1.2 介绍一下微服务之间的通信方式 微…

使用 ESPCN 模型进行超分辨率图像处理

前言 使用 ESPCN (Efficient Sub-Pixel CNN) 模型对低分辨率的图像&#xff0c;进行超分辨率处理。 效果展示 lowres 表示低分辨率图像&#xff0c;highres 表示高分辨率图像&#xff0c;prediction 表示模型预测的高分辨率图像&#xff0c;可以看出模型在生成高分辨率图像过…