Пример перехватчика гибернации - журнал аудита
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