在 Spring Hibernate java 项目中使用“Envers”审计表

Posted

技术标签:

【中文标题】在 Spring Hibernate java 项目中使用“Envers”审计表【英文标题】:Audit table using "Envers" in Spring Hibernate java project 【发布时间】:2015-03-14 21:42:29 【问题描述】:

我们需要使用 envers 来审计现有的表。我们没有hibernate.xml,而不是使用application-context.xml。我们正在通过“liquibase-changeset”创建模式,那么我如何通过@Entity 和@Audited 等注释创建。

我该如何解决这个问题?

我已经添加了休眠配置喜欢

<property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.mysqlInnoDBDialect</prop>
                <prop key="hibernate.ejb.event.post-insert">org.hibernate.ejb.event.EJB3PostInsertEventListener,org.hibernate.envers.event.AuditEventListener</prop>
                <prop key="hibernate.ejb.event.post-update">org.hibernate.ejb.event.EJB3PostUpdateEventListener,org.hibernate.envers.event.AuditEventListener</prop>
                <prop key="hibernate.ejb.event.post-delete">org.hibernate.ejb.event.EJB3PostDeleteEventListener,org.hibernate.envers.event.AuditEventListener</prop>
                <prop key="hibernate.ejb.event.pre-collection-update">org.hibernate.envers.event.AuditEventListener</prop>
                <!-- <prop key="hibernate.ejb.event.pre-collection-remove">org.hibernate.envers.event.AuditEventListener</prop>
                <prop key="hibernate.ejb.event.post-collection-recreate">org.hibernate.envers.event.AuditEventListener</prop> -->
                <prop key="org.hibernate.envers.revision_field_name">REV</prop>
                <prop key="org.hibernate.envers.revision_type_field_name">REVTYPE</prop>
                <prop key="org.hibernate.envers.auditTablePrefix"></prop>
                <prop key="org.hibernate.envers.auditTableSuffix">_HISTORY</prop>
                <prop key="hibernate.hbm2ddl.auto">create</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>

在我的域类中添加了@Audited 注释

@Entity
@Audited
@Table(name="user")
public class User implements Serializable 

但是这个配置删除了我现有的表

例如

Mydatabase
-----------

user
product
order_details
user_role
login

我的数据库中有 5 个表。运行我的应用程序后,它显示 3 个表。它不是创建“审计”表,而是删除现有表。

 Mydatabase
  -----------

  user
  product
  order_details

如何在不触及现有表的情况下创建审计(_HISTORY)表???

【问题讨论】:

看这里 (***.com/questions/8573468/…),我前段时间遇到过类似的问题。 是映射到'user_role'和'login'表的对象@Entity? Yes Rohit.. 表用“@Entity”注释 仍然有问题...尚未创建审计表...如何创建审计表?需要在配置中添加什么? @SST 你能让这个运行吗?请看下面我的回答。 【参考方案1】:

尝试从以下位置更改 DDL 策略:

<prop key="hibernate.hbm2ddl.auto">create</prop>

到:

<prop key="hibernate.hbm2ddl.auto">update</prop>

update DDL 生成策略不应删除任何现有表。

【讨论】:

