使用hibernate模拟触发器&拦截器方式

时间:2022-04-10 16:08:38

在项目中对于事件进行记录是很普遍的事情,比如保存一个实体类(manager.save(entity);其本质为一条insert语句),其实现方式大致有两种方向:1在每个manager层中触发事件时记录的话(缺点:比较难以扩展和维护,耦合性高)  2、触发器方式 (优点:耦合性小 缺点:1、存储过程调试,书写都比较麻烦  2、不同数据库不可相互移植)

我们的方式是使用hibernate提供的拦截器Interceptor模拟触发器:

注:拦截器和过滤器有什么区别?拦截器是面向切面编程的,就是在你的service或者一个方法前调用一个方法,或者在方法后调用一个方法。但是过滤器是在java web中,为你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的 action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者 strutsaction前统一设置字符集,或者去除掉一些非法字符)

首先实现一个拦截器NjuptInterceptor.java,定义保存实体和修改实体时的拦截器:

package com.njupt.interceptor;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Iterator;

import org.hibernate.CallbackException;
import org.hibernate.EntityMode;
import org.hibernate.Interceptor;
import org.hibernate.Transaction;
import org.hibernate.type.Type;

import com.njupt.utils.ApplicationContextHolder;
/*
*事件操作的历史记录:使用拦截器进行处理,而不是用触发器方式
*原因:1 触发器对于不同数据库写法不同,移植性太差
* 2 在事件记录中,我们需要记录的不仅仅是事件本身而已,我们还需要记录:事件的操作者,事件的类型,当前用户类型等等信息
* 这些会导致sql的重新查询等等
* */
public class NjuptInterceptor implements Interceptor {

/* 保存时记录事件 */
public boolean onSave(Object obj, Serializable arg1, Object[] arg2,
String[] arg3, Type[] arg4) throws CallbackException {
String modelName = obj.getClass().getSimpleName();
/* 具体调用的函数名称 */
String methodName = EventRecord.getCommonPrefix() + modelName + EventRecord.getSaveSuffixes();
getEventRecordMethod(methodName, obj);
return false;
}

/* 修改时记录事件 */
public boolean onFlushDirty(Object obj, Serializable arg1, Object[] arg2,
Object[] arg3, String[] arg4, Type[] arg5) throws CallbackException {
String modelName = obj.getClass().getSimpleName();
/* 具体调用的函数名称 */
String methodName = EventRecord.getCommonPrefix() + modelName + EventRecord.getUpdateSuffixes();
getEventRecordMethod(methodName, obj);
return false;
}

/* 根据反射机制执行相应的函数 */
public void getEventRecordMethod(String methodName, Object obj) {
try {
Method method = EventRecord.class.getMethod(methodName, Object.class);
method.invoke((EventRecord)ApplicationContextHolder.getBean("eventRecord"), obj);
}
catch (Exception e) { System.out.println("Method:"+methodName+ " (from Interceptor)"); }
}

@Override
public void afterTransactionBegin(Transaction arg0) {
// TODO Auto-generated method stub

}

@Override
public void afterTransactionCompletion(Transaction arg0) {
// TODO Auto-generated method stub

}

@Override
public void beforeTransactionCompletion(Transaction arg0) {
// TODO Auto-generated method stub

}

@Override
public int[] findDirty(Object arg0, Serializable arg1, Object[] arg2,
Object[] arg3, String[] arg4, Type[] arg5) {
// TODO Auto-generated method stub
return null;
}

@Override
public Object getEntity(String arg0, Serializable arg1)
throws CallbackException {
// TODO Auto-generated method stub
return null;
}

@Override
public String getEntityName(Object arg0) throws CallbackException {
// TODO Auto-generated method stub
return null;
}

@Override
public Object instantiate(String arg0, EntityMode arg1, Serializable arg2)
throws CallbackException {
// TODO Auto-generated method stub
return null;
}

@Override
public Boolean isTransient(Object arg0) {
// TODO Auto-generated method stub
return null;
}

@Override
public void onCollectionRecreate(Object arg0, Serializable arg1)
throws CallbackException {
// TODO Auto-generated method stub

}

@Override
public void onCollectionRemove(Object arg0, Serializable arg1)
throws CallbackException {
// TODO Auto-generated method stub

}

@Override
public void onCollectionUpdate(Object arg0, Serializable arg1)
throws CallbackException {
// TODO Auto-generated method stub

}

@Override
public boolean onLoad(Object arg0, Serializable arg1, Object[] arg2,
String[] arg3, Type[] arg4) throws CallbackException {
// TODO Auto-generated method stub
return false;
}

@Override
public String onPrepareStatement(String arg0) {
// TODO Auto-generated method stub
return arg0;
}

@Override
public void postFlush(Iterator arg0) throws CallbackException {
// TODO Auto-generated method stub

}

@Override
public void preFlush(Iterator arg0) throws CallbackException {
// TODO Auto-generated method stub

}

@Override
public void onDelete(Object arg0, Serializable arg1, Object[] arg2,
String[] arg3, Type[] arg4) throws CallbackException {
// TODO Auto-generated method stub

}

}

然后定义一个事件记录类EventRecord.java,其方法定义规则为recordFor +实体名+触发方式 ,比如recordForCompanyUnitSave,就是在执行实体类CompanyUnit执行保存时触发运行:

