基于Spring Data的AuditorAware审计功能的示例代码

yizhihongxing

下面我将详细讲解如何实现基于Spring Data的AuditorAware审计功能,并提供两个示例代码。

什么是AuditorAware?

AuditorAware 是 Spring Data JPA 开始支持的一个新的特性,它可以用于在执行 CRUD 操作时自动更新实体中的 Auditor 相关信息(比如 create_by, last_modified_by 等)。AuditorAware 接口的实现类可以返回一个当前要使用的 Auditor,而 Auditor 则可以是任意对象,比如实体、登录用户等等。

第一个示例

首先,我们需要在 pom.xml 中添加 Spring Data JPA 和 Spring Boot Web 依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

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

接着,我们需要创建一个实体类 User,这个实体类包含 id、name、createdBy 和 updatedBy 四个字段,并使用 @EntityListeners 注解标注,用来指定使用 JpaAuditingEntityListener 进行实体审计。

@Entity
@EntityListeners(AuditingEntityListener.class)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(name = "created_by")
    @CreatedBy
    private String createdBy;

    @Column(name = "updated_by")
    @LastModifiedBy
    private String updatedBy;

    // setter 和 getter 省略
}

然后,我们需要添加一个 AuditorAware 实现类,这个实现类需要实现 getCurrentAuditor() 方法,该方法返回一个 Optional 类型的 Auditor 对象。

@Component
public class UserAuditorAware implements AuditorAware<String> {

    @Override
    public Optional<String> getCurrentAuditor() {
        // 获取当前登录用户
        String currentUser = SecurityContextHolder.getContext().getAuthentication().getName();
        return Optional.ofNullable(currentUser);
    }
}

注意,这个实现类需要使用 @Component 注解进行标注,让 Spring Boot 自动扫描并注入到容器中。

最后,我们需要在启动类上添加 @EnableJpaAuditing 注解,启用 JPA 审计功能。

@SpringBootApplication
@EnableJpaAuditing(auditorAwareRef = "userAuditorAware")
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

启动程序,在数据库中创建 user 表,执行 insert 操作,然后查看数据库中的数据,可以看到 createdBy 和 updatedBy 字段都被填充上了当前登录用户。

第二个示例

现在我们来看一个更复杂的示例。假设我们有两个实体类 Book 和 Author,它们之间是一对多的关系。我们需要在操作 Book 的同时,自动更新 Author 中对应字段的值。

首先,我们来创建 Author 实体类,包含 id、name、updatedBy 字段。

@Entity
public class Author {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(name = "updated_by")
    @LastModifiedBy
    private String updatedBy;

    // getter 和 setter 省略
}

接着,我们创建 Book 实体类,包含 id、name 和 author_id 三个字段。在该实体类中使用 @ManyToOne 注解来建立 Book 和 Author 之间的关联关系,并使用 @EntityListeners 注解指定使用 AuditingEntityListener 进行实体审计。

@Entity
@EntityListeners(AuditingEntityListener.class)
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @ManyToOne
    @JoinColumn(name = "author_id")
    private Author author;

    // getter 和 setter 省略
}

然后,我们需要添加一个 AuditorAware 实现类 AuthorAuditorAware,它负责在更新 Book 时自动更新 Author 的 updatedBy 字段。

@Component
public class AuthorAuditorAware implements AuditorAware<String> {

    @Autowired
    private EntityManager entityManager;

    @Override
    public Optional<String> getCurrentAuditor() {
        // 获取当前登录用户
        String currentUser = SecurityContextHolder.getContext().getAuthentication().getName();

        // 获取 JPA 审计器
        JpaMetamodelEntityInformation<Book, ?> bookEntityInformation =
                (JpaMetamodelEntityInformation<Book, ?>) JpaEntityInformationSupport.getEntityInformation(Book.class, entityManager);
        JpaEntityInformation<Author, ?> authorEntityInformation =
                JpaEntityInformationSupport.getEntityInformation(Author.class, entityManager);
        JpaEntityInformation<Object, Serializable> entityInformation =
                (JpaEntityInformation<Object, Serializable>) authorEntityInformation.getMetadata()
                        .getDeclaredAssociationMappings().stream()
                        .filter(mappings -> mappings.getOwnerEntityClass().equals(bookEntityInformation.getJavaType())
                                && mappings.getMappedBy().equals("author"))
                        .findFirst()
                        .orElseThrow(() -> new IllegalStateException("Audited property not found."));

        // 获取当前操作的 Book 实例
        Book book = null;
        Object[] states = entityManager.getEntityManagerFactory()
                .getPersistenceUnitUtil()
                .getIdentifier(bookEntityInformation.getEntity(new Book()), null);
        if (states != null) {
            Serializable bookId = (Serializable) states[0];
            book = entityManager.find(Book.class, bookId);
        }

        // 更新 Author 的 updatedBy 字段
        if (book != null) {
            Author author = book.getAuthor();
            if (author != null && authorEntityInformation.hasCompositeId()) {
                entityInformation.getId(author);
                author.setUpdatedBy(currentUser);
            } else if (author != null) {
                author.setUpdatedBy(currentUser);
            }
            return Optional.ofNullable(currentUser);
        }

        return Optional.empty();
    }
}

