您的位置:首页 > 其它

Hibernate 拦截器Interceptor使用

2015-11-26 09:14 253 查看
如果想在DAO层对插入,更新,读取数据进行过滤更改,可以使用EmptyInterceptor。用法如下:

public class VideoServerInterceptor extends EmptyInterceptor {

/**

*

*/

private static final long serialVersionUID = 6314774135018183911L;

public boolean onFlushDirty(

Object entity,

Serializable id,

Object[] state,

Object[] previousState,

String[] propertyNames,

Type[] types) {

if (entity instanceof VideoServer) {

boolean modified = false;

for (int i = 0; i < propertyNames.length; i++) {

if ("adslPassword".equals(propertyNames[i])) {

if (null != state[i]) {

modified = true;

state[i] = VissEncode.vssEncrypt(state[i].toString());

}

} else if ("tr069Password".equals(propertyNames[i])) {

if (null != state[i]) {

modified = true;

state[i] = VissEncode.vssEncrypt(state[i].toString());

}

} else if ("loginPassword".equals(propertyNames[i])) {

if (null != state[i]) {

modified = true;

state[i] = VissEncode.vssEncrypt(state[i].toString());

}

}

}

return modified;

}

return false;

}

@Override

public boolean onLoad(Object entity, Serializable id, Object[] state,

String[] propertyNames, Type[] types) {

if (entity instanceof VideoServer) {

boolean modified = false;

for (int i = 0; i < propertyNames.length; i++) {

if ("adslPassword".equals(propertyNames[i])) {

if (null != state[i]) {

modified = true;

state[i] = VissEncode.vssDecrypt(state[i].toString());

}

} else if ("tr069Password".equals(propertyNames[i])) {

if (null != state[i]) {

modified = true;

state[i] = VissEncode.vssDecrypt(state[i].toString());

}

} else if ("loginPassword".equals(propertyNames[i])) {

if (null != state[i]) {

modified = true;

state[i] = VissEncode.vssDecrypt(state[i].toString());

}

}

}

return modified;

}

return false;

}

@Override

public boolean onSave(Object entity, Serializable id, Object[] state,

String[] propertyNames, Type[] types) {

if (entity instanceof VideoServer) {

boolean modified = false;

for (int i = 0; i < propertyNames.length; i++) {

if ("adslPassword".equals(propertyNames[i])) {

if (null != state[i]) {

modified = true;

state[i] = VissEncode.vssEncrypt(state[i].toString());

}

} else if ("tr069Password".equals(propertyNames[i])) {

if (null != state[i]) {

modified = true;

state[i] = VissEncode.vssEncrypt(state[i].toString());

}

} else if ("loginPassword".equals(propertyNames[i])) {

if (null != state[i]) {

modified = true;

state[i] = VissEncode.vssEncrypt(state[i].toString());

}

}

}

return modified;

}

return false;

}

}

这样就实现了对属性的更改,当然也可以作为实体类的日志记录。。。这里转一下其他文章转自http://www.yihaomen.com/article/java/464.htm

===============================================================================================

开发应用程序的过程中,经常会对一些比较重要的数据修改都需要写日志。在实际工作的工程中,这些数据都是存在表中的, 一个常见的做法是用触发器,在增删改的时候,用触发器将数据写入到另一张表中去,但个人不推荐这么做,原因如下:

1. 如果有多个表,得写很多触发器。

2. 触发器与数据库特性关联太紧,不同的数据库,虽然思路一样,但语法却不太一样。

对数据库表操作的日志记录,完全可以利用Hibernate的Interceptor特性来实现,也就是拦截器。下面用一个具体的例子来说明如何使用Hibernate的Interceptor。

创建一个表,用来记录日志的表


程序代码

