2012-11-07 77 views
0

我正在使用Spring AOP試圖定義一個很好的方法來讓我所有的表都沒有多少麻煩。場景示例: 我有一個名爲Person的表及其相應的表PersonLog,它將除每個更新的修改用戶,時間和事件類型外,還存儲Person值。Spring AOP - 數據庫審計

簡單地說,我的問題是:

我試圖想出一個辦法,沒有任何必要的修改,它被審覈我的建議類將是足夠的智慧來處理任何新表...讓我們假設我創建了表Car和CarLog表,如果我可以避免在我的建議實現中更改任何內容(它會自動將Car識別爲正在審計,並且能夠持久化CarLog實體)--->我可以識別表Car作爲審計相當容易(通過註釋),但我努力尋找一種方法來動態創建和持久化CarLog實例。

任何人都可以想出一種方法來實現它?謝謝。

+0

如果你已經使用hibernate,那麼envers可以幫你在這裏 –

+0

非常酷!我不知道這一個。謝謝! – pabhb

回答

2

這叫做"change data capture"或CDC。

就我個人而言,我認爲這不適合Spring或AOP。我認爲數據庫本身會更好,特別是如果數據庫由多個應用程序共享/修改。

您不會說您使用的是哪個數據庫,但我建議您深入挖掘供應商的文檔,以瞭解他們開箱即可支持CDC。

+0

由於這將涉及到很多業務需求,我不能將它傳遞給數據庫,我需要從應用程序完全控制。 我可以這樣做: ---如果對象是人,則:堅持personLog 否則,如果對象是汽車,那麼:堅持CARLOG ......但它太醜陋了......必須有一個更好的方法。 – pabhb

+0

由於什麼時候這樣的實現是由業務需求驅動的?有一個更好的方法,而你沒有給予認真的想法就會解散它。你聽起來像你只是在尋找你的想法批准。 – duffymo

+0

Hibernate Envers是我的問題的答案......無論如何感謝@duffymo ..並且不,我不想爲我的想法尋求批准,因爲還沒有想法。 – pabhb

0

Envers是你需要審計的目的

1

我有項目我在哪裏假設把複雜的對象圖的快照保存前similiar要求。

溶液我已經申請是1)開發的定製註釋@Archivable與某些屬性等抵消,忽略,一部開拓創新,setArchiveFlag

2)寫入的Hiberante深拷貝機的工具,它創建的對象的副本,並插入到相同的表。深層克隆人使用簡單的技巧searlize然後desearlize對象,這將創建新的實例,然後將id和版本設置爲null。 3)在實體攔截器中使用克隆實用程序來決定是否存檔或不存檔。

下面是一些代碼。

@Retention(RetentionPolicy.RUNTIME) 
@Target({ ElementType.TYPE }) 
public @interface Archivable { 

/** This will mark property as null in clone */ 
public String[] nullify() default {}; 

/** 
* If property is archivable but not from enclosing entity then specify as 
* ignore. 
*/ 
public String[] ignore() default {}; 

/** 
* sets original reference to clone for back refer data. This annotation is 
* applicable to only root entity from where archiving started. 
* 
* @return 
*/ 
public String original() default ""; 

/** 
* if marks cloned entity to archived, assumes flag to be "isArchived". 
* @return 
*/ 
public boolean setArchiveFlag() default false; 
} 


@Component 
public class ClonerUtils { 

private static final String IS_ARCHIVED = "isArchived"; 
@Autowired 
private SessionFactory sessionFactory; 

public Object copyAndSave(Serializable obj) throws Exception { 
    List<BaseEntity> entities = new ArrayList<BaseEntity>(); 
    Object clone=this.copy(obj,entities); 
    this.save(clone, entities); 
    return clone; 
} 

public Object copy(Serializable obj,List<BaseEntity> entities) throws Exception{ 
    recursiveInitliaze(obj); 
    Object clone = SerializationHelper.clone(obj); 
    prepareHibernateObject(clone, entities); 
    if(!getOriginal(obj).equals("")){ 
     PropertyUtils.setSimpleProperty(clone, getOriginal(obj), obj); 
    } 
    return clone; 
} 


private void save(Object obj,List<BaseEntity> entities){ 
    for (BaseEntity baseEntity : entities) { 
     sessionFactory.getCurrentSession().save(baseEntity); 
    } 
} 

@SuppressWarnings("unchecked") 
public void recursiveInitliaze(Object obj) throws Exception { 
    if (!isArchivable(obj)) { 
     return; 
    } 
    if(!Hibernate.isInitialized(obj)) 
     Hibernate.initialize(obj); 
    PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj); 
    for (PropertyDescriptor propertyDescriptor : properties) { 
     Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName()); 
     if (origProp != null && isArchivable(origProp) && !isIgnore(propertyDescriptor, obj)) { 
      this.recursiveInitliaze(origProp); 
     } 
     if (origProp instanceof Collection && origProp != null) {    
      for (Object item : (Collection) origProp) { 
       this.recursiveInitliaze(item); 
      } 
     } 
    } 
} 