package com.njupt.interceptor;

import java.util.Date;

import com.njupt.dao.Constants;
import com.njupt.model.ClientUnit;
import com.njupt.model.CompanyUnit;
import com.njupt.model.RecordModule;
import com.njupt.model.RecordPayment;
import com.njupt.model.Role;
import com.njupt.webapp.action.BaseAction;
/**
* 继承自BaseAction, PS: 该实例并未进行依赖注入,但已在Application.xml进行配置
* */
@SuppressWarnings("serial")
public class EventRecord extends BaseAction{

private static String prefixPackageName = "com.njupt.model."; // 包的前缀,反射得到类时使用
// 调用函数的前缀,反射执行函数时使用
private static String CommonPrefix = "recordFor";
// 调用函数的后缀,反射执行函数时使用
private static String SaveSuffixes = "Save";
private static String DeleteSuffixes = "Delete";
private static String UpdateSuffixes = "Update";
private static String QuerySuffixes = "Query";

/* 新添一个公司触发器 */
public void recordForCompanyUnitSave(Object cu) {
CompanyUnit temp = (CompanyUnit)cu;
RecordModule rm = new RecordModule();
rm.setOperateType(getCurrentUserType());
rm.setOperateUserId(getCurrentUserId());
rm.setOperateDate(new java.sql.Timestamp((new Date()).getTime()));
rm.setOperateType(Constants.SAVE_TYPE_NAME);
rm.setOperateEntity("CompanyUnit");
rm.setModuleId(Constants.CompanyUnitBaseInfo_Create);
rm.setDescription("增加一个新公司:"+temp.getCompanyName());
manager.save(rm);
}

/* 新添一个角色触发器 */
public void recordForRoleSave(Object cu) {
Role role = (Role)cu;
RecordModule rm = new RecordModule();
rm.setOperateType(getCurrentUserType());
rm.setOperateUserId(getCurrentUserId());
rm.setOperateDate(new java.sql.Timestamp((new Date()).getTime()));
rm.setOperateType(Constants.SAVE_TYPE_NAME);
rm.setOperateEntity("Role");
rm.setDescription("增加一个新角色:"+role.getRoleName());
manager.save(rm);
}
/* 修改一个角色触发器 */
public void recordForRoleUpdate(Object cu) {
Role role = (Role)cu;
RecordModule rm = new RecordModule();
rm.setOperateType(getCurrentUserType());
rm.setOperateUserId(getCurrentUserId());
rm.setOperateDate(new java.sql.Timestamp((new Date()).getTime()));
rm.setOperateType(Constants.UPDATE_TYPE_NAME);
rm.setOperateEntity("Role");
rm.setDescription("修改角色:"+role.getRoleName());
manager.save(rm);
}

/* 新添一个客户单位触发器 */
public void recordForClientUnitSave(Object cu) {
ClientUnit temp = (ClientUnit)cu;
RecordModule rm = new RecordModule();
rm.setOperateType(getCurrentUserType());
rm.setOperateUserId(getCurrentUserId());
rm.setOperateDate(new java.sql.Timestamp((new Date()).getTime()));
rm.setOperateType(Constants.SAVE_TYPE_NAME);
rm.setOperateEntity("ClietnUnit");
rm.setModuleId(Constants.ClientUnitBaseInfo_Create);
rm.setDescription("增加一个新客户:"+temp.getClientUnitName());
manager.save(rm);
}



public static String getPrefixPackageName() {
return prefixPackageName;
}

public static void setPrefixPackageName(String prefixPackageName) {
EventRecord.prefixPackageName = prefixPackageName;
}

public static String getCommonPrefix() {
return CommonPrefix;
}

public static void setCommonPrefix(String commonPrefix) {
CommonPrefix = commonPrefix;
}

public static String getSaveSuffixes() {
return SaveSuffixes;
}

public static void setSaveSuffixes(String saveSuffixes) {
SaveSuffixes = saveSuffixes;
}

public static String getDeleteSuffixes() {
return DeleteSuffixes;
}

public static void setDeleteSuffixes(String deleteSuffixes) {
DeleteSuffixes = deleteSuffixes;
}

public static String getUpdateSuffixes() {
return UpdateSuffixes;
}

public static void setUpdateSuffixes(String updateSuffixes) {
UpdateSuffixes = updateSuffixes;
}

public static String getQuerySuffixes() {
return QuerySuffixes;
}

public static void setQuerySuffixes(String querySuffixes) {
QuerySuffixes = querySuffixes;
}

}

ApplicationContextHolder.java 

package com.njupt.utils;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/*
* 进行对象实例化
* */
public class ApplicationContextHolder {

public static ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");

public static Object getBean(String beanName){ return ac.getBean(beanName); }

}

applicationContext.xml 配置如下:

<bean id="eventRecord" class="com.njupt.interceptor.EventRecord">
<property name="manager" ref="manager"/>
</bean>
<bean id="njuptInterceptor" class="com.njupt.interceptor.NjuptInterceptor" />
<property name="entityInterceptor"><ref bean="njuptInterceptor"/></property> 

还可以参看:http://www.iteye.com/topic/310493