Java | 使用切面AOP拦截并修改Controller接口请求参数

news2024/12/21 15:48:20

关注common wx: CodingTechWork

引言

  在开发过程中,会有一些需求将controller层的一些方法入参进行全量转换,最容易想到的可能是在调用下层service方法时,调用公共的方法进行入参转换,这时带来的唯一问题就是代码不雅观,比较冗余。那还有什么方法可以更优雅的解决这个问题吗?答案是有的:切面。
  我们实现一个AOP切面程序,对入参中的需转换的参数进行专项转换,而无需在各个controller层的各个方法中进行转换处理。

实践

controller类

package com.test.selfcoding.controller;

import com.test.selfcoding.bean.PersonBean;
import com.test.selfcoding.service.HelloWorldService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @Description controller
 * @Author Liao Jy
 * @Date 2023/6/28
 */
@RestController
@RequestMapping("/hello/world")
public class HelloWorldController {

    @Autowired
    private HelloWorldService helloWorldService;

    @GetMapping("/test1")
    public String testGetHelloWorld() {
        return helloWorldService.getHelloWolrd();
    }

    @PostMapping("/test2")
    public String testPostHelloWord(@RequestBody PersonBean personBean) {
        return helloWorldService.postHelloWorld(personBean);
    }

    @GetMapping("/test3")
    public String testPostHelloWord(@RequestParam String personName) {
        return personName + ", hi world!";
    }

}

切面类

package com.test.selfcoding.aspect;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;

/**
 * @Description DefaultArgumentsAspect
 * @Author LiaoJy
 * @Date 2023/6/28
 */

@Component
@Aspect
@Slf4j
public class DefaultArgumentsAspect {
    @Before(value = "execution(* com.test.selfcoding.controller..*(..))")
    public void doBefore(JoinPoint joinPoint) {
        try {
        	//获取入参列表
            Object[] args = joinPoint.getArgs();
            log.info("args: {}", JSON.toJSONString(args));
            //入参判空
            if (null == args || args.length == 0) {
                log.info("no fields!");
                return;
            }
            //获取第一个入参(主要针对@RequestBody,一般只会有一个入参,若遇到多个@RequestParam,需循环处理)
            Object arg = args[0];
            //获取字段域
            Field[] fields = arg.getClass().getDeclaredFields();
            log.info("getDeclaredFields: {}", JSON.toJSONString(fields));
			//判断入参中是否有"name"
            if (Arrays.stream(fields).noneMatch(item -> "name".equals(item.getName()))) {
                log.info("no name field!");
                return;
            }
            //入参中有"name",获取该字段
            Field field = arg.getClass().getDeclaredField("name");
            //判断是否可使用
            boolean accessible = ((!Modifier.isPublic(field.getModifiers())
                    || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
                    || Modifier.isFinal(field.getModifiers())) && !field.isAccessible());
            //若不可用,则需要进行setAccessible
            if (accessible) {
                ServletRequestAttributes attributes
                        = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                // 获取request对象
                HttpServletRequest request = attributes.getRequest();
                log.info("method name: {}", request.getRequestURI());
                field.setAccessible(true);
                //将name参数替换为system
                field.set(arg, "system");
            }
        } catch (Exception e) {
            log.error("切面参数设置异常", e);
        }
    }
}

验证

无参测试接口1

  1. 接口调用
    在这里插入图片描述
  2. 控制台日志
2023-06-28 18:06:06.060  INFO 6495 --- [nio-8001-exec-1] c.t.s.aspect.DefaultArgumentsAspect      : args: []
2023-06-28 18:06:06.061  INFO 6495 --- [nio-8001-exec-1] c.t.s.aspect.DefaultArgumentsAspect      : no fields!
2023-06-28 18:06:06.066  INFO 6495 --- [nio-8001-exec-1] c.t.s.s.impl.HelloWorldServiceImpl       : getHelloWolrd() get str success.
result: hugh, hello world!
  1. 结果分析
    未获取到参数,正常走接口。打印no fields!,无需转换参数。

