首页 > 代码库 > 利用Hibernate监听器实现用户操作日志

利用Hibernate监听器实现用户操作日志

网上搜索发现,实现用户操作日志的方式有:自定义注解方式、Hibernate拦截器方式、Hibernate监听器方式等。

1、自定义注解方式较为麻烦,需要进行操作记录的方法均需要添加注解,但是相对的操作描述更为针对性,缺点是无法获得所操作的实体ID以及成员;

2、拦截器方式经我自己试验,拦截器是在Hibernate操作数据库之前执行的,所以同样获取不了所操作的实体ID和成员,但是相对注解方式来说,不用在原有代码上更改添加注解等,耦合性比较低。

使用拦截器需要保证数据库操作均是对实体类的操作,即使用save、update、delete、get、load等方式,原生sql语句的执行是不会被拦截的;

3、监听器方式是我最终采用的方法,监听器是在Hibernate操作数据库之后执行的回调方式,可以获取操作实体的ID和成员变量,同样的相对业务层耦合性低,

使用监听器需要保证数据库操作均是对实体类的操作,即使用save、update、delete、get、load等方式,原生sql语句的执行是不会被拦截的。

 

下边展示我的代码:

这部分是监听器的注册部分

 1 import javax.annotation.PostConstruct; 2  3 import org.hibernate.SessionFactory; 4 import org.hibernate.event.service.spi.EventListenerRegistry; 5 import org.hibernate.event.spi.EventType; 6 import org.hibernate.internal.SessionFactoryImpl; 7 import org.springframework.beans.factory.annotation.Autowired; 8 import org.springframework.stereotype.Component; 9 10 /** 11  * hibernate的事件监听注册 12  * @author tianzhen13  */  14 @Component  15 public class HibernateEvent {  16   17     @Autowired18     private SessionFactory sessionFactory;  19     @Autowired  20     private OperListener operListener;  21       22     @PostConstruct 23     public void registerListeners() {  24         EventListenerRegistry registry = ((SessionFactoryImpl) sessionFactory).getServiceRegistry().getService(  25                 EventListenerRegistry.class);  26         registry.getEventListenerGroup(EventType.POST_COMMIT_INSERT).appendListener(operListener);//对实体保存的监听27         registry.getEventListenerGroup(EventType.POST_COMMIT_UPDATE).appendListener(operListener);//对实体修改的监听28         registry.getEventListenerGroup(EventType.POST_COMMIT_DELETE).appendListener(operListener);//对实体删除的监听29     }  30 }

这部分是监听器

import java.io.Serializable;import java.text.SimpleDateFormat;import java.util.Date;import javax.servlet.http.HttpSession;import org.hibernate.Session;import org.hibernate.event.spi.PostCommitDeleteEventListener;import org.hibernate.event.spi.PostCommitInsertEventListener;import org.hibernate.event.spi.PostCommitUpdateEventListener;import org.hibernate.event.spi.PostDeleteEvent;import org.hibernate.event.spi.PostInsertEvent;import org.hibernate.event.spi.PostUpdateEvent;import org.hibernate.persister.entity.EntityPersister;import org.hibernate.type.Type;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import com.nuctech.model.Useroper;import com.nuctech.util.Constant;/**  * hibernate的事件监听 * @author tianzhen */  @Componentpublic class OperListener implements PostCommitDeleteEventListener,PostCommitInsertEventListener,PostCommitUpdateEventListener{    private static final long serialVersionUID = -4253791237768268101L;        @Autowired    private HttpSession httpSession;    /**     * 监听修改事件     */    @Override    public void onPostUpdate(PostUpdateEvent event) {        StringBuffer des = new StringBuffer();//操作描述        des.append("更新操作,更新内容{");        String diff = arrayDiff(event.getState(), event.getOldState(), event.getPersister().getPropertyNames(), event.getPersister().getPropertyTypes());//判断修改了哪些部分,并拼接成字符串        des.append(diff);        des.append("}");        saveOperLog(event.getSession(), event.getEntity().getClass().getSimpleName(), event.getId(), des);    }    /**     * 监听插入事件     */    @Override    public void onPostInsert(PostInsertEvent event) {        if(!(event.getEntity() instanceof Useroper)){//当是对用户操作表的插入时,不进行操作,否则进入死循环            StringBuffer des = new StringBuffer();//操作描述            des.append("新建操作,新建内容{");            String inser = arrayToString(event.getState(), event.getPersister().getPropertyNames(), event.getPersister().getPropertyTypes());//判断添加的哪些成员,并拼接成字符串            des.append(inser);            des.append("}");            saveOperLog(event.getSession(), event.getEntity().getClass().getSimpleName(), event.getId(), des);        }    }    /**     * 监听删除事件     */    @Override    public void onPostDelete(PostDeleteEvent event) {        StringBuffer des = new StringBuffer();//操作描述        des.append("删除操作,删除内容{");        String del = arrayToString(event.getDeletedState(), event.getPersister().getPropertyNames(), event.getPersister().getPropertyTypes());//判断删除了哪些成员,并进行拼接        des.append(del);        des.append("}");        saveOperLog(event.getSession(), event.getEntity().getClass().getSimpleName(), event.getId(), des);    }        /**     * 日志的添加     * @param session     * @param des     */    private void saveOperLog(Session session, String tableName, Serializable targetId, StringBuffer des){        int currUserId = (int) httpSession.getAttribute(Constant.CURRENT_USERID);//获取操作人        Date date = new Date();        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");        String time = sdf.format(date);//操作日期        String sql = "INSERT useroper(UserID,TableName,TargetID,OperDesc,OperTime) VALUES("+currUserId+",‘"+tableName+"‘,"+targetId+",‘"+des.toString()+"‘,‘"+time+"‘)";        Session logSession = session.getSessionFactory().openSession();//重新打开一个新的Hibernate session,并在使用完进行关闭,不可使用原session。        logSession.createSQLQuery(sql).executeUpdate();        logSession.close();    }        /**     * 数组转字符串     * @param o 成员值     * @param names 成员名     * @param types 成员类型     * @return     */    private String arrayToString(Object[] o, String[] names, Type[] types){        StringBuffer result = new StringBuffer();        for(int i=0;i<o.length;i++){            if(types[i].isAssociationType())//外键忽略处理                continue;            result.append(names[i]+":"+o[i]+";");        }        if(result.toString().equals(""))            result.append(";");        return result.substring(0, result.length()-1);    }        /**     * 数组不同部分转字符串     * @param n 成员新值     * @param o 成员原值     * @param names 成员名     * @param types 成员类型     * @return     */    private String arrayDiff(Object[] n, Object[] o, String[] names, Type[] types){        StringBuffer result = new StringBuffer();        //各参数数组均按序传进来的,按index取值即可        for(int i=0;i<n.length;i++){            if(types[i].isAssociationType())//外键忽略处理                continue;            //如不相等,则加入字符串中            if(!String.valueOf(n[i]).equals(String.valueOf(o[i]))){                result.append(names[i]+":"+o[i]+">"+n[i]+";");            }        }        return result.substring(0, result.length()-1);    }    @Override    public boolean requiresPostCommitHanding(EntityPersister persister) {        return true;    }    @Override    public void onPostUpdateCommitFailed(PostUpdateEvent event) {            }    @Override    public void onPostInsertCommitFailed(PostInsertEvent event) {            }    @Override    public void onPostDeleteCommitFailed(PostDeleteEvent event) {            }}

我使用的监听器接口均为PostCommitDeleteEventListener、PostCommitInsertEventListener、PostCommitUpdateEventListener,而不是PostDeleteEventListener、PostInsertEventListener、PostUpdateEventListener,前三者是业务逻辑对数据库操作已经Commit后进行回调,后三者则不是,后三者在进行监听时,虽然可以获取各项值,但是在对值进行数据库记录时就会很麻烦,容易出现事物锁等待超时的Bug,导致业务处理也不能完成,本人菜鸟没有找到解决办法,用的是前三者的接口,anyway,实现功能效果就好,哈哈

利用Hibernate监听器实现用户操作日志