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 ...
随机推荐
- Visual Studio 2015 Update 2
Visual Studio Community 2015(带Update2)(社区版,针对个人免费): 简体中文版 || SHA1:待更新 繁体中文版 || SHA1:待更新 英文版 || SHA1: ...
- 解决:j-link V8下载器灯不亮,无法正常烧写固件
昨天j-link V8下载仿真F4正常,下午下载仿真F1后吃了个饭,然后它的灯就不亮了...按照这个例程弄了好几遍都不行,http://www.cr173.com/soft/98542.html,卡在 ...
- cocos2dx-3.9 集成admob
Part 1: 安装GoogleMobileAds framework (即admob) 1. 安装Cocoapods,否则解决依赖关系和配置真的会把人不累死也得烦死 sudo gem install ...
- # mysql -u root -p -bash: mysql: command not found
[root@jboss ~]# mysql -u root -p-bash: mysql: command not found 需要安装mysql # yum install mysql之后就行 了
- alpha值的问题
但凡图像都会涉及到透明度问题.使用透明度之后就可以看到多层图像.Alpha值就是用于描述透明度的参量.Alpha值是一个百分数,alpha=1表示源文件发出的光全部被观察者观察到. 既然是透明度,那么 ...
- JSP页面组件
一.JSP指令 1.page指令 定义:将关于JSP页面一般设置通知给web容器的属性. 语法:<%@ page attribute_list%> 属性:language;extends; ...
- 如何启动app时全屏显示Default.png(图片)?
- js 自运行函数作用
var obj = new Object(); function test2() { for (var i=1;i<5;i++) { obj['f'+i] = function() { retu ...
- 黑马----JAVA内部类
黑马程序员:Java培训.Android培训.iOS培训..Net培训 黑马程序员--JAVA内部类 一.内部类分为显式内部类和匿名内部类. 二.显式内部类 1.即显式声明的内部类,它有类名. 2.显 ...
- SDK截图(三):压缩位图之理论准备篇
压缩位图我们使用简单的行程长度编码的方法,详情参考<windows程序设计>15章之DIB压缩. 在BITMAPINFOHEADER结构中有两个和位图压缩有关的字段,分别是biCompre ...