Spring Boo项目中方法参数对象中字段上存在的自定义注解如何进行拦截解析

一、前言

在Spring Boot项目开发过程中,我们经常会使用到自定义注解的方式进行业务逻辑开发,此时注解我们一般是放在方法或者类上面,通过AOP切面拦截的方式进行自定义业务逻辑填充。但是如果自定义注解放在类的字段上,此时应该如何进行解析呢?

二、技术思路

自定义注解放在类的字段上其实解析起来也是比较容易的,我这里采用的思路是:

自定义一个MethodInterceptor拦截器拦截执行的业务方法,获取到方法参数数组,遍历每个参数,获取每个参数中所有字段,判断字段上是否有自定义注解,筛选出所有标识了自定义注解的字段,然后进行自定义业务逻辑填充。

三、技术实践

按照上面的思路,我们进行一下技术实践,这里我模拟一个案例。

1. 需求

自定义一个注解,该注解作用于类的字段上,带有该标识注解的字段,在使用时,如果字段没有设置值,则采用注解设置的默认值。

2. 新建spring boot项目,导入相关依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

3. 自定义注解

示例代码如下:

import java.lang.annotation.*;@Target({ElementType.FIELD}) // 标识此注解适用于字段上
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DefaultValueAnnotation {String value() default "";
}

4. 字段注解获取工具类

示例代码:

import lombok.Data;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.ReflectionUtils;import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;/*** 字段上注解查找工具类*/
public class FieldAnnotationUtils {/*** 字段注解信息返回VO*/@Datapublic static class FieldAnnotationInfo {/*** 类变量*/private Object obj;/*** 携带该注解的字段对象*/private Field field;/*** 注解对象*/private Annotation annotation;}/*** 判断类变量中是否字段上存在指定的注解,如果存在,则返回字段和注解信息** @param obj            类变量* @param annotationType 注解类型* @return*/public static List<FieldAnnotationInfo> parseFieldAnnotationInfo(Object obj, Class annotationType) {return parseFieldAnnotationInfo(obj, annotationType, null);}/*** 判断类变量中是否字段上存在指定的注解,如果存在,则返回字段和注解信息** @param obj              类变量* @param annotationType   注解类型* @param filterFieldClazz 注解适用的字段类型(不适用的字段类型即使字段上面添加改注解也不生效)* @return*/public static List<FieldAnnotationInfo> parseFieldAnnotationInfo(Object obj, Class annotationType, Set<Class> filterFieldClazz) {if (obj == null) {return null;}List<FieldAnnotationInfo> resultList = new ArrayList<>();/*** 获取该对象的所有字段,进行遍历判断*/ReflectionUtils.doWithFields(obj.getClass(), field -> {// 判断该字段上是否存在注解Annotation annotation = AnnotatedElementUtils.findMergedAnnotation(field, annotationType);if (annotation != null) { // 如果存在指定注解boolean flag = true;if (filterFieldClazz != null && !filterFieldClazz.isEmpty()) { // 如果指定了适用的字段的类型for (Class c : filterFieldClazz) {if (c.isAssignableFrom(field.getType())) { // 判断该字段类型是否符合使用类型,使用isAssignableFrom方法是为了父类也进行判断break;}flag = false;}}if (flag) { // 如果该字段类型符合,则返回字段注解信息FieldAnnotationInfo fieldAnnotationInfo = new FieldAnnotationInfo();fieldAnnotationInfo.setObj(obj);fieldAnnotationInfo.setField(field);fieldAnnotationInfo.setAnnotation(annotation);resultList.add(fieldAnnotationInfo);}}});return resultList;}
}

5. 自定义MethodInterceptor

示例代码:

public class MyMethodInterceptor implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {// 获取执行方法的所有参数Object[] arguments = invocation.getArguments();// 参数列表不为空if (arguments != null && arguments.length != 0) {// 由于我这里注解定义简单,我只让String类型的字段生效Set<Class> clazzSet = new HashSet<>();clazzSet.add(CharSequence.class);for (int i = 0; i < arguments.length; i++) { // 判断所有参数// 从每个参数中获取字段上有@DefaultValueAnnotation注解标识,并且类型是CharSequence的字段信息List<FieldAnnotationUtils.FieldAnnotationInfo> fieldAnnotationInfos = FieldAnnotationUtils.parseFieldAnnotationInfo(arguments[i], DefaultValueAnnotation.class, clazzSet);if (!CollectionUtils.isEmpty(fieldAnnotationInfos)) { // 如果存在符合条件的字段信息for (int m = 0; m < fieldAnnotationInfos.size(); m++) { // 判断所有符合条件的字段FieldAnnotationUtils.FieldAnnotationInfo fni = fieldAnnotationInfos.get(m);Field field = fni.getField(); // 获取字段field.setAccessible(true); // 设置可访问,突破private权限Object value = field.get(fni.getObj());if (value == null) { // 判断当前字段是否已经有值// 如果当前字段没有值,利用反射的方式,把注解中的值设置进去field.set(fni.getObj(), ((DefaultValueAnnotation) fni.getAnnotation()).value());}field.setAccessible(false);}}}}// 放行方法执行return invocation.proceed();}
}

6. 把自定义的MethodInterceptor织入到Spring容器中

示例代码:

import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MyInterceptorConfig {@Beanpublic DefaultPointcutAdvisor DefaultPointcutAdvisor() {DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();defaultPointcutAdvisor.setAdvice(new MyMethodInterceptor()); // 自定义MethodInterceptorAspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut();aspectJExpressionPointcut.setExpression("execution(* com.learn..*(..))"); // 指定需要拦截的切面defaultPointcutAdvisor.setPointcut(aspectJExpressionPointcut);return defaultPointcutAdvisor;}}

7. 使用自定义注解

示例代码:

import lombok.Data;@Data
public class TestParamPojo {@DefaultValueAnnotation("我是注解设置的值.")private String name;@DefaultValueAnnotation("100")private Integer age;
}

8. 定义方法入参

示例代码:

@Component
public class TestService {public void test() {System.out.println("test empty...");}public void test(TestParamPojo pojo) {System.out.println("test pojo: " + pojo.toString());}public void test(TestParamPojo pojo, String testStr) {System.out.println("test pojo: " + pojo.toString() + " testStr: " + testStr);}}

9.测试

  • 测试代码:

        @Autowiredprivate TestService testService;@PostConstructpublic void init() {System.out.println("=========================");testService.test();TestParamPojo testParamPojo = new TestParamPojo();testService.test(testParamPojo);testService.test(testParamPojo, null);testParamPojo.setName("我是自己设置的...");testService.test(testParamPojo, "hello, world.");System.out.println("=========================");}
    
  • 测试结果:

    在这里插入图片描述

  • 测试结论

    可以看到,在没有设置值的时候,可以从注解中获取默认值进行设置,同时,不是指定的字段类型即使标识了自定义注解也不会生效。

四、写在最后

本文是对Spring Boo项目中方法参数对象中字段上存在的注解如何进行拦截解析的技术探讨,以上只是技术思路的一种实现方式,仅供大家参考。

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

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

相关文章

XXE 漏洞简单研究

近期在做个基础的 web 常见漏洞的 ppt&#xff0c;主要参考 OWASP TOP 10 2017RC2&#xff0c;此版本中增加了 XXE 攻击&#xff0c;所以自己简单的研究下 XXE 攻击。XXE&#xff08;XML External Entity&#xff09;XML 外部实体&#xff0c;当前端和后端通信数据采用 xml&…

element el-date-picker 日期组件置灰指定日期范围、禁止日期范围日期选择

JS如何将当前日期或指定日期转时间戳_javascript技巧_脚本之家 小于指定日期前的日期置灰 比如这里 指定日期是 2024-02-20 10:48:15 disabledDate(time) time是一个函数提供的时间用于比较 他是一个时间戳↓ 理解为我们想要置灰的时间 time.getTime() < timeStamps- 1 *…

《Large Language Models for Generative Information Extraction: A Survey》阅读笔录

论文地址&#xff1a;Large Language Models for Generative Information Extraction: A Survey 前言 映像中&#xff0c;比较早地使用“大模型“”进行信息抽取的一篇论文是2022年发表的《Unified Structure Generation for Universal Information Extraction》&#xff0c;也…

IDEA开发环境热部署

开发环境热部署 在实际的项目开发调试过程中会频繁地修改后台类文件&#xff0c;导致需要重新编译重新启动&#xff0c;整个过程非常麻烦&#xff0c;影响开发效率。Spring Boot提供了spring-boot-devtools组件&#xff0c;使得无须手动重启SpringBoot应用即可重新编译、启动项…

36.云原生之SpringCloud+k8s实践

云原生专栏大纲 文章目录 SpringCloudk8s介绍spring-cloud-kubernetes服务发现配置管理负载均衡选主 spring-cloud-bookinfo案例构建项目环境配置namespace部署与验证productpagegatewaybookinfo-admindetailsratingsreviewsreviews-v1reviews-v2 总结 SpringCloudk8s介绍 ht…

vue-router4 (六) 路由嵌套

应用场景&#xff1a; ①比如京东页面的首页、购物车、我的按钮&#xff0c;可以点击切换到对应的页面&#xff1b; ② 比如 Ant Design左侧这些按钮点击就会切到对应的页面&#xff0c;此时可以把左侧按钮放在父路由中&#xff0c;右侧的子路由 1.路由配置&#xff0c;子路由…

将法律条文很美观的复制到word上

前言 目前很多法律条款都没有现成的PDF或者word格式的供大家下载&#xff0c;这个时候呢&#xff0c;领导又要求你帮他搞定&#xff0c;这就很。。。。 步骤 复制全部条款到word中使用wps的排版功能&#xff0c;将空格和空段落全部移除 3. 设置好你需要的格式 标题&#xff…

常用对象的遍历方法

var obj [{name: 1111,account: {01: { name: 1.1 },02: { name: 1.2 },03: { name: 1.3 },04: { name: 1.4 },05: { name: 1.5 },}} ]var nowObj obj[0].account;1、for…in 任意顺序遍历对象所有的可枚举属性&#xff08;包括对象自身的和继承的可枚举属性&#xff0c;不含…

影像仪激光扫描功能,无缝连接2D/3D混合测量

在现代工业生产领域&#xff0c;影像仪用于质量控制和产品检测&#xff0c;是一个不可或缺的工具。它通过高精度的成像和图像处理技术&#xff0c;可以及时发现产品的缺陷和异常&#xff0c;以保证产品质量的稳定性和一致性。 影像仪的重要性及其面临的挑战 在工业生产方面&a…

代码随想录算法训练营第42天|● 1049. 最后一块石头的重量 II ● 494. 目标和 ● 474.一和零

文章目录 1049.最后一块石头的重量II思路&#xff1a;动归五部曲代码&#xff1a; ● 494. 目标和思路五部曲1.确定dp数组五部曲2.确定dp公式3.dp初始化4.遍历顺序 代码&#xff1a; ● 474.一和零思路动归五部曲 代码&#xff1a; 1049.最后一块石头的重量II 思路&#xff1a;…

go test用法(获取单元测试覆盖率)

go test用法&#xff08;获取ut覆盖率&#xff09; 为了提升系统的稳定性&#xff0c;一般公司都会对代码的单元测试覆盖率有一定要求。下面针对golang自带的测试命令go test做讲解。 1 命令 1.1 go test ./… &#xff08;运行当前目录及所有子目录下的测试用例&#xff09; …

【virtual Box】功能速通:安装 Windows 和 Ubuntu

文章目录 一、虚拟机1.1 概述1.2 virtual box概述 二、新建虚拟机、删除、注册三、虚拟机内部设置3.1 安装增强功能驱动3.2 分辨率问题3.3 网络链接方式 一、虚拟机 1.1 概述 虚拟机&#xff08;Virtual Machine&#xff0c;VM&#xff09;是一种软件实现的计算机系统&#x…

【Nginx笔记02】通过Nginx服务器转发客户端的WebSocket接口到后端服务

这篇文章&#xff0c;主要介绍如何通过Nginx服务器转发客户端的WebSocket接口到后端服务【知识星球】。 目录 一、Nginx配置WebSocket 1.1、Nginx配置内容 1.2、客户端请求地址 1.3、创建WebSocket测试工程 1.4、启动测试 1.5、WebSocket超时问题 1.5.1、设置超时时间 …

计算机网络——IPV4数字报

1. IPv4数据报的结构 本结构遵循的是RFC 791规范&#xff0c;介绍了一个IPv4数据包头部的不同字段。 1.1 IPv4头部 a. 版本&#xff08;Version&#xff09;&#xff1a;指明了IP协议的版本&#xff0c;IPv4表示为4。 b. 头部长度&#xff08;IHL, Internet Header Length&…

图论基础(一)

一、图论 图论是数学的一个分支&#xff0c;它以图为研究对象。图论中的图是若干给定的点&#xff08;顶点&#xff09;以及连接两点的线&#xff08;边&#xff09;构成的图像&#xff0c;这种图形通常用来描述某些事物之间的某种特定关系&#xff0c;用点代表事物&#xff0c…

TPS54302 DCDC稳压电路设计与测试

原理图和PCB布局布线参考官方应用手册设计。 输入22V&#xff0c;输出5V-1A时电感发热&#xff0c;如果大于此输出功率建议更换大封装电感。 纹波测试 输出5V-1A情况下&#xff0c;输入电压在8-23V区间时纹波都在 20-40mv之间。当输入电压达到24V时纹波会变得很大&#xff0c…

DAY12_VUE基本用法详细版

目录 0 HBuilderX酷黑主题修改注释颜色1 VUE1.1 VUE介绍1.2 Vue优点1.3 VUE入门案例1.3.1 导入JS文件1.3.2 VUE入门案例 1.4 VUE基本用法1.4.1 v-cloak属性1.4.2 v-text指令1.4.3 v-html指令1.4.4 v-pre指令1.4.5 v-once指令1.4.6 v-model指令1.4.7 MVVM思想 1.5 事件绑定1.5.1…

架构设计:生产消费模型

1. 引言 在现代软件系统中&#xff0c;处理大量数据和消息是一项重要的任务。生产消费模型作为一种经典的并发模式&#xff0c;在解决数据生产和消费之间的关系上发挥着关键作用。该模型通过有效地管理生产者和消费者之间的通信和数据流动&#xff0c;实现了系统组件之间的解耦…

Mycat核心教程--Mycat 监控工具【四】

Mycat核心教程--Mycat 监控工具 九、Mycat 监控工具9.1.Mycat-web 简介9.2.Mycat-web 配置使用9.2.1.ZooKeeper 安装【上面有】9.2.2.Mycat-web 安装9.2.2.1.下载安装包9.2.2.2.安装包拷贝到Linux系统/opt目录下&#xff0c;并解压9.2.2.3.拷贝mycat-web文件夹到/usr/local目录…

[足式机器人]Part2 Dr. CAN学习笔记-Ch00-2 - 数学知识基础

本文仅供学习使用 本文参考: B站:DR_CAN 《控制之美(卷1)》 王天威 《控制之美(卷2)》 王天威 Dr. CAN学习笔记-Ch00 - 数学知识基础 Part2 4. Ch0-4 线性时不变系统中的冲激响应与卷积4.1 LIT System:Linear Time Invariant4.2 卷积 Convolution4.3 单位冲激 Unit Impulse—…