不包含指定参数测试接口2

  1. 接口调用
    在这里插入图片描述

  2. 控制台日志

2023-06-28 18:08:04.040  INFO 6495 --- [nio-8001-exec-5] c.t.s.aspect.DefaultArgumentsAspect      : args: ["xiaowang"]
2023-06-28 18:08:04.055  INFO 6495 --- [nio-8001-exec-5] c.t.s.aspect.DefaultArgumentsAspect      : getDeclaredFields: [{"accessible":false,"annotatedType":{"annotatedGenericComponentType":{"annotations":[],"declaredAnnotations":[],"type":"char"},"annotations":[],"declaredAnnotations":[],"type":"[C"},"annotations":[],"declaringClass":"java.lang.String","enumConstant":false,"genericType":"[C","modifiers":18,"name":"value","synthetic":false,"type":"[C"},{"accessible":false,"annotatedType":{"annotations":[],"declaredAnnotations":[],"type":"int"},"annotations":[],"declaringClass":"java.lang.String","enumConstant":false,"genericType":"int","modifiers":2,"name":"hash","synthetic":false,"type":"int"},{"accessible":false,"annotatedType":{"annotations":[],"declaredAnnotations":[],"type":"long"},"annotations":[],"declaringClass":"java.lang.String","enumConstant":false,"genericType":"long","modifiers":26,"name":"serialVersionUID","synthetic":false,"type":"long"},{"accessible":false,"annotatedType":{"annotatedGenericComponentType":{"annotations":[],"declaredAnnotations":[],"type":"java.io.ObjectStreamField"},"annotations":[],"declaredAnnotations":[],"type":"[Ljava.io.ObjectStreamField;"},"annotations":[],"declaringClass":"java.lang.String","enumConstant":false,"genericType":"[Ljava.io.ObjectStreamField;","modifiers":26,"name":"serialPersistentFields","synthetic":false,"type":"[Ljava.io.ObjectStreamField;"},{"accessible":false,"annotatedType":{"annotatedActualTypeArguments":[{"annotations":[],"declaredAnnotations":[],"type":"java.lang.String"}],"annotations":[],"declaredAnnotations":[],"type":{"actualTypeArguments":["java.lang.String"],"rawType":"java.util.Comparator","typeName":"java.util.Comparator<java.lang.String>"}},"annotations":[],"declaringClass":"java.lang.String","enumConstant":false,"genericType":{"$ref":"$[4].annotatedType.type"},"modifiers":25,"name":"CASE_INSENSITIVE_ORDER","synthetic":false,"type":"java.util.Comparator"}]
2023-06-28 18:08:04.056  INFO 6495 --- [nio-8001-exec-5] c.t.s.aspect.DefaultArgumentsAspect      : no name field!
  1. 结果分析
    未获取到指定的参数,正常走接口。打印no name field!,无需转换参数。

包含指定参数测试接口3

  1. 接口调用
    在这里插入图片描述

  2. 控制台日志

2023-06-28 18:10:15.481  INFO 6495 --- [nio-8001-exec-9] c.t.s.aspect.DefaultArgumentsAspect      : args: [{"age":1,"name":"xiaohong"}]
2023-06-28 18:10:15.482  INFO 6495 --- [nio-8001-exec-9] c.t.s.aspect.DefaultArgumentsAspect      : getDeclaredFields: [{"accessible":false,"annotatedType":{"annotations":[],"declaredAnnotations":[],"type":"java.lang.String"},"annotations":[],"declaringClass":"com.test.selfcoding.bean.PersonBean","enumConstant":false,"genericType":"java.lang.String","modifiers":2,"name":"name","synthetic":false,"type":"java.lang.String"},{"accessible":false,"annotatedType":{"annotations":[],"declaredAnnotations":[],"type":"int"},"annotations":[],"declaringClass":"com.test.selfcoding.bean.PersonBean","enumConstant":false,"genericType":"int","modifiers":2,"name":"age","synthetic":false,"type":"int"}]
2023-06-28 18:10:15.482  INFO 6495 --- [nio-8001-exec-9] c.t.s.aspect.DefaultArgumentsAspect      : method name: /hello/world/test2
  1. 结果分析
    获取到指定的参数,进行name值替换为system,切面转换参数成功。

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

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

