【问题标题】:Add custom field to Hibernate Envers revision table (revinfo), like operation_id. Which is a PK of Operation entity将自定义字段添加到 Hibernate Envers 修订表 (revinfo),如 operation_id。哪个是操作实体的PK
【发布时间】: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());
        }

    }

}

【问题讨论】:

    标签: java spring-boot spring-data-jpa audit hibernate-envers


    【解决方案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());
      

      【讨论】:

        猜你喜欢
        • 2012-01-04
        • 2014-07-03
        • 2015-05-05
        • 2014-12-01
        • 1970-01-01
        • 2021-04-06
        • 1970-01-01
        • 2010-10-28
        • 2018-09-22
        相关资源
        最近更新 更多