2015-11-06 122 views
1

我正在使用Grails 2.3.8。我想添加两个审计字段(createdBy和lastUpdatedBy)到一些域。因此,从audit plugin开始,我创建了一个自定义侦听器。Grails - 创建一个自定义的PersistenceEventListener

package com.nimbus.listener 

import groovy.util.logging.Log4j 
import org.grails.datastore.mapping.core.Datastore 
import org.grails.datastore.mapping.engine.event.AbstractPersistenceEvent 
import org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener 
import org.grails.datastore.mapping.engine.event.PreInsertEvent 
import org.grails.datastore.mapping.engine.event.PreUpdateEvent 
import org.springframework.context.ApplicationEvent 

@Log4j 
class NimbusStampListener extends AbstractPersistenceEventListener { 

    public NimbusStampListener(final Datastore datastore) { 
     super(datastore) 
    } 

    @Override 
    protected void onPersistenceEvent(final AbstractPersistenceEvent event) { 
     if (event.source != this.datastore) { 
      log.trace("Event received for other datastore. Ignoring event") 
      return 
     } 

     if (event instanceof PreInsertEvent) { 
      beforeInsert(event.getEntity(), event.getEntityAccess()) 
     } else if (event instanceof PreUpdateEvent) { 
      beforeUpdate(event.getEntity(), event.getEntityAccess()) 
     } 
    } 

    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { 
     return PreInsertEvent.class.isAssignableFrom(eventType) || 
       PreUpdateEvent.class.isAssignableFrom(eventType) 
    } 

    . 
    . 
    . 
} 

,并对其进行注册内插件:

def doWithApplicationContext = { applicationContext -> 
    application.mainContext.eventTriggeringInterceptor.datastores.each { key, datastore -> 
      com.nimbus.NimbusStampListener listener = new com.nimbus.NimbusStampListener(datastore, application) 
      applicationContext.addApplicationListener(listener) 
     } 
} 

监听器被注册成功,同时也听取持久性事件。问题是,当我试图取对象的entityentityAccess字段时,它们为空。

但我可以取event.entityObject字段,我可以用这个工作。但有时在创建新的可审计对象时,createdBy和lastUpdatedBy的值不会在插入时设置,而会触发新的更新事件,从而修改项目其他部分中的对象版本StaleObjectStateException

AbstractPersistenceEvent类有两个构造函数。

protected AbstractPersistenceEvent(final Datastore source, final PersistentEntity entity, 
     final EntityAccess entityAccess) { 
    super(source); 
    this.entity = entity; 
    this.entityAccess = entityAccess; 
    this.entityObject = entityAccess.getEntity(); 
} 

protected AbstractPersistenceEvent(final Datastore source, final Object entity) { 
    super(source); 
    entityObject = entity; 
    this.entity = null; 
    this.entityAccess = null; 
} 

所以很明显,我的听众收到正在从第二个构造函数创建的事件对象。 Grails还有一些内置监听器,如AutoTimestampEventListener,它会自动更新域中的时间戳字段(dateCreated & lastUpdated)。这个监听器使用entity和entityAccess对象,这意味着它们在那里不是null。

当我试图打印所有使用applicationContext.applicationEventMulticaster.applicationListeners通过applicationContext注册的侦听器时,它不包含AutoTimestampEventListener

如果有人可以帮助我如何使我的自定义侦听器或点中的实体和实体访问可用,我可以在哪里找到AutoTimestampEventListener正在注册。我无法在发行版附带的Grails源代码中找到它。

+0

什么是你'beforeInsert'和'beforeUpdate'方法里面做什么? –

+0

我会根据事件类型更新createdBy和lastUpdatedBy字段 –

回答

0

那么我找到了一些方法来实现我的要求,并认为与他人分享。我创建了两个博客来描述适用于我的选项。在这里发布整个博客是没有意义的,所以我只想给出关于这些选项的小概念。

  1. 选项1:勾成GormInstanceApi并覆盖其方法有实现你的逻辑来更新域场。
  2. 选项2:不是直接在持久性监听器中使用Grails事件,而是从它们中获取本地Hibernate事件,它允许您更新事件的当前状态。

对于更详细的解释博客链接:

Using Hibernate Events with PersistenceEventListener

Hooking into the Instance methods of the GORM API