首页 > 代码库 > SSH基于Hibernate eventListener 事件侦听器的操作日志自动保存到数据库

SSH基于Hibernate eventListener 事件侦听器的操作日志自动保存到数据库

  1. 在spring xml配置文件中添加配置,包含:model、listener
  2. 在model中增加需要写入数据库对应表的model
  3. 在auditLog.xml配置文件中配置自己项目中,需要进行日志记录的model类shortName,以及相关属性。

相关代码如下:

首先spring xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context-3.0.xsd           http://www.springframework.org/schema/aop           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd           http://www.springframework.org/schema/tx            http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">    <context:annotation-config />    <context:component-scan base-package="com.cqta" />    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">        <property name="locations">            <list>                <value>classpath:db.properties</value>            </list>        </property>    </bean>     <bean id="dataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource">        <property name="driver" value="${driver}" />        <property name="driverUrl" value="${driverUrl}" />        <property name="user" value="${user}" />        <property name="password" value="${password}" />        <property name="maximumActiveTime" value="600000" />        <property name="maximumConnectionCount" value="500" />        <property name="minimumConnectionCount" value="5" />        <property name="prototypeCount" value="5" />        <property name="simultaneousBuildThrottle" value="5" />        <property name="maximumConnectionLifetime" value="36000000" />    </bean>          <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">        <property name="dataSource" ref="dataSource" />        <property name="mappingLocations">            <list>                <value>classpath*:com/cqta/dev/model/system/*.hbm.xml</value>                <value>classpath*:com/cqta/dev/model/authority/*.hbm.xml</value>                <value>classpath*:com/cqta/dev/model/question/*.hbm.xml</value>                <value>classpath*:com/cqta/dev/model/communication/*.hbm.xml</value>                <value>classpath*:com/cqta/dev/model/teacherwork/*.hbm.xml</value>                <value>classpath*:com/cqta/dev/model/workstation/*.hbm.xml</value>                <value>classpath*:com/cqta/dev/model/acupuncture/*.hbm.xml</value>                <value>classpath*:com/cqta/dev/model/online/*.hbm.xml</value>                <value>classpath*:com/cqta/dev/model/log/*.hbm.xml</value>            </list>        </property>        <property name="hibernateProperties">            <props>                <prop key="hibernate.dialect">${hibernate.dialect}    </prop>                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>                <prop key="hibernate.show_sql">false</prop>                <prop key="hibernate.format_sql">true</prop>                <prop key="hibernate.jdbc.fetch_size">50</prop>                <prop key="hibernate.jdbc.batch_size">50</prop>                <prop key="hibernate.cache.use_query_cache ">true</prop>                <prop key="hibernate.connection.autocommit">true</prop>            </props>        </property>        <property name="eventListeners"  >                       <map>                        <entry>                         <key>                          <value>post-insert</value>                         </key>                         <ref bean="auditlogEvent" />                        </entry>                        <entry>                         <key>                          <value>post-update</value>                         </key>                         <ref bean="auditlogEvent" />                        </entry>                        <entry>                         <key>                          <value>post-delete</value>                         </key>                         <ref bean="auditlogEvent" />                        </entry>                       </map>        </property>          <property name="packagesToScan" value="com.cqta.dev.model." />        </bean><bean id="auditlogEvent" class="com.cqta.dev.web.util.LogAuditListener"></bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory"></property></bean> <aop:config proxy-target-class="true"> </aop:config>    <!-- 如果Service层出现新的pacage,需要在此处添加配置 -->    <aop:config proxy-target-class="true">        <aop:advisor pointcut="execution(public * com.cqta.dev.service.system..*.*(..))" advice-ref="txAdvice" />        <aop:advisor pointcut="execution(public * com.cqta.dev.service.authority..*.*(..))" advice-ref="txAdvice" />        <aop:advisor pointcut="execution(public * com.cqta.dev.service.workstation..*.*(..))" advice-ref="txAdvice" />        <aop:advisor pointcut="execution(public * com.cqta.core.dao..*.*(..))" advice-ref="txAdvice" />    </aop:config>    <tx:advice id="txAdvice" transaction-manager="transactionManager">        <tx:attributes>            <tx:method name="*" propagation="REQUIRED" />            <tx:method name="add*" propagation="REQUIRED" />            <tx:method name="del*" propagation="REQUIRED" />            <tx:method name="edit*" propagation="REQUIRED" />            <tx:method name="save*" propagation="REQUIRED" />        </tx:attributes>    </tx:advice></beans>
View Code

然后LogAuditListener.java代码

