使用Spring Boot 2和Spring Data JPA实现审计

  在本文中,我们将讨论如何配置JPA以自动持久保存任何实体的CreatedBy,CreatedDate,LastModifiedBy和LastModifiedDate标注的字段列。我们将创建一个简单的Spring Boot CRUD REST API,并使用spring数据JPA实现审计。

  在任何业务应用程序中,审计意味着跟踪和记录我们在持久记录中所做的每一项更改,这意味着跟踪每个插入,更新和删除操作并存储它。审计有助于我们维护历史记录,以后可以帮助我们跟踪用户操作系统的活动。

  这样就不需要在每次保存,更新或删除操作上进行手动编写代码,我们完全可以使用第三方库自动执行。Spring Data提供了复杂的支持,可以透明地跟踪创建或更改实体的人员以及发生这种情况的时间点。

  首先必须为实体类配备审计元数据,该元数据可以使用注释或通过实现接口来定义。在此示例中,我们将使用审计字段创建一个通用的通用Auditable抽象类,以便任何实体都可以扩展它以使用审计。

  直接使用JPA依赖即可:

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

 

  使用Spring数据注释创建通用可审计类@CreatedBy,@ CreatedDate,@ LastModifiedBy和@LastModifiedDate:

@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class Auditable<U> {

@CreatedBy
protected U createdBy;

@CreatedDate
@Temporal(TIMESTAMP)
protected Date createdDate;

@LastModifiedBy
protected U lastModifiedBy;

@LastModifiedDate
@Temporal(TIMESTAMP)
protected Date lastModifiedDate;

public U getCreatedBy() {
return createdBy;
}

public void setCreatedBy(U createdBy) {
this.createdBy = createdBy;
}

public Date getCreatedDate() {
return createdDate;
}

public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}

public U getLastModifiedBy() {
return lastModifiedBy;
}

public void setLastModifiedBy(U lastModifiedBy) {
this.lastModifiedBy = lastModifiedBy;
}

public Date getLastModifiedDate() {
return lastModifiedDate;
}

public void setLastModifiedDate(Date lastModifiedDate) {
this.lastModifiedDate = lastModifiedDate;
}
}
让我们理解重要的JPA审核注释:
  1. @CreatedDate - 声明一个字段,表示创建包含该字段的实体的日期。
  2. @LastModifiedDate - 声明一个字段,表示最近修改了包含该字段的实体的日期。
  3. @CreatedBy - 声明一个字段,表示创建包含该字段的实体的主体。
  4. @LastModifiedBy - 声明一个字段,表示最近修改包含该字段的实体的主体。

使用带有@EntityListeners的AuditingEntityListener类,Spring Data JPA提供了一个JPA实体监听器类AuditingEntityListener,它包含回调方法(使用@PrePersist@PreUpdate注释),当我们将持久化或更新我们的实体时,它将用于持久化和更新这些属性。

JPA提供了@EntityListeners注释来指定回调监听器类,我们用它来注册我们的AuditingEntityListener类。

JPA可以使用当前系统时间分析createdDate和lastModifiedDate,但是createdBy和lastModifiedBy字段呢?JPA将如何识别存储在其中的内容?

要告诉JPA当前登录的用户,我们需要提供AuditorAware的实现并覆盖getCurrentAuditor()方法。在getCurrentAuditor()中,我们需要获取当前登录的用户。

提供了一个硬编码用户,但是如果你使用的是Spring Security,则可用它来查找当前登录的用户。

public class AuditorAwareImpl implements AuditorAware<String> {

@Override
public Optional<String> getCurrentAuditor() {
return Optional.of("Ramesh");
// Use below commented code when will use Spring Security.
}
}

// ------------------ Use below code for spring security --------------------------

/*class SpringSecurityAuditorAware implements AuditorAware<User> {

public User getCurrentAuditor() {

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

if (authentication == null || !authentication.isAuthenticated()) {
return null;
}

return ((MyUserDetails) authentication.getPrincipal()).getUser();
}
}*/

 

  现在,我们可以创建一个业务JPA实体继承上面Auditable类:

@Entity
@Table(name = "users")
@EntityListeners(AuditingEntityListener.class)
public class User extends Auditable<String> {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;

@Column(name = "first_name", nullable = false)
private String firstName;

@Column(name = "last_name", nullable = false)
private String lastName;

@Column(name = "email_address", nullable = false)
private String emailId;


public long getId() {
return id;
}

public void setId(long id) {
this.id = id;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getEmailId() {
return emailId;
}

public void setEmailId(String emailId) {
this.emailId = emailId;
}
}

 

指定@EnableJpaAuditing来启用JPA审计:

@SpringBootApplication
@EnableJpaAuditing(auditorAwareRef = "auditorAware")
public class Springboot2JpaAuditingApplication {

@Bean
public AuditorAware<String> auditorAware() {
return new AuditorAwareImpl();
}

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

 

现在,我们完成了所有JPA审计的主要设置。

源码连接Github

Spring Boot