使用Spring Data JPA实现审计功能,记录创建人、创建时间、最后修改时间和最后修改人
前言
近日心血来潮想做一个开源项目,目标是做一款可以适配多端、功能完备的模板工程,包含后台管理系统和前台系统,开发者基于此项目进行裁剪和扩展来完成自己的功能开发。
本项目为前后端分离开发,后端基于Java21
和SpringBoot3
开发,后端使用Spring Security
、JWT
、Spring Data JPA
等技术栈,前端提供了vue
、angular
、react
、uniapp
、微信小程序
等多种脚手架工程。
在项目中每条数据在创建或修改的时候,我想记录创建人,创建时间,最后修改人,最后修改时间等审计信息。如果每次都手动赋值,代码会变得冗长,显得很不优雅。Spring Data JPA
为我们提供了审计功能,可以在执行创建或修改操作时自动为审计信息赋值。
本文将介绍两种实现方式,关于SpringBoot项目如何整合Spring Data JPA,请参阅blog.csdn.net/kingslave1/…
实现方式
使用Spring Data JPA实现审计功能,主要涉及以下注解:
@EnableJpaAuditing
,启用JPA审计功能开关。@EntityListeners
,可以监听实体对象的增删改查操作,调用监听器中设置的回调方法。@CreatedBy
,创建人,执行insert
操作时自动赋值。@CreatedDate
,创建日期,执行insert
操作时自动赋值。@LastModifiedBy
,最后修改人,执行insert
或update
操作时自动赋值。@LastModifiedDate
,最后修改时间,执行insert
或update
操作时自动赋值。
基于AuditorAware
接口实现审计功能
启用JPA审计功能
定义一个配置类Bean,启用Spring Data JPA和审计功能,也可以直接main方法所在类上直接添加@EnableJpaRepositories
、@EntityScan
和@EnableJpaAuditing
注解。
/**
* Spring Data JPA Bean配置
* 启用Jpa,扫描指定包下的Repository类和指定包下的实体类
*/
@Configuration
@EnableJpaRepositories(basePackages = {"com.demo.data.repo"})
@EntityScan(basePackages = "com.demo.data.model")
@EnableJpaAuditing
public class JpaConfig {
}
定义实体类
以定义一个用户类SysUser
为例,为其添加@EntityListeners({AuditingEntityListener.class})
注解,在其审计信息属性上添加@CreatedBy
等注解。
@Getter
@Setter
@Entity
@EntityListeners({AuditingEntityListener.class})
public class SysUser implements Serializable {
/**
* ID,唯一标识列,使用主键自增策略
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 创建时间
*/
@CreatedDate
private LocalDateTime createdTime;
/**
* 最后修改时间
*/
@LastModifiedDate
private LocalDateTime lastModifiedTime;
/**
* 创建人ID
*/
@CreatedBy
private Long creatorId;
/**
* 最后修改人ID
*/
@LastModifiedBy
private Long lastModifierId;
/**
* 用户名
*/
@Column(unique = true)
private String username;
/**
* 密码
*/
private String password;
/**
* 电话
*/
private String phone;
}
实现AuditorAware
接口
我们需要定义一个AuditorAware
接口的实现类,并将其注册为Bean。
实现AuditorAware<T>
接口需要传递类型参数,这个参数应使用创建人(creatorId)
和最后修改人(lastModifierId)
属性的类型,在实体类SysUser
中creatorId
和lastModifierId
的类型是Long
,则此处泛型参数也应该为Long
。
@Component
public class AuditorAwareImpl implements AuditorAware<Long> {
/**
* 返回当前用户ID,insert和update操作会调用该方法自动赋值
*/
@Override
public Optional<Long> getCurrentAuditor() {
// 获取当前用户Id,具体获取逻辑请自行实现
Long userId = 1L;
return Optional.ofNullable(userId);
}
}
至此,审计功能开发完成,可调用SysUser
类的Repository
接口执行创建或修改操作来测试是否开发成功。
基于自定义监听器实现审计功能
基于AuditorAware
接口实现审计功能虽然简单,但也存在不适用的场景,例如创建人
属性不仅要记录创建人的用户ID,还需要记录创建人的用户名时;或者开发者希望仅在insert
操作时执行某些操作。
针对上述场景,可以考虑使用自定义实体操作监听器的方式实现,实现步骤如下。
启用JPA审计功能
定义一个配置类Bean,启用Spring Data JPA和审计功能,也可以直接main方法所在类上直接添加@EnableJpaRepositories
、@EntityScan
和@EnableJpaAuditing
注解。
/**
* Spring Data JPA Bean配置
* 启用Jpa,扫描指定包下的Repository类和指定包下的实体类
*/
@Configuration
@EnableJpaRepositories(basePackages = {"com.demo.data.repo"})
@EntityScan(basePackages = "com.demo.data.model")
@EnableJpaAuditing
public class JpaConfig {
}
定义实体类
以定义一个用户类SysUser
为例,为其添加@EntityListeners({AuditingEntityListener.class, CustomEntityAuditingListener.class})
注解,在其审计信息属性上添加@CreatedBy
等注解。
与1.2一节中给出的实体类相比,新增了creator
,lastModifier
两个属性,@EntityListeners
注解中多了一个CustomEntityAuditingListener
,在下一节中笔者将给出CustomEntityAuditingListener
的实现代码。
@Getter
@Setter
@Entity
@EntityListeners({AuditingEntityListener.class, CustomEntityAuditingListener.class})
public class SysUser implements Serializable {
/**
* ID,唯一标识列,使用主键自增策略
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
* 创建时间
*/
@CreatedDate
private LocalDateTime createdTime;
/**
* 最后修改时间
*/
@LastModifiedDate
private LocalDateTime lastModifiedTime;
/**
* 创建人ID
*/
@CreatedBy
private Long creatorId;
/**
* 创建人用户名
*/
private String creator;
/**
* 最后修改人ID
*/
@LastModifiedBy
private Long lastModifierId;
/**
* 最后修改人用户名
*/
private Long lastModifier;
/**
* 用户名
*/
@Column(unique = true)
private String username;
/**
* 密码
*/
private String password;
/**
* 电话
*/
private String phone;
}
定义自定义监听器类
自定义监听器会用到以下几种注解,可以监听数据库操作的不同时机。
@PostLoad
,实体对象查询之后@PrePersist
,实体对象保存之前@PostPersist
,实体对象保存之后@PreUpdate
,实体对象修改之前@PostUpdate
,实体对象修改之后@PreRemove
,实体对象删除之前@PostRemove
,实体对象删除之后
以下是CustomEntityAuditingListener
类的实现代码,使用了@PrePersist
和@PreUpdate
两个注解。
public class CustomEntityAuditingListener {
@PrePersist
private void prePersist(BaseEntity entity) {
// 获取当前用户,具体获取逻辑请自行实现
SysUser current = new SysUser();
entity.setCreatorId(current.getId());
entity.setCreator(current.getUsername());
entity.setLastModifierId(current.getId());
entity.setLastModifier(current.getUsername());
}
<span class="hljs-meta">@PreUpdate</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">preUpdate</span><span class="hljs-params">(BaseEntity entity)</span> {
<span class="hljs-comment">// 获取当前用户,具体获取逻辑请自行实现</span>
<span class="hljs-type">SysUser</span> <span class="hljs-variable">current</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">SysUser</span>();
entity.setLastModifierId(current.getId());
entity.setLastModifier(current.getUsername());
}
}
至此,审计功能开发完成,可调用SysUser
类的Repository
接口执行创建或修改操作来测试是否开发成功。
总结
本文介绍了两种使用Spring Data JPA实现审计功能的方法,实现AuditorAware
接口和自定义实体操作监听器,可以在创建或修改数据时自动为审计信息赋值,减少了冗长的手动赋值代码,如有错误,还望批评指正。
在后续实践中我也是及时更新自己的学习心得和经验总结,希望与诸位看官一起进步。