如何在Spring JPA Auditing中存储lastModifiedBy的用户列表
实现Spring JPA Audit存储所有编辑用户的可行方案
针对你需要将lastModifiedBy扩展为存储所有编辑用户列表的需求,结合PostgreSQL数据库,提供以下三种可行方案:
方案一:基于PostgreSQL数组类型直接存储
利用PostgreSQL原生的数组类型,在主实体中维护编辑用户列表,每次更新时追加当前用户。
1. 修改抽象审计类
替换原lastModifiedBy字段为用户列表,指定PostgreSQL数组类型的列定义:
@Data @MappedSuperclass @EntityListeners({AuditingEntityListener.class, ModifiedByEntityListener.class}) public abstract class Auditable<T> { @CreatedBy @Column(updatable = false) protected T createdBy; @Temporal(TemporalType.TIMESTAMP) @CreationTimestamp @Column(updatable = false) protected Date createdDate; // 存储所有编辑用户的数组,这里以String类型用户ID为例,若为Long则用bigint[] @Column(columnDefinition = "text[]") protected List<T> modifiedByUsers; @Temporal(TemporalType.TIMESTAMP) @UpdateTimestamp protected Date lastModifiedDate; }
2. 自定义实体监听器实现追加逻辑
编写监听器在实体创建和更新时,将当前用户加入列表(可选择去重):
@Component public class ModifiedByEntityListener { @Autowired private AuditorAware<String> auditorAware; @PrePersist public void prePersist(Auditable<String> entity) { String currentUser = auditorAware.getCurrentAuditor().orElse(null); if (currentUser != null) { List<String> users = new ArrayList<>(); users.add(currentUser); entity.setModifiedByUsers(users); } } @PreUpdate public void preUpdate(Auditable<String> entity) { String currentUser = auditorAware.getCurrentAuditor().orElse(null); if (currentUser != null) { List<String> users = Optional.ofNullable(entity.getModifiedByUsers()).orElse(new ArrayList<>()); // 可选:避免同一用户多次编辑重复存储 if (!users.contains(currentUser)) { users.add(currentUser); } entity.setModifiedByUsers(users); } } }
3. 确保AuditorAware配置正常
你需要已实现AuditorAware来获取当前登录用户,例如基于Spring Security的实现:
@Component public class SecurityAuditorAware implements AuditorAware<String> { @Override public Optional<String> getCurrentAuditor() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth == null || !auth.isAuthenticated()) { return Optional.empty(); } return Optional.of(auth.getName()); } }
方案二:独立审计日志表(推荐用于复杂审计场景)
创建单独的审计日志表,记录每个实体的所有修改操作及用户信息,避免主表字段冗余。
1. 定义审计日志实体
@Entity @Table(name = "entity_audit_log") @Data public class EntityAuditLog { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "entity_type") private String entityType; @Column(name = "entity_id") private String entityId; @Column(name = "modified_by") private String modifiedBy; @Temporal(TemporalType.TIMESTAMP) private Date modifiedDate; @Column(name = "operation_type") private String operationType; // CREATE/UPDATE/DELETE }
2. 自定义监听器插入审计日志
@Component public class EntityAuditListener { @Autowired private EntityManager entityManager; @Autowired private AuditorAware<String> auditorAware; @PrePersist public void prePersist(Object entity) { saveAuditLog(entity, "CREATE"); } @PreUpdate public void preUpdate(Object entity) { saveAuditLog(entity, "UPDATE"); } @PreRemove public void preRemove(Object entity) { saveAuditLog(entity, "DELETE"); } private void saveAuditLog(Object entity, String operationType) { String currentUser = auditorAware.getCurrentAuditor().orElse("anonymous"); EntityAuditLog log = new EntityAuditLog(); log.setEntityType(entity.getClass().getSimpleName()); // 获取实体ID,假设实体有getId()方法 try { Method getIdMethod = entity.getClass().getMethod("getId"); log.setEntityId(getIdMethod.invoke(entity).toString()); } catch (Exception e) { log.setEntityId("unknown"); } log.setModifiedBy(currentUser); log.setModifiedDate(new Date()); log.setOperationType(operationType); entityManager.persist(log); } }
3. 更新抽象审计类
将监听器添加到Auditable类,可移除原lastModifiedBy字段:
@Data @MappedSuperclass @EntityListeners({AuditingEntityListener.class, EntityAuditListener.class}) public abstract class Auditable<T> { @CreatedBy @Column(updatable = false) protected T createdBy; @Temporal(TemporalType.TIMESTAMP) @CreationTimestamp @Column(updatable = false) protected Date createdDate; @Temporal(TemporalType.TIMESTAMP) @UpdateTimestamp protected Date lastModifiedDate; }
方案三:使用Hibernate Envers实现完整审计
Hibernate Envers是官方审计框架,自动记录实体所有修改版本及相关审计信息。
1. 添加依赖
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-envers</artifactId> </dependency>
2. 配置自定义修订实体和监听器
首先定义包含修改用户的修订实体:
@Entity @RevisionEntity(CustomRevisionListener.class) @Data public class CustomRevisionEntity extends DefaultRevisionEntity { private String modifiedBy; }
然后实现修订监听器填充用户信息:
public class CustomRevisionListener implements RevisionListener { @Override public void newRevision(Object revisionEntity) { CustomRevisionEntity revision = (CustomRevisionEntity) revisionEntity; Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.isAuthenticated()) { revision.setModifiedBy(auth.getName()); } else { revision.setModifiedBy("anonymous"); } } }
3. 启用实体审计
在Auditable类添加@Audited注解,让所有继承的实体自动开启审计:
@Data @MappedSuperclass @EntityListeners(AuditingEntityListener.class) @Audited public abstract class Auditable<T> { // 原有字段保持不变 }
4. 查询审计历史
通过AuditReader获取实体的所有修订版本及对应的修改用户:
AuditReader auditReader = AuditReaderFactory.get(entityManager); List<Number> revisions = auditReader.getRevisions(YourEntity.class, entityId); for (Number rev : revisions) { CustomRevisionEntity revision = auditReader.findRevision(CustomRevisionEntity.class, rev); String modifiedBy = revision.getModifiedBy(); Date modifiedDate = revision.getRevisionDate(); // 获取对应版本的实体数据 YourEntity entityVersion = auditReader.find(YourEntity.class, entityId, rev); }
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