Create TABLE `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;

创建这个表对应的实体类:


程序代码

@Entity

@Table(name = "auditlog")

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;

public AuditLog() {

}

public AuditLog(String action, String detail, Date createdDate,

long entityId, String entityName) {

this.action = action;

this.detail = detail;

this.createdDate = createdDate;

this.entityId = entityId;

this.entityName = entityName;

}

@Id

@GeneratedValue(strategy = IDENTITY)

@Column(name = "AUDIT_LOG_ID", unique = true, nullable = false)

public Long getAuditLogId() {

return this.auditLogId;

}

.... 余下部分可以参考提供下载的源代码.

创建一个接口,所有实现了这个接口的实体类,都会写日志


程序代码

package com.mkyong.interceptor;

//market interface

public interface IAuditLog {

public Long getId();

public String getLogDeatil();

}

这里有两个方法,getId,getLogDetail 需要实现类去实现具体的方法,也就是要被写入到日志表中的详细记录.

创建一个类实现了IAuditLog 接口,并给出接口方法的具体实现


程序代码

@Entity

@Table(name="stock")

public class Stock implements java.io.Serializable,IAuditLog {

private static final long serialVersionUID = 1L;

@Id

@GeneratedValue(strategy=GenerationType.AUTO)

@Column(name="STOCK_ID")

private Integer stockId;

@Column(name="STOCK_CODE", length=10)

private String stockCode;

@Column(name="STOCK_NAME", length=20)

private String stockName;

public Stock() {

}

public Stock(String stockCode, String stockName) {

this.stockCode = stockCode;

this.stockName = stockName;

}

....省略部分getter,setter。

@Transient

public Long getId(){

return this.stockId.longValue();

}

@Transient

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();

}

}

创建记录日志的工具类,所有写日志公用


程序代码

public class AuditLogUtil{

public static void LogIt(String action,

IAuditLog entity){

Session tempSession = HibernateUtil.getSessionFactory().openSession();

try {

tempSession.getTransaction().begin();

AuditLog auditRecord = new AuditLog(action,entity.getLogDeatil()

, new Date(),entity.getId(), entity.getClass().toString());

tempSession.save(auditRecord);

tempSession.getTransaction().commit();

} finally {

tempSession.close();

}

}

}

创建 Hibernate interceptor 拦截器,这是重点,这里拦截所有需要记录日志的类,并处理


程序代码

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;

}

@Override

public String onPrepareStatement(String sql) {

System.out.println("execute sql: " + sql);

return super.onPrepareStatement(sql);

}

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);

}

for (Iterator it = updates.iterator(); it.hasNext();) {

IAuditLog entity = (IAuditLog) it.next();

System.out.println("postFlush - update");

AuditLogUtil.LogIt("Updated",entity);

}

for (Iterator it = deletes.iterator(); it.hasNext();) {

IAuditLog entity = (IAuditLog) it.next();

System.out.println("postFlush - delete");

AuditLogUtil.LogIt("Deleted",entity);

}

} finally {

inserts.clear();

updates.clear();

deletes.clear();

}

}

}

这里面有几个比较常用的方法:

onSave – 保存数据的时候调用,数据还没有保存到数据库.

onFlushDirty – 更新数据时调用,但数据还没有更新到数据库

onDelete – 删除时调用.

preFlush – 保存,删除,更新 在提交之前调用 (通常在 postFlush 之前).

postFlush – 提交之后调用(commit之后)

写测试例子, 添加数据,更新数据,然后再删掉


程序代码

public class App {

public static void main(String[] args) {

Session session = null;

Transaction tx = null;

try {

AuditLogInterceptor interceptor = new AuditLogInterceptor();

session = HibernateUtil.getSessionFactory().withOptions().interceptor(interceptor).openSession();

//session = HibernateUtil.getSessionFactory().openSession();

//interceptor.setSession(session);

//test insert

tx = session.beginTransaction();

Stock stockInsert = new Stock();

stockInsert.setStockCode("1111");

stockInsert.setStockName("yihaomen");

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("yihaomen-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抰 roll back transaction", rbe);

}

throw e;

} finally {

if (session != null) {

session.close();

}

}

}

}

运行结果如下:


程序代码

onSave

execute sql: insert into stock (STOCK_CODE, STOCK_NAME) values (?, ?)

Hibernate: insert into stock (STOCK_CODE, STOCK_NAME) values (?, ?)

preFlush

postFlush

postFlush - insert

Hibernate: insert into auditlog (ACTION, CreateD_DATE, DETAIL, ENTITY_ID, ENTITY_NAME) values (?, ?, ?, ?, ?)

preFlush

execute sql: select stock0_.STOCK_ID as STOCK_ID1_1_, stock0_.STOCK_CODE as STOCK_CO2_1_, stock0_.STOCK_NAME as STOCK_NA3_1_ from stock stock0_ where stock0_.STOCK_CODE='1111'

Hibernate: select stock0_.STOCK_ID as STOCK_ID1_1_, stock0_.STOCK_CODE as STOCK_CO2_1_, stock0_.STOCK_NAME as STOCK_NA3_1_ from stock stock0_ where stock0_.STOCK_CODE='1111'

preFlush

onFlushDirty

execute sql: update stock set STOCK_CODE=?, STOCK_NAME=? where STOCK_ID=?

Hibernate: update stock set STOCK_CODE=?, STOCK_NAME=? where STOCK_ID=?

postFlush

postFlush - update

Hibernate: insert into auditlog (ACTION, CreateD_DATE, DETAIL, ENTITY_ID, ENTITY_NAME) values (?, ?, ?, ?, ?)

onDelete

preFlush

execute sql: delete from stock where STOCK_ID=?

Hibernate: delete from stock where STOCK_ID=?

postFlush

postFlush - delete

Hibernate: insert into auditlog (ACTION, CreateD_DATE, DETAIL, ENTITY_ID, ENTITY_NAME) values (?, ?, ?, ?, ?)

另外查看 auditLog 这张表, 可以看到日志成功写入



另外,如果是在SPRING 容器中使用,应该将这个interceptor 注入进去


程序代码

<bean id="hibermateInterceptor" class="com.yihaomen.interceptor.AuditLogInterceptor"/>

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">

<property name="dataSource">

<ref local="dataSource_jdbc"/>

</property>

<property name="entityInterceptor" ref="hibermateInterceptor"/>

..............

</bean>

这样就能实现对整个项目中需要记录日志的实体类进行拦截,并记录增删改的日志记录. 还是很方便的,重点就是 Hibernate interceptor 的使用.

测试在是在 Hibernate 4.3 下测试的, 如果是hibernate 3 在openSession的时候是不同的,hibernate4用了session = HibernateUtil.getSessionFactory().withOptions().interceptor(interceptor).openSession(); 如果是Hibernate 3的话,应该是:session = HibernateUtil.getSessionFactory().openSession(interceptor);。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: