使用AOP处理参数

说明:在一些时候,我们需要在接口介绍到参数前处理参数,像参数校验、参数转换等,本文介绍如何使用AOP来实现此需求。

场景

需求:有一批开放给第三方调用的接口,之前传递的都是用户表的ID,现在需要换成用户表的用户名。如下:

@RestController
@RequestMapping("user")
public class UserController {@Autowiredprivate UserMapper userMapper;@GetMapping("{id}")public User getUser(@PathVariable String id) {return userMapper.selectUserById(id);}
}

在这里插入图片描述

一般思维,我们可以在响应的接口前,调用一个方法,根据传递的用户名去查询用户表,返回用户ID。这样,所有需要修改的地方,都需要加上这个方法,代码侵入大,不易维护,不优雅。

使用AOP

使用AOP,我们可以考虑在相应的接口上,打上一个自定义注解,表示改接口需要进行处理,然后在对应的参数上,再打上一个注解,表示需要对该参数进行处理,

首先,创建三个注解,如下:

(接口注解,打在接口上,表示需要处理的接口)

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InterfaceAnnotation {
}

(参数注解,打在参数上,表示需要处理的参数)

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface ParamAnnotation {
}

(字段注解,如果参数是对象,打在对象的属性上,表示取出该对象的这个属性处理)

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldAnnotation {
}

重点是切面,切面要做的是取出对应的参数值,进行转换,然后再赋值回去,需要考虑参数是单个字段、对象这两种情况,如下:

import com.hezy.annotation.FieldAnnotation;
import com.hezy.annotation.ParamAnnotation;
import com.hezy.mapper.UserMapper;
import com.hezy.pojo.UserDTO;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;@Aspect
@Component
public class UsernameToIdAspect {@Autowiredprivate UserMapper userMapper;@Around("@annotation(com.hezy.annotation.InterfaceAnnotation)")public Object resolveUsernameToId(ProceedingJoinPoint joinPoint) throws Throwable {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();// 获取方法参数列表Object[] args = joinPoint.getArgs();// 获取方法参数的注解,这里是二位数组,是因为一个参数可以有多个注解Annotation[][] parameterAnnotations = method.getParameterAnnotations();// 遍历每个注解for (int i = 0; i < parameterAnnotations.length; i++) {// 遍历注解,判断是否有ParamAnnotation注解for (Annotation annotation : parameterAnnotations[i]) {// 如果有ParamAnnotation注解if (annotation instanceof ParamAnnotation) {// 获取该对象的属性值String username = (String) args[i];// 将根据username查询后的accountId赋值给这个参数args[i] = getUserIdByUsername(username);}}// 参数如果是对象if (args[i] instanceof UserDTO) {// 获取对象的所有属性,并遍历Field[] declaredFields = args[i].getClass().getDeclaredFields();for (Field field : declaredFields) {// 如果有 FieldAnnotation 注解if (field.getAnnotation(FieldAnnotation.class) != null) {// 设置属性为可访问的field.setAccessible(true);// 获取该对象的属性值String username = (String) field.get(args[i]);// 将根据username查询后的accountId赋值给该对象的id字段Field accountId = args[i].getClass().getDeclaredField("id");accountId.setAccessible(true);accountId.set(args[i], getUserIdByUsername(username));}}}}return joinPoint.proceed(args);}/*** 根据username去查userId*/private String getUserIdByUsername(String username) {String userId = userMapper.selectIdByUsername(username);if (userId == null) {throw new RuntimeException("操作失败,该账户不存在");}return userId;}
}

测试

根据username查id

    @Select("select id from i_users where username = #{username}")String selectIdByUsername(@Param("username") String username);

启动项目,传username,可以看到,也能查出数据,说明转换成功了。完全不用去修改原来的代码。

在这里插入图片描述

再试下传入一个对象,将对象里面的username字段取出来,然后查出id,赋值给原对象。这样就不影响原来逻辑了。