相关文章

TCP的粘包、拆包、解决方案以及Go语言实现

什么是粘包&#xff0c;拆包&#xff1f; TCP的粘包和拆包问题往往出现在基于TCP协议的通讯中&#xff0c;比如RPC框架在使用TCP进行数据传输时&#xff0c;由于TCP是基于字节流的协议&#xff0c;而不是基于消息的协议&#xff0c;可能会出现粘包&#xff08;多个消息粘在一起…

基于matlab创建基于颜色特征的图像检索系统(附源码)

一、前言 此示例说明如何使用自定义的功能包工作流创建基于内容的图像检索 &#xff08;CBIR&#xff09; 系统。 基于内容的图像检索 &#xff08;CBIR&#xff09; 系统用于查找在视觉上与查询图像相似的图像。CBIR系统的应用可以在许多领域找到&#xff0c;例如基于网络的…

记账APP:小哈记账4——记账首页页面的制作(1)

项目介绍&#xff1a; 小哈记账是一款用于记账APP&#xff0c;基于Android Studio开发工具&#xff0c;采用Java语言进行开发&#xff0c;同时使用litepal和阿里云数据库进行数据的增删查改&#xff0c;以图标的形式在App的界面上显示。App可以清晰显示收支情况&#xff0c;并以…

2. MongoDB分片集群架构实战-----MongoDB分片集群和多文档事务详解

分布式技术MongoDB 1. 分片简介2. MongoDB分片集群架构3. 环境搭建3.1 分片集群搭建3.2 使用mtools搭建分片集群 4 使用分片集群5. 分片策略5.1 什么是chunk5.2 分片算法5.3 哈希分片5.4 分片标签5.4 分片键(ShardKey)的选择5.5 分片键(ShardKey)的约束 6. 数据均衡6.1 均衡的方…

【JAVAWEB】JavaScript基础知识

目录 1.认识JavaScript 1.1JavaScript是什么 1.2JavaScript和html,css的关系 1.3JavaScript的组成 2.JavaScript的前置知识 2.1JavaScript的书写形式 行内式 内嵌式 外部式 2.2注释 2.3输入输出 3.JavaScript的语法知识 3.1变量的使用 创建变量 使用变量 3.2动态…

echarts柱状图查找数据

controller层&#xff1a; /*** 查询最近一周每天的行为识别总人数* return*/ApiOperation("查询最近一周每天的行为识别总人数") // RequiresPermissions("zhgd:aialarmdata:selectShu")GetMapping("/selectShu")public List<List> se…

UE5 Motion Warping功能学习

MotionWarping&#xff08;运动扭曲&#xff09;可对角色根运动进行修改&#xff0c;从而让角色根运动动画结束时准确停在某一点&#xff0c;如图&#xff1a; 此外UE5还提供移动步幅、转向的Warping功能&#xff08;防滑步&#xff09;&#xff0c;之前写过一个简单的介绍可…

9.2 IO多路复用select函数

