我可以轻松记录上次修改日期、修改者等。但是,我也需要记录旧值和新值。在拦截器中,我可以在 postflush 开始执行之前触发 select 以获取当前记录的值。然后我可以在这条记录和新记录之间运行一个差异,以查看发生了什么变化并将该信息记录为旧值和新值。有没有更好的办法?
问题是我要修改的对象在引用其他对象时也可能非常大。做差异可能很昂贵。
-谢谢
我可以轻松记录上次修改日期、修改者等。但是,我也需要记录旧值和新值。在拦截器中,我可以在 postflush 开始执行之前触发 select 以获取当前记录的值。然后我可以在这条记录和新记录之间运行一个差异,以查看发生了什么变化并将该信息记录为旧值和新值。有没有更好的办法?
问题是我要修改的对象在引用其他对象时也可能非常大。做差异可能很昂贵。
-谢谢
重写 EmptyInterceptor(IInterceptor) 的 onFlushDirty 为您提供数组 previousState 和 currentState。您可以使用这两个数组来查找 oldvalue 和 newvalue。
你可以试试 Envers,它现在是 Hibernate 的一部分:http ://www.jboss.org/envers
为什么不使用审计表和触发器?
我以这种方式审核,但日期很难看:
持久性.xml:property name="hibernate.ejb.interceptor" value="siapen.jpa.interceptor.MeuInterceptador" />
package siapen.jpa.interceptor;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import org.apache.commons.lang3.ObjectUtils;
import org.hibernate.CallbackException;
import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
import siapen.model.BaseEntity;
public class MeuInterceptador extends EmptyInterceptor {
private static final long serialVersionUID = 7853236444153436270L;
private String strSQL = "";
String acao;
@SuppressWarnings("rawtypes")
BaseEntity entity;
String s = "";
@SuppressWarnings("unchecked")
// 1
public boolean onSave(Object obj, Serializable id, Object[] valores, String[] propertyNames, Type[] types)
throws CallbackException {
if (obj instanceof BaseEntity) {
entity = (BaseEntity) obj;
for (int i = 0; i < valores.length; i++) {
if (valores[i] != null && !valores[i].equals("")) {
s += propertyNames[i] + ":" + valores[i];
if (i != valores.length - 1) {
s += "___";
}
}
}
}
return false;
}
@SuppressWarnings("unchecked")
// 1
public boolean onFlushDirty(Object obj, Serializable id, Object[] valoresAtuais, Object[] valoresAnteriores,
String[] propertyNames, Type[] types) throws CallbackException {
if (obj instanceof BaseEntity) {
entity = (BaseEntity) obj;
for (int i = 0; i < valoresAtuais.length; i++) {
if (!ObjectUtils.equals(valoresAtuais[i], valoresAnteriores[i])) {
if (!s.equals("")) {
s += "___";
}
s += propertyNames[i] + "-Anterior:" + valoresAnteriores[i] + ">>>Novo:" + valoresAtuais[i];
}
}
}
return false;
}
@SuppressWarnings("unchecked")
// 1
public void onDelete(Object obj, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
if (obj instanceof BaseEntity) {
entity = (BaseEntity) obj;
}
}
// CHAMADO ANTES DO COMMIT
// 2
@SuppressWarnings("rawtypes")
public void preFlush(Iterator iterator) {
}
// 3
public String onPrepareStatement(String sql) {
acao = "";
if (sql.startsWith("/* update")) {
acao = "update";
} else if (sql.startsWith("/* insert")) {
acao = "insert";
} else if (sql.startsWith("/* delete")) {
acao = "delete";
}
if (acao != null) {
strSQL = sql;
}
return sql;
}
// CHAMADO APÓS O COMMIT
// 4
@SuppressWarnings("rawtypes")
public void postFlush(Iterator iterator) {
if (acao != null) {
try {
if (acao.equals("insert")) {
AuditLogUtil audi = new AuditLogUtil();
audi.LogIt("Salvo", entity, s);
}
if (acao.equals("update")) {
AuditLogUtil audi = new AuditLogUtil();
audi.LogIt("Atualizado", entity, s);
}
if (acao.equals("delete")) {
AuditLogUtil audi = new AuditLogUtil();
audi.LogIt("Deletado", entity, "");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
strSQL = "";
s = "";
}
}
}
}
对于那些使用 Envers 的人来说,这可以使用自定义的 Envers 侦听器轻松实现。它也可能是更清洁的解决方案。
public class UpdateEnversListener extends EnversPostUpdateEventListenerImpl {
private static Logger log = LoggerFactory.getLogger(UpdateEnversListener.class);
public UpdateEnversListener(EnversService enversService) {
super(enversService);
}
@Override
public void onPostUpdate(PostUpdateEvent event) {
List<String> auditedProperties = Arrays.asList(event.getPersister().getPropertyNames());
List<Integer> dirtyFieldsIndices = Ints.asList(event.getDirtyProperties());
// In the event you have a object
// In the persister you have indices of fields that changed and also their values
// Do your magic stuff here
super.onPostUpdate(event);
}
}