使用AOP处理参数

news2024/9/30 20:30:54

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

场景

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

@RestController
@RequestMapping("user")
public class UserController {

    @Autowired
    private 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 {

    @Autowired
    private 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
    @DeleteMapping
    public 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;

    @FieldAnnotation
    private String username;

    private String password;
}

只传个username

在这里插入图片描述

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

在这里插入图片描述

总结

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

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

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

  • AOP技术

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

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

相关文章

vscode 内网不联网如何导入vscode插件

如果有小伙伴百度到这篇文章&#xff0c;那一定是遇到了在内网开发不能联网的问题&#xff0c;那就往下看看吧。 安装一个新的Visual Studio Code&#xff0c;需要必要的一些插件&#xff0c;但是不能联网&#xff0c;于是自带的扩展程序安装便不能用了。 1、在一台能访问外网…

Kali Linux入门教程(非常详细)从零基础入门到精通,看完这一篇就够了。

作为一名从事渗透测试的人员&#xff0c;不懂Kali Linux的话&#xff0c;就out了。它预装了数百种享誉盛名的渗透工具&#xff0c;使你可以更轻松地测试、破解以及进行与数字取证相关的任何其他工作。 今天给大家分享一套Kali Linux资料合集&#xff0c;包括12份Kali Linux渗透…

数据结构-栈(理解版)

一、栈的定义 相信大家对于栈或多或少有一些了解&#xff0c;可能大多数人会告诉你栈是一种先进后出的数据结构。这其实说了跟没说一样(❁◡❁)&#xff01;当然&#xff08;last in&#xff0c;first out&#xff09;是栈最有特色的性质。 这里可以给大家一些比较好理解的例…

车辆重识别(改进的去噪扩散概率模型)论文阅读2024/9/29

所谓改进的去噪扩散概率模型主要改进在哪些方面&#xff1a; ①对数似然值的改进 通过对噪声的那个方差和T进行调参&#xff0c;来实现改进。 ②学习 这个参数也就是后验概率的方差。通过数据分析&#xff0c;发现在T非常大的情况下对样本质量几乎没有影响&#xff0c;也就是说…

Python库matplotlib之四

Python库matplotlib之四 小部件(widget)RadioButtons构造器APIs应用实列 Slider构造器APIs应用实列 小部件(widget) 小部件(widget)可与任何GUI后端一起工作。所有这些小部件都要求预定义一个Axes实例&#xff0c;并将其作为第一个参数传递。 Matplotlib不会试图布局这些小部件…

基于Springboot+Vue的c语言学习辅导网站的设计与实现 (含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统中…

美洽客户服务AI Agent 1.0,全渠道多场景赋能业务增长

“到 2025 年&#xff0c;由 AI 驱动的客户服务交互将增长 400%。” ——Gartner “70% 的企业报告称&#xff0c;在实施 AI 驱动的客户服务平台后&#xff0c;客户满意度分值提升。” ——麦肯锡 在美洽 AI 中心负责人看来&#xff0c;未来几年&#xff0c;AI 之于企业将由辅助…

国内ChatGPT镜像网站整理汇总【OpenAI o1/GPT 4o】-2024/10月最新

一、中文镜像站 ①yixiaai.com 支持GPT4、4o以及o1&#xff0c;支持MJ绘画、文件上传 ②chat.lify.vip 支持通用全模型&#xff0c;支持文件读取、插件、绘画、AIPPT ③AI Chat 支持GPT3.5/4&#xff0c;4o以及MJ绘画 1. 什么是镜像站 镜像站&#xff08;mirrored site&am…

解决$‘r‘ command not found或者文件夹显示’tvsf 33‘$‘r‘

问题现象: 某客户反馈在执行脚本的时候文件夹显示存在问题,如下图: 但是脚本文件中的内容并没有\r字符,如下图: 也有客户反馈如下: 问题分析: $\r’是回车符的转义表示。在Unix和Linux系统中,回车符是一个不可见的控制字符,它通常用于文本文件中的行结尾。以上…

多线程——进程与线程(详解)

前言 在前一篇文章末尾我简单介绍了操作系统&#xff0c;在操作系统中有一个核心的概念就是进程&#xff0c;然而从本篇文章起&#xff0c;就要开始JAVA语言多线程的讲解了&#xff0c;所以在此之前&#xff0c;本篇文章作为多线程的前序铺垫&#xff0c;一是介绍进程与线程的…

SV830C产品介绍

SV830C产品介绍 SV830C是一款由珠海亿智科技有限公司&#xff08;Zhuhai Eeasy Technology Co., Ltd.&#xff0c;品牌名为EEASYTECH&#xff09;倾力打造的专业AI系统级芯片&#xff08;SoC&#xff09;&#xff0c;专为视频编码产品而设计。这款芯片不仅集成了先进的神经网络…

湖州市自闭症寄宿学校:个性化关爱让每个孩子都能茁壮成长

在探索自闭症儿童教育的广阔领域中&#xff0c;湖州市的自闭症寄宿学校以其个性化的教育模式&#xff0c;为众多家庭点亮了希望之光。然而&#xff0c;当我们把视线转向中国南方的一座现代化大都市——广州&#xff0c;会发现另一所同样在自闭症儿童教育领域深耕细作、成果斐然…

满填充透明背景二维码生成

前几天项目上线的时候发现一个问题&#xff1a;通过Hutool工具包生成的二维码在内容较少时无法填满(Margin 已设置为 0)给定大小的图片。因此导致前端在显示二维码时样式异常。 从图片中我们可以看到&#xff0c;相同大小的图片&#xff0c;留白内容是不一样的。其中上半部分…

RuoYi-Vue实现后台管理系统去掉首页/默认跳转动态路由第一个路由

云风网 云风笔记 云风知识库 RuoYi-Vue 是一个 Java EE 企业级快速开发平台&#xff0c;基于SpringBoot、Spring Security、Jwt、Vue的前后端分离的后台管理系统 内置模块如&#xff1a;部门管理、角色用户、菜单及按钮授权、数据权限、系统参数、日志管理、代码生成等。在线定…

【代码实现】opencv 高斯模糊和pytorch 高斯模糊

wiki百科 Gaussian Blur&#xff0c;也叫高斯平滑&#xff0c;是在Adobe Photoshop、GIMP以及Paint.NET等图像处理软件中广泛使用的处理效果&#xff0c;通常用它来减少图像噪声以及降低细节层次。 opencv实现 opencv实现高斯滤波有两种方式&#xff0c; 1、是使用自带的cv2…

怎样把两个视频合并成一个视频?批量合并视频看好这6个工具!

★ 怎样把两个视频合并成一个视频&#xff1f; 随着视频内容的日益丰富&#xff0c;我们常常需要将多个视频片段合并成一个完整的视频文件&#xff0c;不管将2个视频合并拼接到一个进行播放&#xff0c;还是直接合并2个短视频变成长视频&#xff0c;都可以通过这6个工具进行处…

个人项目简单https服务配置

1.SSL简介 SSL证书是一种数字证书&#xff0c;由受信任的证书颁发机构&#xff08;CA&#xff09;颁发&#xff0c;用于在互联网通信中建立加密链接。SSL代表“安全套接层”&#xff0c;是用于在互联网上创建加密链接的协议。SSL证书的主要目的是确保数据传输的安全性和隐私性…

PWA(Progressive web APPs,渐进式 Web 应用): manifest.json、 Service Worker

文章目录 引言I 什么是 PWA功能特性技术上分为三个部分安装应用II Web 应用清单将Web 应用清单文件链接到站点manifest.json字段说明III Service Worker( 缓存管理)IV 结合构建工具让项目支持 PWA应用使用插件vite-plugin-pwaworkbox-webpack-plugin插件扩展知识将 PWA 作为脱机…

dwceqos网络驱动性能优化

文章介绍 本文会介绍优化QNX系统下io-pkt-v6-hc驱动模块cpu loading过高问题&#xff0c;经过优化可以降低约一半的cpu loading. 问题背景 激光雷达通过以太网发送数据到ADAS域控中&#xff0c;测试发现在激光功能激活的情况下&#xff0c;会出现比较明显的网络丢帧现象。 …

HT8731 内置自适应H类升压和防破音功能的10W D类及AB类音频功率放大器

1、特点 防削顶失真功能(防破音,Anti-Clipping Function, ACF) 免滤波器数字调制&#xff0c;直接驱动扬声器 输出功率 10W(VBAT4.2V,RL3Ω,THDN10%, fiN 1kHz) 6W(VBAT3.3~4.2V,RL4Ω,THDN<1%,20-20kHz 全频段) 3W (VBAT3.3~4.2V,RL8Ω, THDN<1%, 20- 20kHz 全频段 VB…