将自定义字段添加到 Hibernate Envers 修订表 (revinfo),如 operation_id。哪个是操作实体的PK

Posted

技术标签:

【中文标题】将自定义字段添加到 Hibernate Envers 修订表 (revinfo),如 operation_id。哪个是操作实体的PK【英文标题】:Add custom field to Hibernate Envers revision table (revinfo), like operation_id. Which is a PK of Operation entity 【发布时间】:2021-09-09 02:48:07 【问题描述】:

您好,我想知道是否可以将像 Operation_id 这样的自定义字段添加到 revinfo 表中,该字段将具有自定义操作,如 ADD_TRAVEL_OP。这些操作应该在每个端点中静态或动态设置。

@Entity
@Table(name = "revinfo")
@RevisionEntity(AuditRevisionListener.class)
public class AuditRevisionEntity extends DefaultRevisionEntity implements Serializable 

    @Column(name = "rev")
    private int revision;

    private String username;

    private String operationId;

    public int getRevision() 
        return revision;
    

    public void setRevision(final int revision) 
        this.revision = revision;
    

    public String getUsername() 
        return username;
    

    public void setUsername(final String userName) 
        this.username = userName;
    

    public String getOperationId() 
        return operationId;
    

    public void setOperationId(final String operationId) 
        this.operationId = operationId;
    
@Configuration
public class AuditRevisionListener implements RevisionListener 

    @Override
    public void newRevision(Object revisionEntity) 
        final AuditRevisionEntity are = (AuditRevisionEntity) revisionEntity;
        final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication instanceof UserDetails) 
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
            are.setUsername(userDetails.getUsername());
         else 
            are.setUsername(authentication.getName());
        

    


【问题讨论】:

【参考方案1】:

当然,您可以向 AuditRevisionEntity 添加字段。诀窍是您必须有权访问 AuditRevisionListener 中的数据。我要求某些操作需要在审计跟踪 (AuditRevisionEntity) 中记录更改原因。我最终使用本地线程来存储更改原因,使用本地线程在 AuditRevisionListener 中设置更改原因,并在事务开始或完成时清除本地线程。

JpaTransactionManager 实现:

public class AuditingJpaTransactionManager extends JpaTransactionManager 
  private final AuditContextHolder auditContextHolder = new AuditContextHolder();
  
  public AuditingJpaTransactionManager() 
    super();
  

  public AuditingJpaTransactionManager(EntityManagerFactory emf) 
    super(emf);
  
  
  @Override
  protected void doBegin(Object transaction, TransactionDefinition definition) 
    this.auditContextHolder.clearContext();
    super.doBegin(transaction, definition);
  

  @Override
  protected void doCleanupAfterCompletion(Object transaction) 
    this.auditContextHolder.clearContext();
    super.doCleanupAfterCompletion(transaction);
  

线程本地实现:

public class AuditContextHolder 
  private static final ThreadLocal<AuditContext> contextHolder = new ThreadLocal<>();
  
  public void clearContext() 
    contextHolder.remove();
  
  
  public AuditContext getContext() 
    AuditContext ctx = contextHolder.get();
    
    if (ctx == null) 
      ctx = new AuditContext();
      contextHolder.set(ctx);
    
    
    return ctx;
  
  
  @NoArgsConstructor
  public static class AuditContext 
    @Getter
    @Setter
    private String reasonForChange;
  

【讨论】:

【参考方案2】:

所以在 Lee Greiner 的帮助下,我实现了我的目标。我会把剩下的留在这里,这很明显,但仍然可以帮助其他人。

//update to what i already had
public class AuditRevisionListener implements RevisionListener 

    @Override
    public void newRevision(Object revisionEntity) 

        final AuditRevisionEntity are = (AuditRevisionEntity) revisionEntity;
        final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication instanceof UserDetails) 
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();
            are.setUsername(userDetails.getUsername());
         else 
            are.setUsername(authentication.getName());
        
        String operationId = new AuditContextHolder().getContext().getOperationId();
        if(operationId == null) operationId = Operation.NOT_DEFINED.name();
        are.setOperationId(operationId);
    


//Set the desired Operation before the save point
new AuditContextHolder()
.getContext()
.setOperationId(Operation.LOGIN_OP.name());

【讨论】:

以上是关于将自定义字段添加到 Hibernate Envers 修订表 (revinfo),如 operation_id。哪个是操作实体的PK的主要内容,如果未能解决你的问题,请参考以下文章

Netsuite 将自定义字段添加到交易列字段

使用 paypal 节点 sdk 将自定义字段添加到计费协议

Drupal,Ubercart - 将自定义字段添加到结帐表单

DRF,将自定义字段添加到 ModelSerializer

php 将自定义字段内容添加到菜单项

Django Allauth - 如何将自定义 CSS 类添加到字段?