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

相关文章

JavaSE总结

1. Java环境基础 JVM, JRE 和 JDK JVM&#xff08;Java Virtual Machine&#xff09;: 是 Java 虚拟机&#xff0c;负责执行 Java 字节码。JVM 提供了平台无关性&#xff0c;使得 Java 程序可以在不同操作系统上运行。JRE&#xff08;Java Runtime Environment&#xff09;: …

浅谈C++ 多线程锁处理

一、基本介绍 在C中&#xff0c;多线程编程同样需要处理线程安全问题&#xff0c;C11及更高版本提供了一套标准库来支持多线程编程&#xff0c;包括锁的处理。 二、常见锁处理方式 互斥锁&#xff08;std::mutex&#xff09;&#xff1a; std::mutex是最基本的锁类型&#xf…

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

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

网站架构部署——LAMP、LNMP

文章目录 网站架构部署——LAMP、LNMPLAMP安装顺序编译安装Apache httpd服务编译安装mysqld 服务编译安装PHP 解析环境安装论坛安装博客 LNMPyum集中式安装LNMPyum分布式安装LNMP20.0.0.50安装nginx20.0.0.51安装mysql20.0.0.52安装php20.0.0.50配置 nginx 支持 PHP 解析测试my…

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…

使用transformers调用owlv2实现开放目标检测

目录 安装Demo 安装 pip install transformersDemo from PIL import Image, ImageDraw, ImageFont import numpy as np import torch from transformers import AutoProcessor, Owlv2ForObjectDetection from transformers.utils.constants import OPENAI_CLIP_MEAN, OPENAI_…

PTA L1-079 天梯赛的善良

L1-079 天梯赛的善良&#xff08;20分&#xff09; 天梯赛是个善良的比赛。善良的命题组希望将题目难度控制在一个范围内&#xff0c;使得每个参赛的学生都有能做出来的题目&#xff0c;并且最厉害的学生也要非常努力才有可能得到高分。 于是命题组首先将编程能力划分成了 10…

Python日常搜索_random

random.random() 返回随机生成的一个实数&#xff0c;它在[0,1)范围内random.uniform random.uniform(a, b)&#xff0c;用于生成一个指定范围内的随机符点数&#xff0c;两个参数其中一个是上限&#xff0c;一个是下限。如果a > b&#xff0c;则生成的随机数n: b < n &l…

现实的谷歌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;…

Python并发之道:解锁`concurrent.futures`模块的秘密

引言 concurrent.futures模块是Python标准库的一部分&#xff0c;它提供了高层次的接口来执行异步操作。与传统的多线程或多进程编程相比&#xff0c;使用concurrent.futures可以更加简单、高效地管理并行任务。无论是对于初学者还是有经验的开发者来说&#xff0c;掌握这个模…

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

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

C++的6种构造函数

在 C 中&#xff0c;构造函数是一种特殊的成员函数&#xff0c;用于初始化类对象。在对象创建时自动调用&#xff0c;构造函数的主要作用是分配资源、初始化数据成员等。根据不同的功能和使用场景&#xff0c;C 提供了多种类型的构造函数&#xff1a; 1. 默认构造函数 (Defaul…

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

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

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

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