目录 I/O多路复用模型 多路复用的实现方式 select函数 fd_set结构体 I/O多路复用模型 多路复用的实现方式 select函数 int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);poll函数 int poll(struct pollfd *fds, nfds_…

Git 安装 配置初始化

1. Git 下载 1.1 git 官网下载 Git 官网 https://git-scm.com/download/win 根据自己的电脑系统下载对应的版本 1.2 百度网盘下载 百度网盘&#xff1a;https://pan.baidu.com/s/17Thcov7VKfIc_hINcQimrw 提取码&#xff1a;13142. 安装git 2.1 双击安装包 2.2 点击next …

新应用爆发,开启5G的鱼龙之变

鱼龙变化&#xff0c;是中国自古以来就有的吉祥寓意与美好期盼。早在商代出土的玉雕中&#xff0c;就出现了由鱼化为龙的形象。晋代民间的歌谣中&#xff0c;已经有了“东海大鱼化为龙”的说法。在此之后&#xff0c;“鱼跃龙门”成为了考试中第的代名词&#xff0c;也被引申为…

台灯选用什么类型好?分享好用的护眼台灯

建议是选择护眼台灯比较好一点&#xff0c;不管是大人还是孩子使用&#xff0c;都会比普通台灯护眼一些。主要是普通台灯在交流电状态下正常工作的时候&#xff0c;每秒钟会发生闪烁100次左右&#xff0c;这样的频率人眼是看不出来的。但是在台灯下时间一长&#xff0c;极其容易…

sonarqube安装指南

sonarQube安装的指导文章说起来有很多&#xff0c;其他步骤本文不再赘述&#xff0c;可以参考其他文章。 在这里讲一下对JDK版本的事情。 SonarQube Server对系统的JDK、和研发写代码所使用的JDK版本有要求&#xff0c;要求大版本统一&#xff0c;比如大家基本上都在用JDK8&a…

景联文科技高质量教育GPT题库:引领教育行业的技术革命

ChatGPT拉开了大语言题库和生成式AI产业蓬勃发展的序幕。全世界教育科技公司扎堆接入GPT-4&#xff0c;涵盖美国、欧洲、日韩、中东和北非地区等。大语言题库在教育领域中势必将获得更加广阔的应用前景和丰富的应用场景。 杭州景联文科技是AI基础数据行业的头部企业&#xff0c…

实用技巧之拼接

&#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 接下来看看由辉辉所写的关于拼接的相关操作吧 目录 &#x1f973;&#x1f973;Welcome Huihuis Code World ! !&#x1f973;&#x1f973; 一.什么时候会用到拼接 二.使用什么方式进…

React V6实现父子组件双向绑定传值

功能背景 之前在写vue的时候用到一个很好用的东西&#xff0c;比如控制一个dialog的显示隐藏&#xff0c;那么可以由父组件控制它显示&#xff0c;子组件&#xff08;即这个dialog&#xff09;自己可以关闭自己&#xff0c;那么他们之间只维护一个visible的状态&#xff0c;就需…

预约时间列表 带标签 上午下午 今天明天

/*** 时间列表* $interval 间隔X分钟* */ function timeList($day7,$time108:00,$time222:00,$interval60){$date_list [];//日期列表$today_date strtotime(date(Y-m-d,time()));for($i0;$i<$day;$i){$date_title date(Y-m-d,$today_date($i*86400));$buff array();for…

win7下如何开启远程桌面服务?让别人连接的方法

当某台计算机开启了远程桌面连接功能后就可以在网络的另一端控制这台计算机了&#xff0c;通过远程桌面功能可以实时地操作这台计算机&#xff0c;在上面安装软件&#xff0c;运行程序&#xff0c;所有的一切都好像是直接在该计算机上操作一样。这就是远程桌面的最大功能&#…

基于Python所写的图片批量处理器设计

点击以下链接获取源码资源&#xff1a; https://download.csdn.net/download/qq_64505944/87964231 《图片批量处理器》程序使用说明 在PyCharm中运行《图片批量处理器》即可进入如图1所示的系统主界面。在该界面中&#xff0c;通过顶部的菜单栏可以选择所要进行的操作。 图…

2023上半年软考系统分析师科目一整理-06

2023上半年软考系统分析师科目一整理-06 在数据库设计的需求分析、概念结构设计、逻辑结构设计和物理结构设计的四个阶段中&#xff0c;基本E-R图是( D )。 A.需求分析阶段形成的文档&#xff0c;并作为概念结构设计阶段的设计依据 B.逻辑结构设计阶段形成的文档&#xff0c;…

python获取目标主机的MAC地址

下载插件&#xff1a;WinPcap Download 下载后直接安装&#xff08;虽然已停止更新&#xff0c;但还能正常使用&#xff09; python代码&#xff1a;安装 scapy 包 from scapy.all import Ether, ARP, srpdef get_mac_address(ip):# 创建一个ARP请求数据包arp Ether(dst"…