@SuppressWarnings("unchecked") 
private void prepareHibernateObject(Object obj, List entities) throws Exception { 
    if (!isArchivable(obj)) { 
     return; 
    } 
    if (obj instanceof BaseEntity) { 
     ((BaseEntity) obj).setId(null); 
     ((BaseEntity) obj).setVersion(null); 
     if(hasArchiveFlag(obj)){ 
      PropertyUtils.setSimpleProperty(obj, IS_ARCHIVED, true); 
     } 
     entities.add(obj); 
    } 
    String[] nullifyList = getNullifyList(obj); 
    for (String prop : nullifyList) { 
     PropertyUtils.setProperty(obj, prop, null); 
    } 
    PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(obj); 
    for (PropertyDescriptor propertyDescriptor : properties) { 
     if (isIgnore(propertyDescriptor, obj)) { 
      continue; 
     } 
     Object origProp = PropertyUtils.getProperty(obj, propertyDescriptor.getName());   
     if (origProp != null && isArchivable(origProp)) { 
      this.prepareHibernateObject(origProp, entities); 
     } 
     /** This code is for element collection */ 
     if(origProp instanceof PersistentBag){ 
      Collection elemColl=createNewCollection(origProp); 
      PersistentBag pColl=(PersistentBag) origProp; 
      elemColl.addAll(pColl.subList(0, pColl.size())); 
      PropertyUtils.setSimpleProperty(obj, propertyDescriptor.getName(), elemColl); 
      continue; 
     } 
     if (origProp instanceof Collection && origProp != null) { 
      Collection newCollection = createNewCollection(origProp); 
      PropertyUtils.setSimpleProperty(obj, propertyDescriptor.getName(), newCollection); 
      for (Object item : (Collection) origProp) { 
       this.prepareHibernateObject(item, entities); 
      } 
     } 
    } 
} 



@SuppressWarnings("unchecked") 
private Collection createNewCollection(Object origProp) { 
    try { 
     if(List.class.isAssignableFrom(origProp.getClass())) 
      return new ArrayList((Collection)origProp); 
     else if(Set.class.isAssignableFrom(origProp.getClass())) 
       return new HashSet((Collection)origProp); 
     else{ 
      Collection tempColl=(Collection) BeanUtils.cloneBean(origProp); 
      tempColl.clear(); 
      return tempColl; 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    return new ArrayList();  
} 

private boolean isIgnore(PropertyDescriptor propertyDescriptor,Object obj){ 
    String propertyName=propertyDescriptor.getName(); 
    String[] ignores=getIgnoreValue(obj); 
    return ArrayUtils.contains(ignores, propertyName); 
} 

private String[] getIgnoreValue(Object obj) { 
    String[] ignore=obj.getClass().getAnnotation(Archivable.class).ignore(); 
    return ignore==null?new String[]{}:ignore; 
} 

private String[] getNullifyList(Object obj) { 
    String[] nullify=obj.getClass().getAnnotation(Archivable.class).nullify(); 
    return nullify==null?new String[]{}:nullify; 
} 

public boolean isArchivable(Object obj) { 
    return obj.getClass().isAnnotationPresent(Archivable.class); 
} 


private String getOriginal(Object obj) { 
    String original=obj.getClass().getAnnotation(Archivable.class).original(); 
    return original==null?"":original; 
} 

private boolean hasArchiveFlag(Object obj) {   
    return obj.getClass().getAnnotation(Archivable.class).setArchiveFlag(); 
} 

@SuppressWarnings({ "unchecked", "unused" }) 
private Collection getElemColl(Object obj, Object origProp) { 
    Collection elemColl=createNewCollection(origProp); 
    for (Object object : (Collection)origProp) { 
     elemColl.add(object); 
    } 
    return elemColl; 
} 

@SuppressWarnings("unused") 
private boolean isElementCollection(Object obj, String name) { 
    try { 
     Annotation[] annotations=obj.getClass().getDeclaredField(name).getAnnotations(); 
     for (Annotation annotation : annotations) { 
      if(annotation.annotationType() == ElementCollection.class) 
       return true; 
     } 
    } catch (Exception e) { 
     e.printStackTrace();    
    } 
    return false; 
} 
}