感谢您的回复!!!我已经像这样将“创建”更改为“更新”,但仍然没有创建“审计”表...... :(如何创建审计表??休眠版本:3.6.3.Final,休眠环境版本:3.6 .3.Final 我错过了什么? 尝试将 EnversIntegrator.AUTO_REGISTER 添加为 false 我应该在哪里添加这个“EnversIntegrator.AUTO_REGISTER”设置为假?我的配置文件没有这一行... 你必须将 hibernate.listeners.envers.autoRegister 设置为 false 与其他属性 请阅读docs.jboss.org/hibernate/core/4.2/devguide/en-US/html/ch15.html 15.8。条件审计【参考方案2】:

我正在开发一个使用带有 Hibernate 实现的 JPA 的项目,我们仅使用基于 Spring 上下文 xml 的配置(我们既不使用 persistence.xml)设法使 envers 正常工作。

我们的配置基于 Spring JPA 支持,但您可能会找到类似的解决方案:

    <bean id="projectEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
      </bean>
    </property>
    <property name="packagesToScan">
      <list>
        <value>com.teimas.myproject.bo</value>
        <value>com.teimas.myproject.bo.commons</value>
        <value>com.teimas.myproject.bo.util</value>
      </list>
    </property>
    <property name="persistenceUnitName" value="projectPU" />
    <property name="jtaDataSource" ref="projectDataSourceTarget" />
    <!-- Other ptops for hibernate config -->
    <property name="jpaProperties" ref="jpaHibernateProperties" />
  </bean>
  <util:properties id="jpaHibernateProperties">
    <prop key="hibernate.transaction.jta.platform">
      org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform
    </prop>
    <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
    <!-- validate | update | create | create-drop -->
    <prop key="hibernate.hbm2ddl.auto">validate</prop>
    <prop key="hibernate.show_sql">false</prop>
    <prop key="hibernate.format_sql">false</prop>
    <prop key="javax.persistence.transactionType">JTA</prop>
    <prop key="javax.persistence.validation.mode">AUTO</prop>
  </util:properties>

关键是我们使用 Hibernate 对象作为 JPA 提供者:org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter 并且我们添加 packagesToScan 属性来告诉 hibernate 扫描这些包中的注释。所以 Hibernate 找到 Envers 和 Validation 注释,一切正常。

希望这会有所帮助。

【讨论】:

【参考方案3】:

在 Liquibase 变更集中定义审计表定义,就像对任何其他表一样。

跳过 spring-hibernate ocnfiguration 中的 hibernate.hbm2ddl.auto 属性。这将指示 hibernate 不对架构做任何事情。

保持其余配置不变,这应该可以工作。

只需确保架构和配置中的审计表名称匹配即可。

链接到文档,详细说明如果架构是 generated 使用 ant,它是如何完成的

【讨论】:

同意。除了测试之外,不要将 hbm2ddl 用于任何事情。如果您从一个空模式开始,并且正确启用了 Envers,那么 hbm2ddl.auto=create 应该会生成审计表。这对我有用,但我使用的是 JPA persistence.xml(一个单独的用于测试的)。我使用生成的 DDL 并从中为真实数据库创建 Liquibase 更改集。【参考方案4】:

我遇到了同样的问题,为了解决它,我按照以下步骤操作:

    改变:

    <prop key="hibernate.hbm2ddl.auto">create</prop>
    

到:

    <prop key="hibernate.hbm2ddl.auto">update</prop>

    如果您使用 ENVERS Hibernet-envers 3.5.5 或更高版本,您应该在应用程序上下文中进行此配置:

    <property name="eventListeners">
    <map>
    <entry key="post-insert" >
    <bean class="org.hibernate.envers.event.AuditEventListener" />
    </entry>
    <entry key="post-update">
    <bean class="org.hibernate.envers.event.AuditEventListener" />
    </entry>
    <entry key="post-delete">
    <bean class="org.hibernate.envers.event.AuditEventListener" />
    </entry>
    <entry key="pre-collection-update">
    <bean class="org.hibernate.envers.event.AuditEventListener" />
    </entry>
    <entry key="pre-collection-remove">
    <bean class="org.hibernate.envers.event.AuditEventListener" />
    </entry>
    <entry key="post-collection-recreate">
    <bean class="org.hibernate.envers.event.AuditEventListener" />
    </entry>  
    </map>
    </property>
    

    你必须像这样定义一个修订实体:

    @Entity    
    @Table(name = "MY_REVINFO")    
    @RevisionEntity(MyRevisionListener.class)//@see next class   
    public class MyRevisionEntity             
        private static final long serialVersionUID =1L;
    
        @Id
        @GeneratedValue
        @RevisionNumber
        private int id;
    
        @RevisionTimestamp
        private long timestamp;
    
        public int getId() 
            return id;
        
    
        public void setId(int id) 
            this.id = id;
        
    
        @Transient
        public Date getRevisionDate() 
            return new Date(timestamp);
        
    
        @Column(name = "USER_NAME")
        private String userName;
    
        @Column(name = "DATE_OPER")
        private Date dateOperation;
    
        public long getTimestamp() 
            return timestamp;
        
    
        public void setTimestamp(long timestamp) 
            this.timestamp = timestamp;
        
    
        public boolean equals(Object o) 
            if (this == o) return true;
            if (!(o instanceof DefaultRevisionEntity)) return false;
    
            DefaultRevisionEntity that = (DefaultRevisionEntity) o;
    
            if (id != that.getId()) return false;
            if (timestamp != that.getTimestamp()) return false;
    
            return true;
        
    
        public int hashCode() 
            int result;
            result = id;
            result = 31 * result + (int) (timestamp ^ (timestamp >>> 32));
            return result;
        
    
        public String getUserName() 
            return userName;
        
    
        public void setUserName(String userName) 
            this.userName = userName;
        
    
        public Date getDateOperation() 
            return dateOperation;
        
    
        public void setDateOperation(Date dateOperation) 
            this.dateOperation = dateOperation;
        
    
        public String toString() 
            return "DefaultRevisionEntity(id = " + id + ", revisionDate = " + DateFormat.getDateTimeInstance().format(getRevisionDate()) + ")";
        
    
    

    在 application-context.xml 中添加这个新实体的映射:

    <value>mypackage.MyRevisionEntity</value>
    

    创建监听器(如果要保存用户名和操作时间,很有帮助):

    public class MyRevisionListener implements RevisionListener        
    public void newRevision(Object revisionEntity) 
    
        MyRevisionEntity revision = (MyRevisionEntity) revisionEntity;
    
        SecurityContext context = SecurityContextHolder.getContext();
        Authentication authentication = context.getAuthentication();
    
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        String userName="---";
        if (userDetails != null) 
            userName=userDetails.getUsername();
         else 
            userName="UNKNOWN";
        
    
        revision.setUserName(userName);
        revision.setDateOperation(new Date(revision.getTimestamp()));
    
    
    

    清理、安装和运行您的应用程序。

    如果问题仍然存在,请尝试升级您的 Envers 版本(Hibrenate-envers 和 Hibernate-core)

希望对您有所帮助。

【讨论】:

以上是关于在 Spring Hibernate java 项目中使用“Envers”审计表的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring Boot 中配置 Hibernate 以忽略通过依赖项导入的标有 Entity 的某些类

spring 3.1 with hibernate 4 with spring security 3.1:如何确保包含所有依赖项以及要包含哪些标签?

在 Java 9 中删除 sun.misc.Unsafe 将破坏 Spring、Hibernate

关于 Java EE、Spring 和 Hibernate

spring 项目中使用 hibernate validator验证输入参数

Spring + Hibernate 审计(无 Spring Data)