1、前言
用過 jeecg 的小伙伴,在 jeecg 實體中常見下面幾個字段:
/**創建人名稱*/ private java.lang.String createName; /**創建人登錄名稱*/ private java.lang.String createBy; /**創建日期*/ private java.util.Date createDate; /**更新人名稱*/ private java.lang.String updateName; /**更新人登錄名稱*/ private java.lang.String updateBy; /**更新日期*/ private java.util.Date updateDate;
而我們在使用過程中,並沒有給其賦,但是存入數據庫后卻突然冒出值了?
其實不然,在這用到了 [攔截器],下面詳看一下 jeecg 中的實現代碼。
2、代碼分析
在 org.jeecgframework.core.aop 包下有個 HiberAspect.java,這就是今天的主角,攔截器;
也許你會有疑問,為何要把攔截器放在 aop 這個目錄下呀?sorry i don't know...
2.1、為何要使用?
其實,這種需求很常見,比如創建一筆數據,每次創建一筆數據都要去給 createBy createDate.. 賦值,豈不是很麻煩?
而恰好 Hibernate 提供的攔截器就能幫我們實現這樣繁瑣的問題。
當 session 執行 save()、update()、saveOrUpdate()、delete()以及 flush() 方法時,就會調用攔截器的相關方法,然后在這些方法中實現賦值的邏輯。
2.2、了解如何用
對於用戶定義的攔截器必須要實現 org.hibernate.Interceptor 這個接口,在這個接口中主要定義了以下方法。
onDelete(): 刪除時調用.
onFlushDirty():更新數據時調用,但數據還沒有更新到數據庫
onSave():保存數據的時候調用,數據還沒有保存到數據庫.
preFlush(): 保存,刪除,更新 在提交之前調用 (通常在 postFlush 之前).
postFlush():提交之后調用(commit之后)
而在 org.hibernate 包中還提供了 Intercepto 接口的一個實現類 EmptyInterceptor,這個類中的所有方法實際上什么也不做,用戶自定義的攔截器類也可以擴展此類。
類繼承該接口是官方推薦,並且 jeecg 也是這樣用的。
jeecg onSave() 方法實現賦值:
/* 攔截hibernate save方法(即保存對象之前回調此方法),添加審計信息
* entity - POJO Instance
* id - POJO OID
* state - POJO Instance中每一個屬性的值所組成的集合(OID屬性除外)
* propertyNames - POJO Instance中每一個屬性的屬性名組成的集合(OID屬性除外)
* types - POJO Instance中每一個屬性所屬類型所對應的Hibernate類型組成的集合(OID屬性除外)
*/
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) { TSUser currentUser = null; try { currentUser = ResourceUtil.getSessionUser(); // session 中獲取用戶信息 } catch (RuntimeException e) { //logger.warn("當前session為空,無法獲取用戶"); } if(currentUser==null){ return true; } try { //添加數據 for (int index=0;index<propertyNames.length;index++) { /*找到名為"創建時間"的屬性*/ if (DataBaseConstant.CREATE_DATE.equals(propertyNames[index]) ||DataBaseConstant.CREATE_TIME.equals(propertyNames[index])) { /*使用攔截器將對象的"創建時間"屬性賦上值*/ if(oConvertUtils.isEmpty(state[index])){ state[index] = new Date(); } continue; } /*找到名為"創建人"的屬性*/ else if (DataBaseConstant.CREATE_BY.equals(propertyNames[index])) { /*使用攔截器將對象的"創建人"屬性賦上值*/ if(oConvertUtils.isEmpty(state[index])){ state[index] = ResourceUtil.getUserSystemData(DataBaseConstant.SYS_USER_CODE); } continue; } /*找到名為"創建人名稱"的屬性*/ else if (DataBaseConstant.CREATE_NAME.equals(propertyNames[index])) { /*使用攔截器將對象的"創建人名稱"屬性賦上值*/ if(oConvertUtils.isEmpty(state[index])){ state[index] = ResourceUtil.getUserSystemData(DataBaseConstant.SYS_USER_NAME); } continue; } /*找到名為"創建人名稱"的屬性*/ else if (DataBaseConstant.SYS_USER_CODE.equals(propertyNames[index])) { /*使用攔截器將對象的"創建人名稱"屬性賦上值*/ if(oConvertUtils.isEmpty(state[index])){ state[index] = ResourceUtil.getUserSystemData(DataBaseConstant.SYS_USER_CODE); } continue; } /*找到名為"創建人部門"的屬性*/ else if (DataBaseConstant.SYS_ORG_CODE.equals(propertyNames[index])) { /*使用攔截器將對象的"創建人部門"屬性賦上值*/ if(oConvertUtils.isEmpty(state[index])){ state[index] = ResourceUtil.getUserSystemData(DataBaseConstant.SYS_ORG_CODE); } continue; } /*找到名為"創建人部門"的屬性*/ else if (DataBaseConstant.SYS_COMPANY_CODE.equals(propertyNames[index])) { /*使用攔截器將對象的"創建人部門"屬性賦上值*/ if(oConvertUtils.isEmpty(state[index])){ state[index] = ResourceUtil.getUserSystemData(DataBaseConstant.SYS_COMPANY_CODE); } continue; } /*找到名為"流程狀態"的屬性*/ else if (DataBaseConstant.BPM_STATUS.equals(propertyNames[index])) { /*使用攔截器將對象的"流程狀態"屬性賦上值*/ if(oConvertUtils.isEmpty(state[index])){ state[index] = String.valueOf(1);//1:未提交 } continue; } } } catch (RuntimeException e) { e.printStackTrace(); } return true; }
jeecg onFlushDirty() 方法臟數據回調:
/** * 攔截hibernate flush方法(即檢查到臟對象時回調此方法),添加審計信息 * entity - POJO Instance * id - POJO OID * state - POJO Instance中每一個屬性的值所組成的集合(OID屬性除外) * propertyNames - POJO Instance中每一個屬性的屬性名組成的集合(OID屬性除外) * types - POJO Instance中每一個屬性所屬類型所對應的Hibernate類型組成的集合(OID屬性除外) */ public boolean onFlushDirty(Object entity, Serializable id, Object[] state, Object[] previousState, String[] propertyNames, Type[] types) { .... }
2.3、xml配置
首先補充一點,Hibernate 的攔截器有兩種設置方式:
一種是使用sessionFactory.openSession(Interceptor interceptor),這樣的攔截器只會針對該session有效,又叫做局部攔截器。
另一種是使用Configuration的setInterceptor(Interceptor interceptor)方法設置,這樣的攔截器對每一個session都有效,又稱之為全局攔截器,全局攔截器
spring-mvc-hibernate 配置:
<!-- sessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> ...... <property name="entityInterceptor" ref="hiberAspect"></property> ...... </bean>
將審計攔截器作為 sessionFactory 的屬性進行配置,即表示此攔截器可以被所有 Session 實例共享;
等同的代碼表示方式為:Configuration.setInterceptor(Interceptor inter)。
也就是上方補充攔截器設置方式二。
3、最后
jeecg 提供的不一定是唯一實現方式,通過 aop 也可實現,如有想去自定查詢。
博客地址:http://www.cnblogs.com/niceyoo
18年專科畢業后,期間一度迷茫,最近我創建了一個公眾號用來記錄自己的成長。