【SpringBoot】公共字段自动填充

问题引入

JavaEE开发的时候,新增字段,修改字段大都会涉及到创建时间(createTime),更改时间(updateTime),创建人(craeteUser),更改人(updateUser),如果每次都要自己去setter(),会比较麻烦,可以使用Spring的AOP,对于任意Insert,Update操作进行增强

解决步骤

主要依赖

如果使用了springboot,那就只需要导入这一个,这个框架对spring自带的aop框架进行了优化封装,更好用

事实上,还需要两个依赖,spring-context和spring-aop,不过springboot自带的有

<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version>
</dependency>

注释代码

给那些新增、修改功能中的设置时间、修改人的代码部分注释掉

自定义注解&使用

封装数据库操作类型

/*** 数据库操作类型*/
public enum OperationType {/*** 更新操作*/UPDATE,/*** 插入操作*/INSERT}

自定义注解 

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {// 数据库操作类型:UPDATE INSERTOperationType value();
}

给需要自动填充的方法加上注解 

    /*** 新增员工* @param employee*/@Insert("INSERT INTO employee" +"(name, username, password, phone, sex, id_number, create_time, update_time, create_user, update_user)" +"VALUES" +"(#{name}, #{username}, #{password}, #{phone}, #{sex}, #{idNumber}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})")@AutoFill(value = OperationType.INSERT)void insert(Employee employee);/*** 修改员工信息* @param employee*/@AutoFill(value = OperationType.UPDATE)void update(Employee employee);/*** 根据ID查询员工* @param id* @return*/@Select("SELECT * FROM employee WHERE id = #{id}")Employee getById(Long id);/*** 密码修改* @param passwordEditDTO*/@AutoFill(value = OperationType.UPDATE)@Update("UPDATE employee SET `password` = #{newPassword} WHERE `id` = #{empId} AND `password` = #{oldPassword}")void updatePwd(PasswordEditDTO passwordEditDTO);

通知类

@Slf4j
@Component
@Aspect
public class AutoFillAspect {/*** 切面 && 指定切入点*/@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")public void autoFillPointCut(){}/*** 切面 && 此方法(autoFill()) 在切入点之前执行* @param joinPoint*/@Before("autoFillPointCut()")public void autoFill(JoinPoint joinPoint) {log.info("开始进行公共字段自动填充...");// 拿到当前被拦截的方法上的数据库操作类型MethodSignature signature = (MethodSignature)joinPoint.getSignature();// 拿到实现类的签名信息,不过我们只需要方法的签名信息,强转成MethodSignatureAutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);// 获得签名对象的注解对象OperationType operationType = autoFill.value(); // 拿到数据库操作类型// 拿到当前被拦截方法的方法参数(新增、更改方法的参数一般都是实体类)Object[] args = joinPoint.getArgs();if (args == null || args.length == 0){ // 防止null,防止空参return;}Object entity = args[0]; // 这一行就要求,以后的新增、更改方法参数,实体类必须写在首形参位置// 需填充的数据LocalDateTime now = LocalDateTime.now();Long currentId = BaseContext.getCurrentId();// 根据当前不同的操作类型,使用反射为对应的属性赋值if (operationType == OperationType.INSERT) {// 为4个公共字段赋值try {Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);// 通过反射给对象属性赋值setCreateTime.invoke(entity, now);setUpdateTime.invoke(entity, now);setCreateUser.invoke(entity, currentId);setUpdateUser.invoke(entity, currentId);} catch (Exception e) {e.printStackTrace();}} else if (operationType == OperationType.UPDATE) {// 为2个公共字段赋值try {Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);// 通过反射给对象属性赋值setUpdateTime.invoke(entity, now);setUpdateUser.invoke(entity, currentId);} catch (Exception e) {e.printStackTrace();}}}
}

依赖相关类

公共字段自动填充相关常量

/*** 公共字段自动填充相关常量*/
public class AutoFillConstant {/*** 实体类中的方法名称*/public static final String SET_CREATE_TIME = "setCreateTime";public static final String SET_UPDATE_TIME = "setUpdateTime";public static final String SET_CREATE_USER = "setCreateUser";public static final String SET_UPDATE_USER = "setUpdateUser";
}

线程空间上下文

public class BaseContext {public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();public static void setCurrentId(Long id) {threadLocal.set(id);}public static Long getCurrentId() {return threadLocal.get();}public static void removeCurrentId() {threadLocal.remove();}}

启动类加上注解@EnableAspectJAutoProxy