    @InterfaceAnnotation@DeleteMappingpublic void deleteUserByUsername(@RequestBody UserDTO userDTO) {userMapper.deleteUserByUsername(userDTO);}

别忘了要在对象属性上打注解

import com.hezy.annotation.FieldAnnotation;
import lombok.Data;import java.io.Serializable;@Data
public class UserDTO implements Serializable {private String id;@FieldAnnotationprivate String username;private String password;
}

只传个username

在这里插入图片描述

断点打在获取参数后,可以看到id已经补上了,说明切面起作用了。

在这里插入图片描述

总结

本文介绍了AOP的一个使用场景,另外使用AOP还可以解决很多问题,像记录接口访问日志、接口鉴权、补全用户信息(类似上面的)。

完整源码:https://github.com/HeZhongYing/aop_use_demo

AOP技术介绍,参考下面这边博客:

  • AOP技术

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

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

相关文章

“改善就医感受 提升患者体验”经验交流首场活动在呼市顺利举行

2024年9月26日至27日&#xff0c;以“医疗机构高质量发展 促进医改全面深化”为主题的“改善就医感受 提升患者体验”经验交流系列活动&#xff08;以下简称&#xff1a;系列活动&#xff09;首场活动在内蒙古呼和浩特顺利举行。 活动现场 患者体验&#xff0c;并不等同于患者…

CleanMyMac X v4.12.1 中文破解版 Mac优化清理工具

在数字时代&#xff0c;我们的Mac设备承载着越来越多的重要信息和日常任务。然而&#xff0c;随着时间的推移&#xff0c;这些设备可能会变得缓慢、混乱&#xff0c;甚至充满不必要的文件。这就是CleanMyMac X发挥作用的地方。 CleanMyMac X是一款功能强大的Mac优化工具&#…

获取 Jupyter Notebook IPython kernel 在电脑中的目录位置

获取 Jupyter Notebook IPython kernel 在电脑中的目录位置 正文 正文 在 VS code 的 terminal 中或者 Windows 的命令行中使用如下代码即可。 ipython locate运行后得到如下结果&#xff1a; 如图所示&#xff0c;我们获取到了 ipython 的位置。 如果大家觉得有用&#xf…

自动驾驶汽车横向控制方法研究综述

【摘要】 为实现精确、稳定的横向控制&#xff0c;提高车辆自主行驶的安全性和保障乘坐舒适性&#xff0c;综述了近年来自动驾驶汽车横向控制方法的最新进展&#xff0c;包括经典控制方法和基于深度学习的方法&#xff0c;讨论了各类方法的性能特点及在应用中的优缺点&#xff…

现实的谷歌SEO服务商是怎样的?

许多客户在咨询SEO服务时&#xff0c;常常会问到如何在短时间内将某个关键词推上谷歌首页&#xff0c;甚至是第一名。对于这种问题&#xff0c;专业的SEO服务商通常无言以对。SEO的基础是网站本身&#xff0c;而并非凭空捏造或者一夜之间就能实现效果的 SEO需要从网站的基本情况…

CNES实时轨道、钟差,硬件延迟精度评估

CNES实时产品评估以COD事后产品作为参考&#xff0c;采用cnt文件产品&#xff0c;目前最精确的轨道是GPS&#xff0c;但由于伽利略最稳定的原子钟弥补了伽利略轨道上的系统误差&#xff0c;Galileo的轨道钟差SISRE低于GPS,Galileo和GPS的SISRE分别为1.6cm和2.3cm&#xff0c;GL…

【HTML5】html5开篇基础(2)

1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ 亲爱的朋友们&#x1f44b;&#x1f44b;&#xff0c;这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章&#xff0c;请别吝啬你的点赞❤️❤️和收藏&#x1f4d6;&#x1f4d6;。如果你对我的…

《深度学习》OpenCV 指纹验证、识别

目录 一、指纹验证 1、什么是指纹验证 2、步骤 1&#xff09;图像采集 2&#xff09;图像预处理 3&#xff09;特征提取 4&#xff09;特征匹配 5&#xff09;相似度比较 6&#xff09;结果输出 二、案例实现 1、完整代码 2、实现结果 调试模式&#xff1a; 三、…

基于Hadoop的微博舆情监测分析系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

传统操作系统和分布式操作系统的区别

分布式操作系统和传统操作系统之间的区别&#xff0c;根植于它们各自的设计哲学和目标。要理解这些差异&#xff0c;需要从操作系统的基本定义、结构、功能以及它们在不同计算环境中的表现进行分析。每种系统都试图解决特定的计算挑战&#xff0c;因此在不同的使用场景下具有各…

【MySQL】视图、用户和权限管理

目录 视图创建视图数据修改影响删除视图视图优点 用户和权限管理查看当前的数据库拥有用户信息创建用户修改密码删除用户权限授权回收权限 视图 视图就是相当于创建一个表&#xff0c;将查询到的结果集给存储起来。像使用复杂的多表查询查询到的结果集就不可以对结果集操作。而…

揭秘网络钓鱼:如何识破并防范这场数字时代的诈骗游戏

网络钓鱼是一种网络攻击&#xff0c;它利用伪装的电子邮件欺骗收件人提供信息、下载恶意软件或采取其他期望的行动。 网络钓鱼是网络害虫&#xff0c;自20世纪90年代初从暗网出现以来&#xff0c;至今仍危害全球。根据SlashNext的报告&#xff0c;2023年平均每天有31,000次网络…

头戴式耳机性价比排名怎样?头戴式耳机性价比之王推荐!

在音频设备日益普及的今天&#xff0c;头戴式耳机因其出色的音质和舒适的佩戴体验&#xff0c;成为了许多音乐爱好者和游戏玩家的首选。然而&#xff0c;很多人比较关心的是头戴式耳机性价比排名怎样&#xff1f;依据这一排名来进行选购&#xff0c;今天就给大家带来头戴式耳机…

使用TiDB企业版Lightning导入ORC文件到TiDB

作者&#xff1a; 数据源的TiDB学习之路 原文来源&#xff1a; https://tidb.net/blog/818f84f0 TiDB Lightning 是用于从静态文件导入 TB 级数据到 TiDB 集群的工具&#xff0c;常用于 TiDB 集群的初始化数据导入。在开源社区版本中&#xff0c;TiDB Lightning 支持以下文件…

python并发编程实战

python并发编程有三种 多线程Thread多进程Process多协程Coroutine cpu密集型计算 cpu密集型也叫计算密集型&#xff0c;是指I/O在很短的时间就可以完成&#xff0c;cpu需要大量的计算处理&#xff0c;特点是cpu占用率相当高 例如&#xff1a;压缩解压缩、加密解密、正则表达…

你知道吗?这四种关机重启情况,有更好解决办法

一、太长不看&#xff1a; 给4G模组VBAT断电关机&#xff0c;模组关机前未能及时退出当前基站&#xff0c;会有什么影响呢&#xff1f; 基站会误以为设备还在线&#xff0c;下次开机仍会拿着上次驻网信息去连基站。基站一看&#xff0c;上次链接还在——认为你是非法设备&…

天线工作原理:【图文讲解】

在信息传输过程中&#xff0c;我们习惯了PCB线路&#xff0c;线揽等&#xff0c;这些有线连接传输方式&#xff0c;而天线这个无线的传输方式相对不是那么好理解。但它确实在实际应用中&#xff0c;占据了很重要的位置。你有多久没有用有线电话了&#xff1f;&#xff08;20年前…

gateway--网关

在微服务架构中&#xff0c;Gateway&#xff08;网关&#xff09;是一个至关重要的组件&#xff0c;它扮演着多种关键角色&#xff0c;包括路由、负载均衡、安全控制、监控和日志记录等。 Gateway网关的作用 统一访问入口&#xff1a; Gateway作为微服务的统一入口&#xff0c…

MySQL - 运维篇

一、日志 1. 错误日志 2. 二进制日志 3. 查询日志 记录了所有的增删改查语句以及DDL语句 4. 慢查询日志 二、主从复制 1. 概述 2. 原理 3. 搭建 三、分库分表 1. 介绍 2. Mycat概述 3. Mycat入门 4. Mycat配置 5. Mycat分片 6. Mycat管理及监控 四、读写分离 1. 介绍 2. 一…

B3621 枚举元组

1.递归的具体过程&#xff0c;一个dfs1&#xff0c;产生3个dfs2&#xff0c;一个dfs2产生3个dfs3&#xff0c;一共输出9个&#xff08;用n2&#xff0c;k3举例&#xff09; 2.要记得使用return 结束当前递归 #include<bits/stdc.h> using namespace std; int n, k, a[10…