2015-11-06 132 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