SpringBoot实现公共字段自动填充的方法步骤

 更新时间:2024年11月17日 13:53:37   作者:Oneforlove_twoforjob  
这篇文章主要介绍了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 INSERT
    OperationType 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();// 拿到实现类的签名信息,不过我们只需要方法的签名信息,强转成MethodSignature
        AutoFill 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 时可能会抛出类型转换异常。

到此这篇关于SpringBoot实现公共字段自动填充的方法步骤的文章就介绍到这了,更多相关SpringBoot公共字段自动填充内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • IDEA2021常用优化设置步骤图解

    IDEA2021常用优化设置步骤图解

    本文分步骤给大家讲解IDEA2021常用优化设置技巧,非常不错,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2021-09-09
  • 利用java制作简单的音乐播放器

    利用java制作简单的音乐播放器

    这篇文章主要为大家详细介绍了利用java的swing技术制作简单的音乐播放器,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • java使用TimeZone将中国标准时间转成时区值

    java使用TimeZone将中国标准时间转成时区值

    这篇文章主要介绍了java使用TimeZone将中国标准时间转成时区值的相关资料,需要的朋友可以参考下
    2023-11-11
  • SpringBoot中Lombok注解失效的解决方案

    SpringBoot中Lombok注解失效的解决方案

    文章介绍了在使用SpringBoot 4.0.3版本时遇到Lombok依赖不生效的问题,通过排查发现是由于IDEA的Maven插件配置问题导致的,通过注释掉pom.xml文件中的所有插件配置,问题解决,需要的朋友可以参考下
    2026-03-03
  • 使用Java实现创建Excel表单控件

    使用Java实现创建Excel表单控件

    在数据填报时,创建Excel表单控件是一项常见的任务,它可以极大地简化数据收集和处理的过程,本文主要介绍了如何使用Java实现创建Excel表单控件,感兴趣的可以了解下
    2024-03-03
  • Java实现猜数字小游戏代码

    Java实现猜数字小游戏代码

    大家好,本篇文章主要讲的是Java实现猜数字小游戏代码,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • 浅谈Java父子类加载顺序

    浅谈Java父子类加载顺序

    本文主要介绍了Java父子类加载顺序,那么这么长怎么记呀?本文就帮大家总结一下,更有利于记忆,感兴趣的可以了解一下
    2021-08-08
  • java如何发送get请求获取数据(附代码)

    java如何发送get请求获取数据(附代码)

    这篇文章主要给大家介绍了关于java如何发送get请求获取数据的相关资料,Java中的GET请求方法是HTTP协议中的一种请求方式,用于向服务器请求获取资源,需要的朋友可以参考下
    2023-10-10
  • Java实现基于UDP协议的网络通信UDP编程

    Java实现基于UDP协议的网络通信UDP编程

    在Java中使用UDP编程,仍然需要使用Socket,因为应用程序在使用UDP时必须指定网络接口(IP地址)和端口号。注意:UDP端口和TCP端口虽然都使用0~65535,但他们是两套独立的端口,即一个应用程序用TCP占用了端口1234,不影响另一个应用程序用UDP占用端口1234
    2023-04-04
  • 在Window系统下安装Netbeans9的方法

    在Window系统下安装Netbeans9的方法

    今天小编就为大家分享一篇关于在Window系统下安装Netbeans9的方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12

最新评论