使用AOP优化Spring Boot Controller参数:自动填充常用字段的技巧

欢迎来到我的博客,代码的世界里,每一行都是一个故事


在这里插入图片描述

🎏:你只管努力,剩下的交给时间

🏠 :小破站

使用AOP优化Spring Boot Controller参数:自动填充常用字段的技巧

    • 前言
    • 为什么使用AOP
      • 为什么使用AOP实现参数重写?
        • 好处:
        • 坏处:
      • 其他实现方式及其比较
        • 1. Controller基类方法
        • 2. 使用拦截器(Interceptor)
      • 总结
    • 实现
      • 解释说明:

前言

在现代Web开发中,通过AOP实现参数重写是一种高效且优雅的方式。它不仅能帮助开发者简化重复性的代码编写,还能有效提升接口的安全性和可靠性。今天,我们将探索如何利用AOP技术,在Spring Boot项目中实现对Controller保存方法参数的智能填充,让你的API开发更加高效和愉快。

为什么使用AOP

理解为什么选择使用AOP(面向切面编程)来实现参数重写是很重要的,同时还可以考虑其他实现方式。下面我们来详细探讨一下这些方面:

为什么使用AOP实现参数重写?

好处:
  1. 解耦和增强可维护性:AOP可以将横切逻辑(如参数填充)从业务逻辑中分离出来,避免代码重复,提高代码的清晰度和可维护性。
  2. 集中管理和复用:通过AOP,可以集中管理和配置参数填充逻辑,使得多个Controller方法都能够共享同一段逻辑,减少重复开发。
  3. 方便扩展和修改:当需要修改或扩展参数填充逻辑时,只需调整AOP切面,而不必修改每个涉及到参数填充的Controller方法。
坏处:
  1. 引入复杂性:AOP的使用可能会增加代码的复杂性,特别是对于初学者来说,理解和调试AOP可能会有一定的学习曲线。
  2. 运行时性能开销:AOP通常在运行时动态生成代理对象或者织入代码,可能会对系统性能产生一定的影响,尤其是在大规模应用中。

其他实现方式及其比较

1. Controller基类方法

通过创建一个基类Controller,其中包含公共的参数填充逻辑,所有Controller继承这个基类,实现参数填充的共享。

  • 好处:简单直接,无需引入AOP框架,易于理解和维护。
  • 坏处:如果项目中有多种不同的参数填充逻辑,可能会导致基类代码过于复杂和臃肿。
2. 使用拦截器(Interceptor)

在Spring MVC中,可以通过实现HandlerInterceptor接口,重写preHandle方法,在请求进入Controller方法之前进行参数的预处理。

  • 好处:与AOP类似,可以实现对请求的拦截和处理,但更加灵活,可以针对特定的请求路径或者方法进行处理。
  • 坏处:拦截器主要用于对请求的预处理和后处理,不够直接地集中在参数填充的功能上,可能需要额外的配置和管理。

总结

选择使用AOP来实现参数重写,是为了提高代码的复用性、可维护性和灵活性。它能够有效地解耦业务逻辑和横切关注点(如参数填充),使得代码更加清晰和易于扩展。然而,AOP也不是万能的解决方案,需要权衡其引入的复杂性和可能的运行时开销。

除了AOP,还可以考虑使用Controller基类方法或者拦截器来实现类似的功能,具体选择取决于项目的需求和团队的技术栈。

实现

下面是一个改进的示例,演示如何使用反射来处理不同类型的实体对象:

@Aspect
@Component
public class ControllerAspect {@Autowiredprivate UserService userService; // 假设需要从userService中获取当前用户信息@Around("execution(* com.example.controller.*Controller.save*(..))")public Object aroundSave(ProceedingJoinPoint joinPoint) throws Throwable {// 获取目标方法的参数Object[] args = joinPoint.getArgs();for (Object arg : args) {if (arg instanceof BaseEntity) {handleEntity((BaseEntity) arg);}}// 继续执行目标方法Object result = joinPoint.proceed();return result;}private void handleEntity(BaseEntity entity) {try {// 使用反射获取实体对象的类Class<?> clazz = entity.getClass();// 设置创建时间、修改时间、创建人、修改人等通用属性Field createTimeField = clazz.getDeclaredField("createTime");createTimeField.setAccessible(true);createTimeField.set(entity, LocalDateTime.now());Field updateTimeField = clazz.getDeclaredField("updateTime");updateTimeField.setAccessible(true);updateTimeField.set(entity, LocalDateTime.now());Field createUserField = clazz.getDeclaredField("createUser");createUserField.setAccessible(true);createUserField.set(entity, userService.getCurrentUser());Field updateUserField = clazz.getDeclaredField("updateUser");updateUserField.setAccessible(true);updateUserField.set(entity, userService.getCurrentUser());// 可以根据需要添加其他通用属性的处理} catch (NoSuchFieldException | IllegalAccessException e) {// 处理异常e.printStackTrace();}}
}

