Пример перехватчика гибернации - журнал аудита
Hibernate имеет мощную функцию, называемую «interceptor», для перехвата или перехвата различных событий Hibernate, таких как операция CRUD базы данных. В этой статье я продемонстрирую, как реализовать функцию журнала аудита приложений с помощью перехватчика Hibernate. Он будет регистрировать все операции сохранения, обновления или удаления Hibernate в таблице базы данных с именем «auditlog».
Пример перехватчика гибернации - журнал аудита
1. Создать таблицу
Создайте таблицу с именем «loglog »для хранения всех проверенных записей приложения.
DROP TABLE IF EXISTS `example`.`auditlog`; CREATE TABLE `example`.`auditlog` ( `AUDIT_LOG_ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `ACTION` varchar(100) NOT NULL, `DETAIL` text NOT NULL, `CREATED_DATE` date NOT NULL, `ENTITY_ID` bigint(20) unsigned NOT NULL, `ENTITY_NAME` varchar(255) NOT NULL, PRIMARY KEY (`AUDIT_LOG_ID`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
2. Создать интерфейс маркера
Создайте интерфейс маркера, любые классы, которые реализовали этот интерфейс, будут проверяться. Этот интерфейс требует, чтобы реализованный класс предоставил ему идентификатор -getId() и содержимое для журнала - «getLogDeatil()». Все выставленные данные будут сохранены в базе данных.
package com.example.interceptor;
//market interface
public interface IAuditLog {
public Long getId();
public String getLogDeatil();
}
3. Сопоставьте таблицу «audlog»
Обычный файл модели аннотации для сопоставления с таблицей Auditlog.
@Entity
@Table(name = "auditlog", catalog = "example")
public class AuditLog implements java.io.Serializable {
private Long auditLogId;
private String action;
private String detail;
private Date createdDate;
private long entityId;
private String entityName;
...
}
4. Класс реализовал IAuditLog
Обычный файл модели аннотации для сопоставления с таблицей stock, который позже будет использован для демонстрации перехватчика. Он должен реализовать интерфейс маркераIAuditLog и реализовать методgetId() иgetLogDeatil().
...
@Entity
@Table(name = "stock", catalog = "example"
public class Stock implements java.io.Serializable, IAuditLog {
...
@Transient
@Override
public Long getId(){
return this.stockId.longValue();
}
@Transient
@Override
public String getLogDeatil(){
StringBuilder sb = new StringBuilder();
sb.append(" Stock Id : ").append(stockId)
.append(" Stock Code : ").append(stockCode)
.append(" Stock Name : ").append(stockName);
return sb.toString();
}
...
5. Создать вспомогательный класс
Вспомогательный класс, который принимает данные от перехватчика и сохраняет их в базе данных.
...
public class AuditLogUtil{
public static void LogIt(String action,
IAuditLog entity, Connection conn ){
Session tempSession = HibernateUtil.getSessionFactory().openSession(conn);
try {
AuditLog auditRecord = new AuditLog(action,entity.getLogDeatil()
, new Date(),entity.getId(), entity.getClass().toString());
tempSession.save(auditRecord);
tempSession.flush();
} finally {
tempSession.close();
}
}
}
6. Создать класс перехватчика Hibernate
Создайте класс перехватчика, расширяя HibernateEmptyInterceptor. Вот самая популярная функция перехватчика.
-
onSave - вызывается при сохранении объекта, объект еще не сохранен в базе данных.
-
onFlushDirty - Вызывается при обновлении объекта, объект еще не обновляется в базе данных.
-
onDelete - Вызывается, когда вы удаляете объект, объект еще не удален в базу данных.
-
preFlush - вызывается до того, как сохраненные, обновленные или удаленные объекты будут переданы в базу данных (обычно до postFlush).
-
postFlush - вызывается после фиксации сохраненных, обновленных или удаленных объектов в базе данных.
Код довольно многословен, он должен быть самоанализом.
...
public class AuditLogInterceptor extends EmptyInterceptor{
Session session;
private Set inserts = new HashSet();
private Set updates = new HashSet();
private Set deletes = new HashSet();
public void setSession(Session session) {
this.session=session;
}
public boolean onSave(Object entity,Serializable id,
Object[] state,String[] propertyNames,Type[] types)
throws CallbackException {
System.out.println("onSave");
if (entity instanceof IAuditLog){
inserts.add(entity);
}
return false;
}
public boolean onFlushDirty(Object entity,Serializable id,
Object[] currentState,Object[] previousState,
String[] propertyNames,Type[] types)
throws CallbackException {
System.out.println("onFlushDirty");
if (entity instanceof IAuditLog){
updates.add(entity);
}
return false;
}
public void onDelete(Object entity, Serializable id,
Object[] state, String[] propertyNames,
Type[] types) {
System.out.println("onDelete");
if (entity instanceof IAuditLog){
deletes.add(entity);
}
}
//called before commit into database
public void preFlush(Iterator iterator) {
System.out.println("preFlush");
}
//called after committed into database
public void postFlush(Iterator iterator) {
System.out.println("postFlush");
try{
for (Iterator it = inserts.iterator(); it.hasNext();) {
IAuditLog entity = (IAuditLog) it.next();
System.out.println("postFlush - insert");
AuditLogUtil.LogIt("Saved",entity, session.connection());
}
for (Iterator it = updates.iterator(); it.hasNext();) {
IAuditLog entity = (IAuditLog) it.next();
System.out.println("postFlush - update");
AuditLogUtil.LogIt("Updated",entity, session.connection());
}
for (Iterator it = deletes.iterator(); it.hasNext();) {
IAuditLog entity = (IAuditLog) it.next();
System.out.println("postFlush - delete");
AuditLogUtil.LogIt("Deleted",entity, session.connection());
}
} finally {
inserts.clear();
updates.clear();
deletes.clear();
}
}
}
7.Enabling the interceptor
Вы можете включить перехватчик, передав его в качестве аргументаopenSession(interceptor);.
...
Session session = null;
Transaction tx = null;
try {
AuditLogInterceptor interceptor = new AuditLogInterceptor();
session = HibernateUtil.getSessionFactory().openSession(interceptor);
interceptor.setSession(session);
//test insert
tx = session.beginTransaction();
Stock stockInsert = new Stock();
stockInsert.setStockCode("1111");
stockInsert.setStockName("example");
session.saveOrUpdate(stockInsert);
tx.commit();
//test update
tx = session.beginTransaction();
Query query = session.createQuery("from Stock where stockCode = '1111'");
Stock stockUpdate = (Stock)query.list().get(0);
stockUpdate.setStockName("example-update");
session.saveOrUpdate(stockUpdate);
tx.commit();
//test delete
tx = session.beginTransaction();
session.delete(stockUpdate);
tx.commit();
} catch (RuntimeException e) {
try {
tx.rollback();
} catch (RuntimeException rbe) {
// log.error("Couldn’t roll back transaction", rbe);
}
throw e;
} finally {
if (session != null) {
session.close();
}
}
...
В тесте вставки
session.saveOrUpdate(stockInsert); //it will call onSave tx.commit(); // it will call preFlush follow by postFlush
В обновлении теста
session.saveOrUpdate(stockUpdate); //it will call onFlushDirty tx.commit(); // it will call preFlush follow by postFlush
В тесте удаления
session.delete(stockUpdate); //it will call onDelete tx.commit(); // it will call preFlush follow by postFlush
Выход
onSave
Hibernate:
insert into example.stock
(STOCK_CODE, STOCK_NAME)
values (?, ?)
preFlush
postFlush
postFlush - insert
Hibernate:
insert into example.auditlog
(ACTION, CREATED_DATE, DETAIL, ENTITY_ID, ENTITY_NAME)
values (?, ?, ?, ?, ?)
preFlush
Hibernate:
select ...
from example.stock stock0_
where stock0_.STOCK_CODE='1111'
preFlush
onFlushDirty
Hibernate:
update example.stock
set STOCK_CODE=?, STOCK_NAME=?
where STOCK_ID=?
postFlush
postFlush - update
Hibernate:
insert into example.auditlog
(ACTION, CREATED_DATE, DETAIL, ENTITY_ID, ENTITY_NAME)
values (?, ?, ?, ?, ?)
onDelete
preFlush
Hibernate:
delete from example.stock where STOCK_ID=?
postFlush
postFlush - delete
Hibernate:
insert into example.auditlog
(ACTION, CREATED_DATE, DETAIL, ENTITY_ID, ENTITY_NAME)
values (?, ?, ?, ?, ?)
В базе данных
SELECT * FROM auditlog a;
Все проверенные данные вставляются в базу данных.

Заключение
Журналы аудита - это полезная функция, которая часто обрабатывается в базе данных с помощью триггеров, но я бы порекомендовал использовать приложение для ее реализации в целях переносимости.
Загрузите этот пример -Hibernate interceptor example.zip