[SpringBoot]自定义注解@AutoFill,实现公共字段自动填充(避免重复对时间属性初始化

news/2024/10/22 16:22:12/

对于时间属性,如createTime、updateTime在进行插入、修改操作时都要一个个初始化处理,过于麻烦。

可以自定义注解@AutoFill作用于INSERT,UPDATE操作方法上,再自定义切面类,统一拦截加入了AutoFill注解的方法,通过反射为公共字段赋值。

涉及知识点:枚举、注解、AOP、反射

目录

1.自定义注解@AutoFill, 用于标示某个方法需要进行功能字段自动填充处理

2.在Mapper层对应insert、update方法上加上注解@AutoFill 

3.自定义切面,实现公共字段自动填充处理逻辑


 

老办法,缺点:过于重复和麻烦 

f70a5dfc6b814f26858b12527979df4f.png

好方法:公共字段自动填充

1.自定义注解@AutoFill, 用于标示某个方法需要进行功能字段自动填充处理

35f97158fdcc433f9764c65c3d3f32a2.png 

自定义注解:AutoFill

import com.sky.enumeration.OperationType;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 AutoFill {// 枚举数据库类型:UPDATE INSERT 用于标示自动填充的类型OperationType value();
}

自定义枚举类型:OperationType

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

2.在Mapper层对应insert、update方法上加上注解@AutoFill 

026ceabe5cf14f4cae50585c0fb5ca98.png

1600c05e83fa4352b103d0076db0091e.png

3.自定义切面,实现公共字段自动填充处理逻辑

 ①定义切入点,即统一拦截加入了AutoFill 注解的方法

 ②编写前置通知,进行公共字段自动填充

  • 获取到当前被拦截的方法上的数据库操作类型

  • 获取到当前被拦截的方法的参数--实体对象

  • 准备赋值的数据

  • 根据当前不同的操作类型,为对应的属性通过反射来赋值

自定义切面类:AutoFillAspect

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;
import java.time.LocalDateTime;/*** 自定义切面,实现公共字段自动填充处理逻辑*/
@Aspect
@Component
@Slf4j
public class AutoFillAspect {/*** 切入点*/@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")public void autoFillPointCut() {}/*** 前置通知*/@Before("autoFillPointCut()")public void autoFill(JoinPoint joinPoint) {log.info("开始进行公共字段自动填充...");//1. 获取到当前被拦截的方法上的数据库操作类型MethodSignature signature = (MethodSignature)joinPoint.getSignature(); //方法签名对象AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class); //获得方法上的对象OperationType operationType = autoFill.value(); //获取数据库操作类型//2. 获取到当前被拦截的方法的参数--实体对象Object[] args = joinPoint.getArgs();if (args == null || args.length == 0){return;}Object entity = args[0];//3. 准备赋值的数据LocalDateTime now = LocalDateTime.now();Long currentId = BaseContext.getCurrentId();//4. 根据当前不同的操作类型,为对应的属性通过反射来赋值if (operationType == OperationType.INSERT){// 为4个公共字段赋值try {Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);//通过反射为对象属性赋值setCreateTime.invoke(entity, now);setCreateUser.invoke(entity, currentId);setUpdateTime.invoke(entity, now);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();}}}
}

公共字段填充常量类:AutoFillConstant

/*** 公共字段自动填充相关常量*/
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";
}

 


http://www.ppmy.cn/news/1295621.html

相关文章

Go语言中的init函数的执行时机

init函数的执行时机 这个涉及到 init 函数的作用和执行顺序相同个文件和不同文件中以及在不同的包中init的执行顺序go文件初始化的顺序 一、init 函数的作用和执行顺序 作用 init 函数是用于程序执行前做包的初始化的函数,比如初始化包里面的一些变量等等通常在…

UE5.1_UMG序列帧动画制作

UE5.1_UMG序列帧动画制作 UMG序列帧动画制作相对比较简单,不像视频帧需要创建媒体播放器那么复杂,以下简要说明: 1. 事件函数 2. 准备序列帧装入数组 3. 构造调用事件函数 4. 预览 序列帧UMG0105 5. 完成!按需配置即可。

mysql服务多实例运行

1、官网下载mysql安装包 https://downloads.mysql.com/archives/community/ 2、解压安装包 tar -zxvf mysql-8.1.0-linux-glibc2.28-aarch64.tar.xz -C /usr/localmv /usr/local/mysql-8.1.0-linux-glibc2.28-aarch64 /usr/local/mysql 3、创建mysql用户组 groupadd…

HCIA-Datacom题库(自己整理分类的)_11_其他网络协议单选【9道题】

1.DNS协议的主要作用是? 文件传输 远程接入 域名解析 邮件传输 2.下列属于链路状态协议的是? Direct static FTP OSPF 解析: FTP:文件传输协议 OSPF:链路状态路由协议 3.如下图所示的网络主机A通过Telnet登录到路由…

【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax概述

【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax概述 【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax快速入门 【大数据进阶第三阶段之Datax学习笔记】阿里云开源离线同步工具Datax类图 【大数据进阶第三阶段之Datax学习笔记】使用…

Docker使用扩展

日升时奋斗,日落时自省 目录 1、容器 1.1、容器的生命周期 1.1.1、容器OOM 1.1.2、容器异常退出 1.1.3、容器暂停 1.2、容器命令 1.2.1、创建容器 1.2.2、启动容器 1.2.3、容器日志 1.2.4、容器交互 1.2.5、容器停止 1.2.6、扩展 1.3、综合演示 2、存…

Qt之explicit作用及用法

在 Qt 中,explicit 是一个关键字,用于修饰类构造函数。explicit 的主要作用是防止隐式类型转换,即禁止编译器使用该构造函数进行隐式类型转换。 在 C 中,当一个构造函数只接受一个参数的时候,它可能会被用于执行隐式类…

网络安全与IP地址:构建数字世界的前沿堡垒

网络安全是当今数字社会中不可忽视的挑战之一。而IP地址,作为互联网通信的基础协议,既是数字化时代的桥梁,也是网络安全的关键节点。本文将剖析IP地址在网络安全领域的作用,以及如何利用其特性建立有效的网络安全策略。 IP地址&a…