我可以使用Spring Data JPA审计功能而不需要orm.xml文件吗(使用JavaConfig代替)?

16

我想让Spring Data审计在我的Spring 3.2.8 / Spring Data 1.5 / Hibernate 4项目中工作。

根据Spring Data审计文档,我已经向我的实体添加了@CreatedBy等注释,并创建了AuditorAware实现并从我的JavaConfig中实例化它。但是,它似乎从未生效。

我觉得这些文件有点令人困惑。它似乎JavaConfig条目取代了xml条目,但我不确定。

我的应用程序中当前没有任何orm.xml文件。老实说,我甚至不知道在哪里/如何配置它,或者为什么我需要它。我的所有实体都使用注释。我尝试将@EntityListeners(AuditingEntityListener.class)添加到实体中,但没有帮助。

我的当前实体管理器没有使用persistence.xml文件进行定义:

    <!--  entity manager -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter"/>
        <property name="packagesToScan" value="com.ia.domain"/>
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                <prop key="hibernate.query.substitutions">true '1', false '0'</prop>
                <prop key="hibernate.generate_statistics">true</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
                <prop key="hibernate.connection.charSet">UTF-8</prop>
            </props>
        </property>
    </bean>

JavaConfig:

@Configuration
@EnableJpaAuditing
public class AuditConfig {
    @Bean
    public AuditorAware<User> auditorProvider(){
        return new SpringSecurityAuditorAware();
    }
}

实体:

@EntityListeners({AuditingEntityListener.class})
@Entity
public class User
{

  @TableGenerator(name="UUIDGenerator", pkColumnValue="user_id", table="uuid_generator", allocationSize=1)
  @Id
  @GeneratedValue(strategy=GenerationType.TABLE, generator="UUIDGenerator")
  @Column(name="id")
  private Long id;

  @NotNull
  private String username;

  @CreatedDate
  @NotNull
  @Temporal(TemporalType.TIMESTAMP)
  @Column(name="created_date", nullable=false)
  private Date createdDate;

  @LastModifiedDate
  @NotNull
  @Temporal(TemporalType.TIMESTAMP)
  @Column(name="last_modified_date", nullable=false)
  private Date lastModifiedDate;

  @CreatedBy
  @ManyToOne(fetch=FetchType.LAZY)
  @JoinColumn(name="created_by")
  private User createdBy;

  @LastModifiedBy
  @ManyToOne(fetch=FetchType.LAZY)
  @JoinColumn(name="last_modified_by")
  private User lastModifiedBy;
  private String password;
  private Boolean enabled;


...
}

我在SpringSecurityAuditorAware类中设置了一个断点,但它从未被触发。

我是否仍需要一个orm.xml文件?这个文件从EntityManager的哪里引用?


@OliverGierke 我花了一上午的时间在一个示例应用程序中尝试重现这个问题。最终我成功地重现了这个问题,但我认为这是一个jRebel的问题。虽然我还不确定,但事情似乎朝着这个方向发展。我会随时通知你的。 - Eric B.
3
原文:@OliverGierke Turns out it was a jRebel issue. I had been using aspectJ to compile-time-weave in the @EntityListeners() but when jRebel was loading the classes, it was using the classpath pointing to the original entities and not the augmented classes. I had to remove the rebel.xml file that the jRebel maven plugin generated, and everything seems to be working properly now.翻译:事实证明这是一个 jRebel 的问题。我一直在使用 aspectJ 将 @EntityListeners() 编译时织入,但是当 jRebel 加载类时,它使用的是指向原始实体而不是增强类的类路径。我不得不删除 jRebel Maven 插件生成的 rebel.xml 文件,现在一切都正常了。 - Eric B.
еҳҝ@EricBгҖӮжҲ‘们жӯЈеңЁдҪҝз”ЁJrebel并йҒҮеҲ°зӣёеҗҢзҡ„й—®йўҳгҖӮжңүд»Җд№ҲеҠһжі•и®©jrebelдёҺSpring Data Auditingе…је®№еҗ—пјҹ - oak
@oak 就像我说的那样,我不得不删除 rebel.xml 文件。实际上,我并没有使用它,也没有看到它的价值,所以从我的构建中删除它对我来说没有任何影响。 - Eric B.
谢谢回复,我们正在使用rebel.xml实时更新开发服务器,这对我们很有帮助。你有什么想法吗? - oak
显示剩余3条评论
3个回答

10

简短版: 不行

自JPA 2.0起,无法在没有XML文件(orm.xml)的情况下定义此类实体侦听器。

长版本:解决方法...

如果项目中的所有实体都扩展了 AbstractAuditable 超类,则可以在 AbstractAuditable 上放置 @EntityListeners({AuditingEntityListener.class})。附加到实体类的侦听器将被其子类继承。

请注意,子类可以使用 @ExcludeSuperclassListeners 注释显式地排除继承的侦听器。

以下是实现解决方法的代码示例:

AbstractAuditableEntity.java

import java.util.Date;

import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@MappedSuperclass
@EntityListeners({AuditingEntityListener.class}) // AuditingEntityListener will also audit any subclasses of AbstractAuditable...
public abstract class AbstractAuditableEntity {
    @Id
    @GeneratedValue
    private Long id;

    @CreatedDate
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;

    @LastModifiedDate
    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModifiedDate;
}

MyEntity.java

@Entity
public abstract class MyEntity extends AbstractAuditableEntity {

}

我认为可以使用接口 Auditable@EntityListeners 可以出现在接口上)代替 AbstractAuditable 类,但我没有尝试过...


参考文献:JSR-000317 Java Persistence 2.0 - Final Release


1
第二次尝试时...当我创建自己的审计类时,这个工作得很好...我会在答案中发布。 - Justin Smith
这个解决方法没有XML就不起作用。@JustinSmith你的解决方案非常好,但是不知道为什么。 - Abhishek Chatterjee

7
使用Stephan的答案,https://dev59.com/HWEh5IYBdhLWcg3wdzeR#26240077
我使用自定义监听器使其正常工作。
@Configurable
public class TimestampedEntityAuditListener {

    @PrePersist
    public void touchForCreate(AbstractTimestampedEntity target) {
        Date now = new Date();
        target.setCreated(now);
        target.setUpdated(now);
    }

    @PreUpdate
    public void touchForUpdate(AbstractTimestampedEntity target) {
        target.setUpdated(new Date());
    }
}

然后在我的基类中引用它:
@MappedSuperclass
@EntityListeners({TimestampedEntityAuditListener.class})
public abstract class AbstractTimestampedEntity implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;

    @Temporal(TemporalType.TIMESTAMP)
    private Date created;

    @Temporal(TemporalType.TIMESTAMP)
    private Date updated;

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public Date getUpdated() {
        return updated;
    }

    public void setUpdated(Date updated) {
        this.updated = updated;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

顺便提一下,我在一个spring-boot项目中使用它,没有orm.xml文件。


你能在你的帖子中解释一下 @CreatedDate@LastModifiedDate 注解是什么吗? - Stephan
@Stephan 我不确定你的意思。再看一遍,使用这种方法可能根本不需要那些注释,因为自定义审计类根本没有使用注释,只使用了抽象类。 - Justin Smith
如果这些注释甚至都不需要,为什么它们会出现在代码中呢? - Stephan
1
更新了,感谢你帮我找到正确的方向。 - Justin Smith

4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接