0

我正在使用 Spring AOP 尝试定义一种很好的方法来轻松审核我的所有表。场景示例:我有一个名为 Person 的表及其各自的表 PersonLog,除了每次更新的修改用户、时间和事件类型之外,它还将存储 Person 值。

简单地说,我的问题是:

我试图想出一种方法,让我的建议类足够聪明,可以处理任何正在审核的新表,而无需对其进行任何必要的修改……假设我创建了表 Car 及其 CarLog 表,如果可以的话避免在我的建议实现中更改任何内容(它会自动将 Car 识别为被审计并能够持久化 CarLog 实体)---> 我可以很容易地将表 Car 识别为被审计(通过注释),但我' 正在努力寻找一种方法来动态创建和持久化 CarLog 实例。

谁能想到一种方法来实现这一点?谢谢。

4

3 回答 3

2

这称为“变更数据捕获”或 CDC。

就个人而言,我不认为这对 Spring 或 AOP 有很好的用途。我认为最好在数据库本身中完成,特别是如果数据库由多个应用程序共享/修改。

您没有说您使用的是哪个数据库,但我建议您深入研究供应商的文档以了解他们开箱即用的内容来支持 CDC。

于 2012-11-07T00:50:59.300 回答
1

我在项目中有类似的要求,我想在保存之前拍摄复杂对象图的快照。

我应用的解决方案是 1) 开发了具有某些属性的自定义注释 @Archivable,如 nullify、ignore、orignal、setArchiveFlag

2) 编写了 hiberante 深度克隆实用程序,它创建对象的副本并插入到同一个表中。深度克隆器适用于简单的技巧 searlize 然后反序列化对象,这将创建新实例,然后将 id 和 version 设置为 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;
}
}
于 2012-11-07T05:18:48.467 回答
0

Envers 是您出于审计目的而需要的

于 2012-11-07T01:29:02.210 回答