解释说明:

  1. @Around("execution( com.example.controller.Controller.save(…))")*:

    • @Around:表示在目标方法执行前后都会执行该切面逻辑。
    • "execution(* com.example.controller.*Controller.save*(..))":指定切入点表达式,匹配所有保存方法(如save、saveOrUpdate等)。
  2. aroundSave方法

    • ProceedingJoinPoint joinPoint:继承自JoinPoint,可以控制目标方法的执行。
    • Object[] args = joinPoint.getArgs():获取目标方法的所有参数。
    • 遍历参数数组,对每个参数进行类型判断。在示例中,假设所有的实体类都继承自BaseEntity,因此使用instanceof BaseEntity来判断。
  3. handleEntity方法

    • BaseEntity entity:传入的实体对象,通过反射动态设置通用属性。
    • 使用entity.getClass()获取实体对象的Class对象,然后使用反射操作这些属性。
    • 获取并设置实体对象的创建时间、修改时间、创建人、修改人等通用属性。
    • 可以根据实际需求,添加其他通用属性的处理。

通过这种方式,你可以处理多种不同类型的实体对象,只需在BaseEntity中定义通用的属性,并确保这些属性在各个实体对象中都存在和可访问。这种实现方式不仅通用,而且具有较高的灵活性和可扩展性,能够满足处理复杂业务场景下多样化实体对象的需求。

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

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

相关文章

java8函数式编程学习(二):optional,函数式接口和并行流的学习

简介 java8函数式编程中optional的简单使用&#xff0c;函数式接口的了解&#xff0c;并行流的使用。 optional 可以更优雅的来避免空指针异常。类似于包装类&#xff0c;把具体的数据封装到optional对象内部&#xff0c;然后使用optional的方法去操作封装好的数据。 创建o…

Python编程入门指南:从基础到高级

Python编程入门指南&#xff1a;从基础到高级 一、Python编程语言简介 1. Python是什么&#xff1f; Python是一门广泛使用的计算机程序编程语言&#xff0c;由荷兰人吉多范罗苏姆&#xff08;Guido van Rossum&#xff09;于1991年首次发行。Python是一种解释型、交互式、面…

汽车免拆诊断案例 | 2018 款别克阅朗车蓄电池偶尔亏电

故障现象 一辆2018款别克阅朗车&#xff0c;搭载LI6发动机和GF6变速器&#xff0c;累计行驶里程约为9.6万km。车主反映&#xff0c;该车停放一晚后&#xff0c;蓄电池偶尔亏电。 故障诊断 接车后用虹科Pico汽车示波器和高精度电流钳&#xff08;30 A&#xff09;测量该车的寄…

Spring AOP(2)原理(代理模式和源码解析)

目录 一、代理模式 二、静态代理 三、动态代理 1、JDK动态代理 &#xff08;1&#xff09;JDK动态代理实现步骤 &#xff08;2&#xff09;定义JDK动态代理类 &#xff08;3&#xff09;代码简单讲解 2、CGLIB动态代理 &#xff08;1&#xff09;CGLIB 动态代理类实现…

【数据结构】稀疏数组

问题引导 在编写五子棋程序的时候&#xff0c;有“存盘退出”和“续上盘”的功能。现在我们要把一个棋盘保存起来&#xff0c;容易想到用二维数组的方式把棋盘表示出来&#xff0c;但是由于在数组中很多数值取默认值0&#xff0c;因此记录了很多没有意义的数据。此时我们使用稀…

Apache压测工具ab(Apache Bench)工具的下载安装和使用示例

场景 Jmeter进行http接口压力测试&#xff1a; Jmeter进行http接口压力测试_接口压测两万量-CSDN博客 上面讲压测工具Jmeter的使用&#xff0c;下面介绍另外一个ab(Apache Bench)压测工具的使用。 apache bench apache bench是apache自带的压力测试工具。 ab不仅可以对ap…

基于联盟链Fabric 2.X 的中药饮片代煎配送服务与监管平台

业务背景 近年来&#xff0c;随着公众对中医药青睐有加&#xff0c;中药代煎服务作为中医药现代化的重要一环&#xff0c;在全国各地蓬勃兴起。鉴于传统煎煮方式的繁琐耗时&#xff0c;医疗机构纷纷转向与第三方中药饮片企业合作&#xff0c;采用集中代煎模式。这些第三方煎药中…