注意,这个实现类需要使用 @Component 注解进行标注,让 Spring Boot 自动扫描并注入到容器中。

最后,我们需要在启动类上指定 auditorAwareRef,即使用 AuthorAuditorAware 进行审计:

@SpringBootApplication
@EnableJpaAuditing(auditorAwareRef = "authorAuditorAware")
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

启动程序,在数据库中创建 author 和 book 表,执行 insert 操作,然后查看数据库中的数据,可以看到 Author 中的 updatedBy 字段已经被自动更新。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:基于Spring Data的AuditorAware审计功能的示例代码 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • zookeeper实现分布式锁

    下面我将详细讲解如何使用zookeeper实现分布式锁。 什么是分布式锁? 分布式锁是一种用于控制分布式系统之间访问共享资源的机制。例如,在分布式系统中使用共享资源时,需要确保在任何时刻只有一个节点能够持有该资源。在这种情况下,分布式锁可以防止多个节点同时访问共享资源,从而保证系统的正确性和稳定性。 ZooKeeper简介 ZooKeeper是由Apache…

    Java 2023年5月20日
    00
  • 算法系列15天速成 第八天 线性表【下】

    算法系列15天速成 第八天 线性表【下】完整攻略 前言 在线性表【上】的基础上,我们再来讲一些新的线性表特性及其相关算法。 栈 栈是一种特殊的线性表,只能在表尾插入和删除数据,简单来说就是类似于装东西的箱子。它有以下几个特点: 先进后出,后进先出,即最先入栈的元素最后出栈; 只能在表尾插入和删除数据,元素的加入和删除只发生在栈顶。 栈的应用 递归; 计算器;…

    Java 2023年5月31日
    00
  • 替换jar包未重启引起的系统宕机事件

    一、事件背景: 某天凌晨,一阵急促的铃声将我从周公那里拉了过来,接听电话后,一脸懵逼。 什么情况?XX后台宕机了?当日日志也不打印了,前端发起的请求,都报超时,重启后又恢复了,不清楚会不会再次宕机。 出现这种情况,我第一时间想的是为什么是00:00:00宕机?难道后台嫌我这个大龄程序员睡得早了? 然后是通过远程视频,看日志,排查了凌晨之前的日志里的所有异常,…

    Java 2023年4月18日
    00
  • 解决idea中Terminal终端无法执行GIT命令+Terminal 中文乱码问题

    解决idea中Terminal终端无法执行GIT命令+Terminal 中文乱码问题的攻略如下: 问题一:解决idea中Terminal终端无法执行GIT命令 问题描述 在IDEA中使用Terminal终端时,执行git命令时出现如下错误提示: -bash: git: command not found 导致无法正常使用git命令。 解决方法 经过排查发现,…

    Java 2023年5月20日
    00
  • Java中的Runnable接口是什么?

    Java中的Runnable接口是一种用于定义线程任务的接口。该接口中只包含一个run()方法,线程通过调用该方法来执行任务。与继承Thread类相比,实现Runnable接口可以更好地体现面向对象的设计模式,并且可以让任务更加灵活地执行。 public interface Runnable { public abstract void run(); } 在…

    Java 2023年4月27日
    00
  • Java、JavaScript、Oracle、MySQL中实现的MD5加密算法分享

    Java、JavaScript、Oracle、MySQL中实现的MD5加密算法分享 简介 MD5是一种常用的密码加密算法,用于将用户输入的密码在存储到数据库中之前进行加密,保证密码的安全性。该算法将任意长度的“消息”(message)表示为一个128位的“消息摘要”(message digest),常用来保证信息传输的完整性和单向加密。 在本篇文章中,我们将…

    Java 2023年5月20日
    00
  • Java8 Stream 流常用方法合集

    Java8 Stream 流常用方法合集 Java 8 引入了一种新的抽象数据类型 Stream,它让数据的操作变得更加简单高效。Stream 可以是一组数据的集合、数组等等,它支持多方面的操作,比如过滤、映射、筛选、分组、去重、排序等等。下面将介绍 Java8 Stream 常用的方法。 创建流 从集合创建流:可以将一个集合转换为流,并对流中的元素进行操作…

    Java 2023年5月26日
    00
  • Java构造方法有什么作用?

    Java中的构造方法是一个特殊的方法,它与类的名称相同,且没有返回类型。它主要用于在创建对象时对对象进行初始化操作,也可以用于为一个类的成员变量赋值。构造方法的作用可以总结为以下两点: 1. 对象的初始化 构造方法在创建对象时被调用,用于对对象进行初始化。在Java中,通过关键字new来创建对象时,其实就是创建了这个类的一个实例,同时也创建了一个隐式的构造方…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部