2012-11-07 2 views
0

저는 모든 테이블을 많은 번거 로움없이 감사 할 수있는 좋은 접근 방식을 정의하려고 Spring AOP를 사용하고 있습니다. 시나리오 예제 : Person 테이블과 각 테이블 PersonLog가 있는데, PersonLog는 각 업데이트에 대해 이벤트를 수정 한 사용자와 시간 및 유형을 저장합니다.Spring AOP - 데이터베이스 감사

간단히 말해, 내 질문은 : 나는 ...하자 내 충고 클래스는 그것에 필요한 모든 수정없이 감사하고 새로운 테이블을 처리 할 수있을만큼 스마트 될 수있는 방법을 마련하기 위해 노력하고있어

내 조언을 구현할 때 아무 것도 변경할 필요가 없다면 Car와 CarLog 테이블을 만들었다 고 말하면서 (자동으로 Car를 감사하는 것으로 식별하고 CarLog 엔터티를 유지할 수 있음) ---> 할 수 있습니다. 테이블 자동차를 (주석에 의해) 꽤 쉽게 감사하는 것으로 식별하지만, 나는 CarLog 인스턴스를 동적으로 생성하고 유지하는 방법을 찾는데 어려움을 겪고있다.

누구나 그 방법을 생각할 수 있습니까? 감사.

+0

최대 절전 모드를 이미 사용중인 경우 여기를 클릭하면 도움이 될 수 있습니다. –

+0

매우 좋음! 나는이 사실을 몰랐다. 감사! – pabhb

답변

2

"change data capture" 또는 CDC라고합니다.

개인적으로 저는 이것이 Spring이나 AOP에 유용하다고 생각하지 않습니다. 특히 데이터베이스가 둘 이상의 응용 프로그램에서 공유/수정되는 경우 데이터베이스 자체에서 더 잘 수행 될 것이라고 생각합니다.

사용중인 데이터베이스는 밝히지 않았지만 공급 업체의 문서를 열어 CDC를 지원하기 위해 제품을 가지고 있는지 확인할 수 있습니다.

+0

필자의 경우 많은 비즈니스 요구 사항이 관련되어 있으므로 데이터베이스에 전달할 수 없으며 응용 프로그램에서 모든 권한을 가져야합니다. 객체가 사람의 경우 --- : 객체가 자동차의 경우 personLog 다른 지속 : 내가 좋아하는 뭔가를 할 수 carLog 계속 ...... 그러나 너무 추한 ...이 있어야합니다 더 좋은 방법. – pabhb

+0

비즈니스 요구 사항에 따라 이러한 구현이 수행되는 시점은 언제입니까? 더 좋은 방법이 있습니다. 그리고 당신은 그것을 진지하게 생각하지 않고 해산합니다. 아이디어에 대한 승인을 찾고있는 것 같습니다. – duffymo

+0

최대 절전 모드 Envers 내 질문에 대한 답변을 ... 덕분에 어쨌든 @duffymo .. 아니, 아직 아이디어가 없기 때문에 내 아이디어에 대한 승인을 찾고 아니에요. – pabhb

0

Envers는 감사를 위해

1

내가 저장하기 전에 복잡한 객체 그래프의 스냅 샷을 가정하고 프로젝트의 비슷한 요구 사항을 가지고 필요한 것입니다. 난 적용한

용액 1)의 오브젝트의 복제를 작성하여 동일한 테이블에 삽입 hiberante 깊은 클론 업체 유틸리티 쓸

2 setArchiveFlag

)는 오리지널, 무시 무효화 같은 특정 속성 정의 주석 @Archivable을 개발 하였다. deep cloner는 간단한 트릭을 검색하고 객체를 deslite 처리하여 새 인스턴스를 만든 다음 id 및 version을 null로 설정합니다.

3) 엔티티 인터셉터에서 아카이브 날씨를 결정하기 위해 cloner 유틸리티를 사용했습니다.

아래 코드 중 일부입니다.

@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; 
} 
}