SSH基于Hibernate eventListener 事件侦听器的操作日志自动保存到数据库
- 在spring xml配置文件中添加配置,包含:model、listener
- 在model中增加需要写入数据库对应表的model
- 在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>
然后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();
}
}
}
最后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>
末尾附上相关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;
} }
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>
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;
}
}
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;
/*
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 事件侦听器的操作日志自动保存到数据库的更多相关文章
- JavaScript DOM高级程序设计 4.3控制事件流和注册事件侦听器--我要坚持到底!
一.事件流 我们通过下面一个实例,进行说明. <body> <h1>Event Flow</h1> <ul id="nav"> &l ...
- js事件流、事件处理程序/事件侦听器
1.事件流 事件冒泡 IE的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档). 事件捕获 ...
- Android事件侦听器回调方法浅谈
http://developer.51cto.com/art/201001/180846.htm Android事件侦听器作为视图View类的接口,其中包含有不少回调方法,比如:onClick():o ...
- javascript中事件总结&通用的事件侦听器函数封装&事件委托
前言: JAVASCRIPT与HTML之间的交互是通过事件来实现的.事件,就是文档或浏览器窗口中发生的一些特定交互瞬间.可以使用侦听器( 或处理程序 )来预定事件,以便事件发生时执行相应的代码.这种在 ...
- 052_末晨曦Vue技术_处理边界情况之程序化的事件侦听器
程序化的事件侦听器 点击打开视频讲解更详细 现在,你已经知道了 $emit 的用法,它可以被 v-on 侦听,但是 Vue 实例同时在其事件接口中提供了其它的方法.我们可以: 通过 $on(event ...
- 【JavaScript代码实现二】通用的事件侦听器函数
// event(事件)工具集,来源:github.com/markyun markyun.Event = { // 页面加载完成后 readyEvent : function(fn) { if (f ...
- Unity3D 自定义事件(事件侦听与事件触发)
先来看下效果图,图中点击 Cube(EventDispatcher),Sphere(EventListener)以及 Capsule(EventListener)会做出相应的变化,例子中的对象相互之间 ...
- java里的MouseLisetener接口的使用过程==========需要用组件是来注册侦听器
总结:通过匿名类来实现鼠标的监听或者 通过实现接口的方法都可以的 从此是实现MouseListener接口的方式 package com.a.b; import java.awt.Color; im ...
- 异常将上下文初始化事件发送到类的侦听器实例.[org.springframework.web.context.ContextLoaderListener] org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class p
严重: 异常将上下文初始化事件发送到类的侦听器实例.[org.springframework.web.context.ContextLoaderListener]org.springframework ...
随机推荐
- 1、C#基础:变量、运算符、分支、循环、枚举、数组、方法 <转>
转自:海盗船长 链接:http://www.cnblogs.com/baidawei/p/4701504.html#3241882 C#..Net以及IDE简介 一.什么是.Net? .Net指 .N ...
- 【Java讨论】引用类型赋值为null对加速垃圾回收的作用(转载)
:有一些人认为等于null可以帮助垃圾回收机制早点发现并标识对象是垃圾.其他人则认为这没有任何帮助.是否赋值为null的问题首先在方法的内部被人提起.现在,为了更好的阐述提出的问题,我们来撰写一个Wi ...
- pip 下载慢
经常在使用Python的时候需要安装各种模块,而pip是很强大的模块安装工具,但是由于国外官方pypi经常被墙,导致不可用,所以我们最好是将自己使用的pip源更换一下,这样就能解决被墙导致的装不上库的 ...
- C#队列
队列(Queue)是插入操作限定在表的尾部而其它操作限定在表的头部进行的线性表.把进行插入操作的表尾称为队尾(Rear),把进行其它操作的头部称为队头(Front).当对列中没有数据元素时称为空对列( ...
- C#常用操作类库一(验证类)
public class Validator { #region 验证输入字符串为数字 /// <summary> /// 验证输入字符串 ...
- 使用AdvinceInstaller把exe或者msi重新包装成为msi静默安装程序
最近在学习installShelled打包.net做的软件,其中mysql数据库的静默安装脚本不会写,本人新手勿喷.在不会写脚本的方式下,偶然间看见了这个AdvinceInstaller可以吧.exe ...
- iOS给UIimage添加圆角的两种方式
众所周知,给图片添加圆角有CALayer的cornerRadius, 比如: 最直接的方法: imgView.layer.cornerRadius1=110; imgView.clipsToBou ...
- oracle行转列,decode 等用法
DECODE()函数,它将输入数值与函数中的参数列表相比较,根据输入值返回一个对应值.函数的参数列表是由若干数值及其对应结果值组成的若干序偶形式.当然,如果未能与任何一个实参序偶匹配成功,则函数也有默 ...
- 修改hive分区表,在分区列前增加一个字段
本文主要为了测试,在有数据的分区表中增加新的一个非分区字段后,新数据加入表中是否正常. 原始数据 1;zhangsan 2;zhangsan 3;zhangsan 4;lisi 5;lisi 6;li ...
- linux 查找文件与进程常用命令
Linux的五个查找命令 1. find find是最常见和最强大的查找命令,你可以用它找到任何你想找的文件. find的使用格式如下: $ find <指定目录> <指定条件> ...