@SpringBootApplication
@EnableTransactionManagement //开启注解方式的事务管理
@EnableAspectJAutoProxy // 开启注解方式的AOP
@Slf4j
public class SkyApplication {public static void main(String[] args) {SpringApplication.run(SkyApplication.class, args);log.info("server started");}
}

在这段代码中,joinPoint 是 Spring AOP 中的一个概念,表示连接点,即在程序执行过程中切入的某个点。Signature 则是 Signature 接口的实现类之一,用于表示连接点的签名信息,包括方法名、参数列表等。

具体来说,这段代码的含义是从 joinPoint 中获取连接点的签名信息,并将其强制转换为 MethodSignature 类型。然后可以通过 signature 对象获取连接点(被代理方法)的详细信息,比如方法名、参数类型等。

例如,可以通过 signature.getMethod().getName() 获取连接点方法的名称,通过 signature.getParameterTypes() 获取连接点方法的参数类型数组等。

需要注意的是,在实际应用中,我们使用这段代码时需要确保 joinPoint 真正代表了一个方法连接点,否则在强制转换为 MethodSignature 时可能会抛出类型转换异常。

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

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

相关文章

深度学习-卷积神经网络CNN

案例-图像分类 网络结构: 卷积BN激活池化 数据集介绍 CIFAR-10数据集5万张训练图像、1万张测试图像、10个类别、每个类别有6k个图像&#xff0c;图像大小32323。下图列举了10个类&#xff0c;每一类随机展示了10张图片&#xff1a; 特征图计算 在卷积层和池化层结束后, 将特征…

stm32——通用定时器时钟知识点

&#xff08;该图来自小破站 铁头山羊老师的stm32标准库教学&#xff09;

SobarQube实现PDF报告导出

文章目录 前言一、插件配置二、使用步骤1.新生成一个Token2.将拷贝的Token加到上文中执行的命令中3.查看报告 三、友情提示总结 前言 这篇博文是承接此文 .Net项目在Windows中使用sonarqube进行代码质量扫描的详细操作配置 描述如何导出PDF报告 众所周知&#xff0c;导出PDF功…

【数据结构】10.线索二叉树

一、线索二叉树的产生 采用先序、中序、后序三种方法遍历二叉树后都可以得到一个线性序列&#xff0c;序列上的每一个结点&#xff08;除了第一个和最后一个&#xff09;都有一个前驱和一个后继&#xff0c;但是&#xff0c;这个线性序列只是逻辑的概念&#xff0c;不是物理结…

如何合理设计一套springcloud+springboot项目中的各个微服务模块之间的继承关系的最优方案

文章目录 一、模块化设计所遵循的原则二、项目架构设计三、各个模块作用说明3.1 core 模块3.2 common 模块3.3 generatorcode模块3.4 business 模块3.5 web 模块3.6 admin 模块3.7 父pom 四、采用import引入SpringBoot 在springcloud微服务项目中经常用到多模块化的架构设计&am…

HarmonyOS4+NEXT星河版入门与项目实战--------开发工具与环境准备

文章目录 1、熟悉鸿蒙官网1、打开官网2、下载 DevEco Studio3、HarmonyOS 资源库4、开发指南与API 2、安装 DevEco Studio1、软件安装2、配置开发工具 1、熟悉鸿蒙官网 1、打开官网 百度搜索 鸿蒙开发者官网 点击进入开发者官网&#xff0c;点击开发&#xff0c;可以看到各种…

单元测试、集成测试、系统测试、验收测试、压力测试、性能测试、安全性测试、兼容性测试、回归测试(超详细的分类介绍及教学)

目录 1.单元测试 实现单元测试的方法&#xff1a; 注意事项&#xff1a; 2.集成测试 需注意事项&#xff1a; 实现集成测试的方法&#xff1a; 如何实现高效且可靠的集成测试&#xff1a; 3.系统测试 实现系统测试的方法: 须知注意事项&#xff1a; 4.验收测试 实现验…

Ubuntu24 上安装搜狗输入法

link 首先在终端中依次输入以下代码 sudo apt update sudo apt install fcitx 找到语言支持 在终端中依次输入 sudo cp /usr/share/applications/fcitx.desktop /etc/xdg/autostart/ sudo apt purge ibus 进入网页 搜狗输入法linux-首页​ shurufa.sogou.com/linux 找到刚才下…

FairyGUI和Unity联动(入门篇)

一、FairyGUI编辑器中 1.新建按钮、新建组件 编辑器中界面简易设计如下 2.文件-发布设置-发布路径&#xff1a;自己unity项目Resources所在的路径 二、Unity 使用代码展示UI using FairyGUI; using System.Collections; using System.Collections.Generic; using UnityEngi…