没有51基础,能不能学好STM32?

在开始前刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「STM32的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; 我们通常准备攻读一本大部…

浅谈监听器之断言结果

浅谈监听器之断言结果 在进行测试过程中&#xff0c;断言是一种关键组件&#xff0c;用于验证采样器&#xff08;如HTTP请求&#xff09;的响应数据是否符合预期。而“断言结果”监听器则是展示这些断言执行情况的重要工具&#xff0c;它帮助用户快速识别哪些断言通过或未通过…

【JAVA多线程】线程的状态控制

目录 1.JDK中的线程状态 2.基础操作 2.1关闭 2.2中断 2.3.等待、唤醒 2.4.阻塞、唤醒 1.JDK中的线程状态 在JDK的线程体系中线程一共6种状态&#xff1a; NEW&#xff08;新建&#xff09;: 当线程对象创建后&#xff0c;但尚未启动时&#xff0c;线程处于新建状态。RUN…

python毕业设计选题校园食堂菜谱推荐系统

✌网站介绍&#xff1a;✌10年项目辅导经验、专注于计算机技术领域学生项目实战辅导。 ✌服务范围&#xff1a;Java(SpringBoo/SSM)、Python、PHP、Nodejs、爬虫、数据可视化、小程序、安卓app、大数据等设计与开发。 ✌服务内容&#xff1a;免费功能设计、免费提供开题答辩P…

stack(leetcode练习题,牛客)

文章目录 STL用法总结32 最长有效括号思路代码 496 下一个最大元素思路代码 856 括号的分数思路 最优屏障思路代码 STL用法总结 关于stack的知识&#xff0c;可以看点击查看上面的博客&#xff0c;以下题目前三个全在leetcode&#xff0c;最后一个在牛客 32 最长有效括号 思路…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第五十章 Linux设备树

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

代理IP在数据采集中具体有哪些作用

在当今信息化高速发展的时代&#xff0c;从市场趋势分析到消费者行为预测&#xff0c;从产品优化到服务改进&#xff0c;大数据都在其中扮演着不可或缺的角色。但数据的采集、整理和分析并非易事&#xff0c;特别是在面对海量的网络数据时&#xff0c;我们往往需要借助一些技术…

前端 SSE 长连接

使用 const options {withCredentials: true, // 默认 false}const eventSource new EventSource(/api, options);eventSource.addEventListener(open, () > {});eventSource.onmessage (event) > {}; // 或addEventListener(message,callback)eventSource.addEvent…

程序员拔火罐技能的分享

一.背景 之前为了考“中医康复理疗师”的证书&#xff0c;自学了拔火罐。自学主要是在自己大腿上练习&#xff0c;然后拿家人做小白鼠。后来考试没有那么严格也就顺利通过了。操作过程中&#xff0c;积累的一些小知识&#xff0c;分享给大家&#xff0c;有空在家里给家人服务体…

CTF ssrf 基础入门 (一)

0x01 引言 我发现我其实并不是很明白这个东西&#xff0c;有些微妙&#xff0c;而且记忆中也就记得Gopherus这个工具了&#xff0c;所以重新学习了一下&#xff0c;顺便记录一下吧 0x02 辨别 我们拿到一个题目&#xff0c;他的名字可能就是题目类型&#xff0c;但是也有可能…

FastAPI(七十三)实战开发《在线课程学习系统》接口开发-- 回复留言

源码见&#xff1a;"fastapi_study_road-learning_system_online_courses: fastapi框架实战之--在线课程学习系统" 之前文章分享FastAPI&#xff08;七十二&#xff09;实战开发《在线课程学习系统》接口开发-- 留言列表开发&#xff0c;这次我们分享如何回复留言 按…

Jenkins+Gitlab持续集成综合实战

一、持续集成应用背景&#xff1a; DevOps&#xff1a;&#xff08;英文Development&#xff08;开发&#xff09;和Operations&#xff08;技术运营&#xff09;的组合&#xff09;是一组过程、方法与系统的统称&#xff0c;用于促进开发&#xff08;应用程序/软件工程&#…

NCRE3 2-1 网络总体设计基本方法

这部分记忆的比较多 概览 设计网络建设总体目标确定网络系统方案设计原则网络系统总体设计设计网络拓扑结构进行网络设备选型网络系统安全设计 设计网络建设总体目标 这部分视频没说到 确定网络系统方案设计原则 这部分视频没说到 网络系统总体设计 核心层网络结构设计 …