在项目中对于事件进行记录是很普遍的事情,比如保存一个实体类(manager.save(entity);其本质为一条insert语句),其实现方式大致有两种方向:1、在每个manager层中触发事件时记录的话(缺点:比较难以扩展和维护,耦合性高) 2、触发器方式 (优点:耦合性小 缺点:1、存储过程调试,书写都比较麻烦 2、不同数据库不可相互移植)
我们的方式是使用hibernate提供的拦截器Interceptor模拟触发器:
(注:拦截器和过滤器有什么区别?拦截器是面向切面编程的,就是在你的service或者一个方法前调用一个方法,或者在方法后调用一个方法。但是过滤器是在java web中,为你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的 action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者 struts的action前统一设置字符集,或者去除掉一些非法字符)
首先实现一个拦截器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