【Java知识】Java性能测试工具JMeter

一文带你了解什么是JMeter 概述JMeter的主要功能&#xff1a;JMeter的工作原理&#xff1a;JMeter的应用场景&#xff1a;JMeter的组件介绍&#xff1a; 实践说明JMeter实践基本步骤&#xff1a;JMeter实践关键点&#xff1a; JMeter支持哪些参数化技术&#xff1f;常见插件及其…

Redis的缓存穿透、缓存雪崩、缓存击穿问题及有效解决方案

目录 一、缓存穿透 1.简介 2.解决方案 3.修改前的代码 4.修改过后的代码 二、缓存雪崩 1.简介 2.解决方案 三、缓存击穿 1.简介 2.解决方案 3.用代码来实现互斥锁来解决缓存击穿 4.用代码来实现逻辑过期解决缓存击穿 四、缓存穿透和缓存击穿的区别 一、缓存穿透 …

CPU的性能指标总结(学习笔记)

CPU 性能指标 我们先来回顾下&#xff0c;描述 CPU 的性能指标都有哪些。 首先&#xff0c;最容易想到的应该是 CPU 使用率&#xff0c;这也是实际环境中最常见的一个性能指标。 用户 CPU 使用率&#xff0c;包括用户态 CPU 使用率&#xff08;user&#xff09;和低优先级用…

【go从零单排】Environment Variables环境变量

&#x1f308;Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 &#x1f4d7;概念 在 Go 语言中&#xff0c;环境变量是用于配置程序行为的一种常见方式。它们可以用…

信捷PLC转以太网连接电脑方法

信捷XC/XD/XL等系列PLC如何上下载程序?可以选择用捷米特JM-ETH-XJ模块轻松搞定,并不需要编程&#xff0c;即插即用&#xff0c;具体看见以下介绍&#xff1a; 产品介绍 捷米特JM-ETH-XJ是专门为信捷PLC转以太网通讯面设计&#xff0c;可实现工厂设备信息化需求&#xff0c;对…

【golang-技巧】-线上死锁问题排查-by pprof

1.背景 由于目前项目使用 cgo golang 本地不能debug, 发生死锁问题&#xff0c;程序运行和期待不一致&#xff0c;通过日志排查可以大概率找到 阻塞范围&#xff0c;但是不能找到具体问题在哪里&#xff0c;同时服务器 通过k8s daemonset 部署没有更好的方式暴露端口 获取ppr…

AVL树的删除方法简单实现

看过前面的AVL树的介绍和插入方法实现AVL树了解并简单实现-CSDN博客&#xff0c;接着可以来学习删除方法的实现 目录 1.AVL树的删除 2.平衡因子调节 3.删除代码逻辑 4.AVL树的整体代码 1.AVL树的删除 因为AVL树也是二叉搜索树&#xff0c;可按照二叉搜索树的方式将节点删除…

ArcGIS的汉字(亚洲文本)垂直标注

01 需求说明 实现ArcGIS的汉字&#xff08;亚洲文本的垂直标注&#xff09;。 启用 Maplex 标注引擎。 在标注 工具条上单击标注管理器按钮 。 选中要进行标注的图层旁边的复选框。 选择图层下方的标注分类。 单击符号。 选中 CJK 字符方向复选框。 仅当字体有垂直的文本度…

飞凌嵌入式RK3576核心板已适配Android 14系统

在今年3月举办的RKDC2024大会上&#xff0c;飞凌嵌入式FET3576-C核心板作为瑞芯微RK3576处理器的行业首秀方案重磅亮相&#xff0c;并于今年6月率先量产发货&#xff0c;为客户持续稳定地供应&#xff0c;得到了众多合作伙伴的认可。 FET3576-C核心板此前已提供了Linux 6.1.57…

基于python的dlib库的人脸识别实现

1、环境搭建 基于dlib库的人脸识别环境配置需求如下: conda create -n dlibFace python3.6.4 conda activate dlibFacepip install dlib19.8.1 pip install opencv-python3.4.1.15 pip install tqdm 安装如下: 2、模块介绍 2.1 源代码下载 源代码点击:下载源代码 2.2 源码…

Ubuntu问题 -- 允许ssh使用root用户登陆

目的 新重装的系统, 普通用户可以使用ssh登陆服务器, 但是root不能使用ssh登陆 方法 vim 编辑ssh配置文件 sudo vim /etc/ssh/sshd_config找到 PermitRootLogin 这一行, 把后面值改成 yes 重启ssh sudo service sshd restart然后使用root账号登陆即可