package com.cqta.dev.web.util;import java.io.IOException;import java.lang.reflect.Method;import java.util.Date;import java.util.HashMap;import java.util.Map;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import javax.xml.parsers.ParserConfigurationException;import org.hibernate.event.PostDeleteEvent;import org.hibernate.event.PostDeleteEventListener;import org.hibernate.event.PostInsertEvent;import org.hibernate.event.PostInsertEventListener;import org.hibernate.event.PostUpdateEvent;import org.hibernate.event.PostUpdateEventListener;import org.springframework.security.core.userdetails.User;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.NodeList;import org.xml.sax.SAXException;import com.cqta.dev.model.log.Log;import com.cqta.dev.model.log.LogAudit;import com.cqta.dev.service.online.TxtContentService;import com.cqta.dev.web.util.AppContextUtils;public class LogAuditListener implements PostInsertEventListener,PostUpdateEventListener, PostDeleteEventListener {     /**  *   */ private static final long serialVersionUID = 1L; private static String INSERT="添加"; private static String UPDATE="修改"; private static String DELETE="删除"; private static Map<String,LogAudit> logAuditMap=new HashMap<String, LogAudit>(); /**  * 添加操作   日志  */ public void onPostInsert(PostInsertEvent event) {     Class<?> clazz = event.getEntity().getClass();  try {   Log log=null;   if (logAuditMap.size() > 0) {    LogAudit logAudit=logAuditMap.get(clazz.getSimpleName());    if (logAudit != null) {        log=newLog(logAudit,INSERT);        StringBuilder content = new StringBuilder(INSERT + logAudit.getDescription());//操作说明        User user = null;  //操作人        user = SecurityUserHolder.getCurrentUser();     Object[] newState = event.getState();     String[] fields = event.getPersister().getPropertyNames();     if (newState != null && fields != null && newState.length == fields.length ) {      for (int i = 0; i < fields.length; i++) {       if(logAudit.getProperty().containsKey(fields[i])){        content.append( "\""+logAudit.getProperty().get(fields[i])+ "\"  "+newState[i]);       }      }     }     log.setDescription(content.toString());     log.setActionUserName(user!=null?user.getUsername():null);     saveOperate(log);       }   }  } catch (Exception e) {   e.printStackTrace();  } }       /**  * 修改操作  日志     */ public void onPostUpdate(PostUpdateEvent event) {  Class<?> clazz = event.getEntity().getClass();  try {   Log log=null;   if (logAuditMap.size() > 0) {    LogAudit logAudit=logAuditMap.get(clazz.getSimpleName());    if (logAudit != null) {      log =newLog(logAudit,UPDATE);      String content = UPDATE + logAudit.getDescription(); //操作说明      User user = null;  //操作人      user = SecurityUserHolder.getCurrentUser();       log.setActionUserName(user!=null?user.getUsername():null);      Object[] oldState = event.getOldState();  //获取旧值      Object[] newState = event.getState();  //获取更改后的值      String[] fields = event.getPersister().getPropertyNames();  //获取对象属性      if("User".equals(clazz.getSimpleName())){ //当对象是用用户时      将用户 单独拿出来    判断用户登录和修改密码       if(oldState != null && newState != null && fields != null && oldState.length == newState.length && oldState.length == fields.length){        boolean ref=false; //是否为登录操作        for (int i = 0; i < fields.length; i++) {         if(fields[i]=="lastlogintime" && oldState[i]!=newState[i]){ //登录操作  最后一次登录时间被修改          ref=false;break ;         }else if(fields[i]=="password" && oldState[i]!=newState[i]){ //登录操作  最后一次登录时间被修改          content = "修改密码";          ref=true;         }         if(logAudit.getProperty().containsKey(fields[i])&&! oldState[i].equals(newState[i])){          content += "{将  \"" + logAudit.getProperty().get(fields[i]) + "\"  :    \""+oldState[i]+ "\"  改为    \"" + String.valueOf(newState[i]) + "\"}";          ref=true;         }        }        if(ref){         log.setDescription(content);         saveOperate(log);        }       }       //如果修改的model不是USER      }else if (oldState != null && newState != null && fields != null && oldState.length == newState.length && oldState.length == fields.length ) {       for (int i = 0; i < fields.length; i++) {                     if(logAudit.getProperty().containsKey(fields[i])&&! oldState[i].equals(newState[i])){                  content += "{将  \"" + logAudit.getProperty().get(fields[i]) + "\"  :    \""+oldState[i]+ "\"  改为    \"" + String.valueOf(newState[i]) + "\"}";                 }       }       log.setDescription(content);       saveOperate(log);      }     }    }  } catch (Exception e) {   e.printStackTrace();  }     }       /**  * 删除操作     日志             */ public void onPostDelete(PostDeleteEvent event) {   Class<?> clazz = event.getEntity().getClass();  try {   Log log=null;   if (logAuditMap.size() > 0) {    LogAudit logAudit=logAuditMap.get(clazz.getSimpleName());    if (logAudit != null) {         log=newLog(logAudit,DELETE);         log.setDescription(DELETE+logAudit.getDescription());         User user = null;  //操作人         user = SecurityUserHolder.getCurrentUser();         log.setActionUserName(user!=null?user.getUsername():null);      saveOperate(log);        }    }   } catch (Exception e) {   e.printStackTrace();  }   }   public Log newLog(LogAudit audit,String operation){  Log log=new Log();     log.setAction(operation);       log.setCommand(audit.getOperate());     log.setActiontime(new Date());  return log; } /**  * 生成日志  * @param session  * @param entry  */ private void saveOperate(final Log entry) {  //在新的线程中打开hibernate session,解决页面数据不同不问题.   new Thread(new Runnable() {   public void run() {       TxtContentService txtContentService = (TxtContentService) AppContextUtils.getBean("txtContentService");       txtContentService.saveObject(entry);    }  }).start();    } /**  * 读取需做日志记录的XML配置文件  * @return  */   static{   try {   DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();   DocumentBuilder builder = dbf.newDocumentBuilder();   Document doc = builder.parse(LogAudit.class.getClassLoader().getResourceAsStream("auditLog.xml")); // 获取到xml文件   Element root = doc.getDocumentElement(); // 获取根元素   NodeList logAudits = root.getElementsByTagName("entity");   LogAudit log =null;   for (int i = 0; i < logAudits.getLength(); i++) {    Element ss = (Element) logAudits.item(i);    log= new LogAudit();    log.setClazz(ss.getAttribute("clazz"));     //实体类    log.setDescription(ss.getAttribute("description"));  //操作说明    log.setOperate(ss.getAttribute("operate"));     //操作项    NodeList propertys = ss.getElementsByTagName("property");//属性    Map<String,String> proMap=new HashMap<String,String>();    for(int j = 0; j < propertys.getLength(); j++){     Element e = (Element) propertys.item(j);     proMap.put(e.getAttribute("name"), e.getTextContent());    }    log.setProperty(proMap);    logAuditMap.put(ss.getAttribute("clazz"), log);   }  } catch (ParserConfigurationException e) {   e.printStackTrace();  } catch (SAXException e) {   e.printStackTrace();  } catch (IOException e) {   e.printStackTrace();  } }}
View Code

最后auditLog.xml文件

<?xml version="1.0" encoding="UTF-8"?><entities > <!-- 记录的日志的实体类 --> <entity clazz="User" description="用户" operate="用户管理">  <property name="username">用户名</property>    <property name="type">人员类型</property>    <property name="realname">真实姓名</property>   </entity> <entity clazz="Datadictionary" description="数据字典" operate="数据字典管理">  <property name="name">分类名称</property>    <property name="optionName">选项名称</property>    <property name="mtype">所属类型</property>   </entity>  </entities>
View Code

末尾附上相关model代码

Log.class

package com.cqta.dev.model.log;import java.util.Date;public class Log {    private int id;    private String action;// 用户所执行的数据操作:增|删|改    private String command;//执行的操作    private Date actiontime;// 执行此操作的时间    private String actionUserName;//操作者姓名    private int actionUserId;//操作者姓名    private String description;//操作说明    public String getAction() {        return action;    }    public void setAction(String action) {        this.action = action;    }    public String getCommand() {        return command;    }    public void setCommand(String command) {        this.command = command;    }    public Date getActiontime() {        return actiontime;    }    public void setActiontime(Date actiontime) {        this.actiontime = actiontime;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }     public String getDescription() {        return description;    }    public void setDescription(String description) {        this.description = description;    }    public String getActionUserName() {        return actionUserName;    }    public void setActionUserName(String actionUserName) {        this.actionUserName = actionUserName;    }    public int getActionUserId() {        return actionUserId;    }    public void setActionUserId(int actionUserId) {        this.actionUserId = actionUserId;    }}
View Code

Log.hbm.xml

<?xml version="1.0" encoding="utf-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.cqta.dev.model.log.Log" table="log" ><id name="id" type="java.lang.Integer"><column name="id" /><generator class="identity" /></id><property name="action" type="string"><column name="action"></column></property><property name="command" type="string"><column name="command"></column></property><property name="description" type="string"><column name="description"></column></property><property name="actionUserId" type="java.lang.Integer"><column name="actionUserId"></column></property><property name="actionUserName" type="string"><column name="actionUserName"></column></property><property name="actiontime" type="date"><column name="actiontime"></column></property> </class></hibernate-mapping>
View Code

LogAudit.class

package com.cqta.dev.model.log;import java.util.Map;public class LogAudit {private String description;//操作说明private String clazz;//需要记录日志的类private String operate;////操作项private Map<String,String>  property;public String getDescription() {    return description;}public void setDescription(String description) {    this.description = description;}public String getOperate() {    return operate;}public void setOperate(String operate) {    this.operate = operate;}public String getClazz() {    return clazz;}public void setClazz(String clazz) {    this.clazz = clazz;}public Map<String,String> getProperty() {    return property;}public void setProperty(Map<String,String> property) {    this.property = property;}}
View Code

mysql.sql-log 

CREATE TABLE `log` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `action` varchar(255) DEFAULT NULL,  `command` varchar(255) DEFAULT NULL,  `actiontime` date DEFAULT NULL,  `actionUserName` varchar(255) DEFAULT NULL,  `actionUserId` int(11) DEFAULT NULL,  `description` varchar(255) DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;
View Code

/*
Navicat MySQL Data Transfer

Source Server : server
Source Server Version : 50602
Source Host : localhost:3306
Source Database : zy_dev

Target Server Type : MYSQL
Target Server Version : 50602
File Encoding : 65001

Date: 2014-12-15 16:55:42
*/

 

SSH基于Hibernate eventListener 事件侦听器的操作日志自动保存到数据库