`

对象修改日志

    博客分类:
  • Java
 
阅读更多
转自:http://hi.baidu.com/419848854/blog/item/4aef20de4464785a95ee37de.html

1.对于金融业务系统中,我们常常需要记录当前用户修改了哪张表中的哪个字段以及修改前的值和修改后的值,对于业务要求较高的公司是非常必须的,这里我主要讲解以下我自己的解决方案:
我所用的框架为SPRING2+Struts2+IBATIS,主要选用IBATIS而不选用HIBERNATE的原因:方便优化SQL ,开发人员上手容易,SQL配置方便,主要还是和更新明细日志记录解决方案相照应。
前期准备工作:
1.对于要记录更新明细日志的IBATIS操作,IBATIS传入的参数必须为Java Bean,如

<statement id="updateRkItemTotal"   parameterClass="com.datadriver.risk.po.RkItemTotal">
update s_baseinfo set fcode=#fcode#,
ITCODE=#itcode#,
ITSHORTNAME=#itshortname#
where S_ID=#sid#
</statement>


2.自定义注解:
Bean类 注解

/**
* @author: zhengjianbo/Ram
* @Email: zhengjianbo2@hotmail.com
* @Company: DataDriver©2010/www.datadriver.com.cn
* @Action: 类注解接口
* @DATE: 2010-9-14-上午07:47:46
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface BeanAnnotation
{

/**
* 类信息说明,主要保存该Bean对应的表名
*
* @return 注解信息
*/
public String msg();

/**
* 编辑保存日志时需要获取原有数据进行比较
*
* @return 通过返回的ibatis statement获取原有数据
*/
public String ps();

/**
* @return 返回表格
*/
public String table();
}



Bean类元素注解



/**
* @author: zhengjianbo/Ram
* @Email: zhengjianbo2@hotmail.com
* @Company: DataDriver©2010/www.datadriver.com.cn
* @Action: Bean元素注解接口
* @DATE: 2010-9-14-上午07:53:10
*/

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldAnnotation
{
/**
* 主要用于说明元素对应的字段属性名
*
* @return 元素注解说明
*/
public String name();

/**
* @return 返回字段名
*/
public String column();

}


现在比如我想对一个项目名称的更新操作记录详细的日志,则需要做以下工作:

首先,对于需要传入的JavaBean参数加入注解信息:

/**
* @author: zhengjianbo/Ram
* @Email:zhengjianbo2@hotmail.com
* @Company:DataDriver
* @Action: 指标总表实体
* @DATE: 2010-4-3-上午03:43:25
*/
@BeanAnnotation(msg="指标总表", table="S_BASEINFO", ps="common.getRkItemTotalToLog")

public class RkItemTotal implements java.io.Serializable
{
@FieldAnnotation(name="指标编码", column="ITCODE")
private String itcode;
@FieldAnnotation(name="指标简称", column="ITSHORTNAME")
private String itshortname;
private String orderstr;// 升降序字段 主要用于判断升序还是降序
@FieldAnnotation(name="基金代码", column="FCODE")
private String fcode;

private long sid;//id唯一标识符
private long fcodel;

private int actiontype; // 操作类型,只当需要记录日志的时候才使用,如果需要记录日志则该Bean必须要有该元素


其中主要需要填写的为:ps(该参数需要填写对应的IBATIS xml文件中的statement id 通过该ID,传入该Bean实体(该Bean为修改好后要传给IBATIS的参数,但其中的某个主键元素可以在PS的statement中获取该数据未修改前的状态)即可获得原有数据)如:
<statement id="getRkItemTotalLog"
    parameterClass="java.lang.Long"  --注意:如果其中只有一个参数可以使用java.lang.Long也可以为com.datadriver.risk.po.RkItemTotal,如果有超过一个参数值,则必须为Java Bean
resultClass="com.datadriver.risk.po.RkItemTotal">
SELECT  fcode,fname as itshortname
from s_baseinfo
where fcode=#sid#
</statement>



准备工作结束后,我们需要在Dao层中统一进行判断:
我将Dao层的增删改操作统一集成为一个方法:
/**
* 更新数据 包括删除添加修改 并保存操作记录以及详细步骤到数据库
*
* @param obj statement节点配置的parameterClass参数实体
* @param action xml文件中的statement的id
*
*/
void updateAttributeByPoJo(Object obj, String action){
getSqlMapClientTemplate().update(action, obj);// 执行操作
}


在service层中根据实际业务需求调用不同操作方法:
/**
* @param obj 参数实体
*/
void updateRkItemTotal(RkItemTotal obj){
commonDao.updateAttributeByPoJo(obj, "common.updateRkItemTotal");
}



有于我们的增删改统一走一个方法,这样就方便我们对所有操作类型扩展,虽然不可能扩展所有,但可以则中,如我们在Java Bean 加入的actiontype元素,我们可以在Dao方法中通过反射的方式获取Java bean中的该元素值:通过扩展updateAttributeByPoJo方法
     public void updateAttributeByPoJo(Object obj, String action)
{
int actionFlag=0;
if(obj!=null)
{
actionFlag=AnnotationUpdateType.getAction(obj);
}else
{
actionFlag=0;
}
DataDriverLog.log.info("actionFlag:"+actionFlag);
先通过反射获取actiontype元素的值,然后根据用户设定给Bean的值来区别操作,如下
/** 更新操作,只适用于更新单独的数据 */
if(actionFlag==Configer.UPDATE)
{
//annotationLog=new AnnotationUpdateLogImpl();
// annotationLog.log(getSqlMapClientTemplate(), obj); 这里用于保存更新记录的详细日志,如保存修改了表S_BASEINFO的S_TYPE字段,将内容从1 改为了2.
getSqlMapClientTemplate().update(action, obj);// 执行操作
return;
}


具体根据obj(要更新的 JavaBean)来查找更新前的数据来和该Bean进行比较,主要通过反射机制获取Bean 以及元素信息,然后通过注解方式获取需要的字段信息,表信息以及ps(获取未更新前的数据的IBATIS statementID),然后再进行比较。。。主要类如下:

/**
* @author: zhengjianbo/Ram
* @Email: zhengjianbo2@hotmail.com
* @Company: DataDriver©2010/www.datadriver.com.cn
* @Action: 用于保存类注解,实体类数据(反射获取)等元素信息
* @DATE: 2010-9-25-上午09:48:05
*/
public class AnnotationDataer
{
private Object t;
private Field[] fields;// 实体类元素数组
private Fielder[] fielders;// 实体
private Class clazz;// 当前实体类

public Fielder[] getFielders()
{
this.fields=this.getFieldByObj();
this.fielders=new Fielder[this.fields.length];
for(int i=0; i<fields.length; i++)
{
this.fielders[i]=new Fielder();
this.fielders[i].setField(fields[i]);
this.fielders[i].setFieldname(this.fields[i].getName());
this.fielders[i].setObj(this.getFieldData(fields[i]));
}
return fielders;
}

public Field[] getFieldByObj()
{
return t.getClass().getDeclaredFields();// 获得属性
}

/**
* @param field 元素
* @return 获取该元素的值
* @throws Exception 抛出异常
*/
public Object getFieldData(Field field)
{
return this.getFieldDataByName(field.getName());
}

/**
* @param fieldName 元素名称
* @return 获取元素值
*/
public Object getFieldDataByName(String fieldName){
try
{
PropertyDescriptor pd=new PropertyDescriptor(fieldName, this.getClazz());
Method getMethod=pd.getReadMethod();// 获得get方法
Object o=getMethod.invoke(t);// 执行get方法返回一个Object
DataDriverLog.log.debug("参数"+fieldName+"获取值:"+o+",值类型:");
return o;
}catch(Exception e)
{
e.printStackTrace();
return null;
}
}

/**
* @return 获取实体类注解
*/
public BeanAnnotation getBeanAnnotation()
{
return t.getClass().getAnnotation(BeanAnnotation.class);
}

public Object getT()
{
return t;
}

public void setT(Object t)
{
this.t=t;
}

public Field[] getFields()
{
return fields;
}

public void setFields(Field[] fields)
{
this.fields=fields;
}

public Class getClazz()
{
clazz=this.getT().getClass();
return clazz;
}

public void setClazz(Class clazz)
{
this.clazz=clazz;
}

public void setFielders(Fielder[] fielders)
{
this.fielders=fielders;
}

}
public void log(SqlMapClientTemplate template, Object obj)
{
List<Loger> logList=new ArrayList<Loger>();
AnnotationDataer annotationDataer=new AnnotationDataer();
annotationDataer.setT(obj);

BeanAnnotation beanAnnotation=annotationDataer.getBeanAnnotation();
String table=beanAnnotation.table();// 表名
Object oldObj=template.queryForObject(beanAnnotation.ps(), obj);// 获取数据
AnnotationDataer oldAnnotationDataer=new AnnotationDataer();
oldAnnotationDataer.setT(oldObj);

Fielder[] fielders=annotationDataer.getFielders();
/*****************************************
* 遍历要修改的数据
****************************************/
for(Fielder fielder : fielders)
{
String fieldname=fielder.getFieldname();// 字段名称(元素名称)
FieldAnnotation fieldAnnotation=fielder.getFieldAnnotation(fielder
.getField());
Object dataObj=fielder.getObj();
if(fieldAnnotation!=null)
{
Object oldDataObj=oldAnnotationDataer
.getFieldDataByName(fieldname);// 原始数据
/** 更新数据时才记录* */
if(dataObj!=null)
{
if(!(dataObj+"").equals(oldDataObj+""))
{
Loger loger=new Loger();
loger.setTable(table);
loger.setColumn(fieldAnnotation.column());
loger.setSold(oldDataObj+"");
loger.setSnew(dataObj+"");
// loger.setTuser(UserSession.get("").toString());
logList.add(loger);
}
}
}
}
分享到:
评论

相关推荐

    对象字段变化比较工具

    对象更改比较工具类,用于比较字段变化值,抛砖引玉,欢迎指正。

    SQLserver日志恢复工具 v1.0.zip

    3对于主事务记录,可以通过选择对象表和时间限制(指定时间向后一天内)来查找日志记录。单击《查找》按钮 4找到需要恢复的主事务记录后,点主事务记录则会显示详细操作日志记录,单击《浏览删除数据》按钮则显示被...

    log4pb, pb的日志组件, 后台线程记录日志

    SQL目录包含一些数据库对象,目前支持postgresql和MS SQL(修改下表log4pb_log可支持其他数据库) // SQL文件在appliation的SQLCA.database中执行 // 5. 演示集成代码已表示出[*** log4pb integrated code],可搜索...

    自定义日志脱敏组件,简单3 步完成 Spring Boot 的日志脱敏

    两种方式各有优缺点:第一种方式需要修改代码,不符合开闭原则。第二种方式,需要在日志方法的参数进行脱敏,对原生日志有入侵行为。 本组件说明 本组件基于非入侵及脱敏字段扩展考虑,采用yml配置文件来扩展脱敏...

    CakePHP-Audit-Log-Plugin, 记录在CRUD操作期间对对象所做的更改.zip

    CakePHP-Audit-Log-Plugin, 记录在CRUD操作期间对对象所做的更改 审计日志插件针对的日志插件 2 1. x. 为每个连接的模型创建一个审计历史。行为跟踪两个级别上的更改。 它获取完全水合对象的快照,在更改之后,更改...

    方法抛出的异常处理 (2)修改UserDaoImp1类,要求用户id不能修改,修改则抛出异常 使用log4j输出日志信息

    (1)对空的User类对象调用getUserInfo()方法抛出的异常处理 (2)修改UserDaoImp1类,要求用户id不能修改,修改则抛出异常 (3)使用log4j输出日志信息 2.技能训练 (1)会使用try-catch-finally捕获和处理异常 ...

    java日志记录工具类

    调用方法:IndexDataLog.print(入参),可以设置文件大小,文件写满以后自动创建新的日志文件。一般用来记录用户的搜索词,或操作记录。目前以json格式保存日志,入参稍作修改,可以传入对象,linux和windows都支持。

    object-path-immutable:修改深层对象属性而不修改原始对象(不变性)。 非常适合React和Redux

    小型JS库,无需修改原始对象即可修改深层对象的属性(不变性)。 与React(特别是在使用setState() )和Redux(在reducer内部)配合使用时效果很好。 这可以看作是React Immutability Helpers和Immutable.js的一种...

    使用log4j进行日志记录

    另一种是动态配置,Log4j提供了PropertyConfigurator.configure(……)来动态配置,参数可以是一个properties文件所在路径的String对象,可以是一个properties文件所在路径的URL对象,也可以是一个properties对象。...

    log4net 自定义对象存数据库

    使用log4net自定义日志对象向,将日志对象存入数据库中,现在不能存Guid类型的属性字段,如果想存Guid类型的字段需要修改log4net源代码AdoNetAppender类中FormatValue方法

    日志记录组件log4web.js.zip

    简介基于浏览器端的console的日志记录组件。支持如下特性:日志级别设置;异常提交到服务器;提交环境信息;日志Tag过滤器;如何使用浏览器下的引用...如果不想依赖jquery,可自行修改相关代码。 标签:log4web

    sslkeylog:一个以NSS密钥日志格式记录SSL会话密钥的Ruby库

    分析网络流量时,诸如的工具可以使用此日志来解密数据。 注意:此版本的库是功能原型。 将来可能会更改实现。安装该gem使用C扩展名从Ruby OpenSSL::SSL::SSLSocket对象提取数据。 这意味着必须使用与编译Ruby解释器...

    远程数据库对象 通过ADO对象实现远程数

    //创建远程服务对象 (参数1 服务端口号 日志对象,如果不需要记录日志请填nil) Gob_RmoDBsvr := TRmodbSvr.Create(FSvrPort, nil); //连接数据库 可以是ADO支持的所有数据库 调用TDBMrg提供的获取各种数据库的链接...

    warhol:用于基于对象状态的日志记录的节点模块

    构建一个模型对象,然后是一个日志行数组,每当模型对象更改时,该模块将更新一个文本块。 日志行模板是使用 json-paths 构建的(有关示例,请参见 )安装$ npm install --save warhol用法 var warhol = require ( ...

    基于Python+MySQL+日志文件 实现的监控报表+源代码+文档说明

    # A chart by Python ...3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 --------

    Asp.Net Core用NLog记录日志操作方法

    4.统一的写日志方法,不用每次get一个logger对象(或依赖注入)来记日志 安装包 在nuget中安装NLog和NLog.Web.AspNetCore ,这两个是NLog相关的包。 还需要安装NLog写入数据库的数据库适配器,我这里写入到MySQL...

    persist:Golang的简单持久性或重放日志

    此Golang包实现的持久性日志非常类似于数据库重播日志或预写日志(WAL):在对资源(任意数据结构)进行更改之前,应用程序将资源的新状态写入日志。 如果应用程序崩溃,可以重播日志以重新创建所有资源。 诀窍是...

    SQL Server 面面观?数据库对象

    SQL Server 2008包含许多对象,主要的数据库对象有:数据库、事务日志、表、模式、文件组、图表、视图、存储过程、用户自定义函数、用户和角色、规则、默认值、用户自定义数据类型、全文目录。  一、数据库对象 ...

    java-操作记录-对比操作前后不同

    该jar中内放了实现功能的class,代码比较易于理解,可以直观的看出效果

    django-auditlog, 保存对对象所做更改的Django 应用程序.zip

    django-auditlog, 保存对对象所做更改的Django 应用程序 请记住,这个应用还在开发中。 在生产环境中部署这里应用程序之前,请先对它的进行英镑测试。 django-auditlog ( Auditlog ) 是一个用于 Django的可以重用...

Global site tag (gtag.js) - Google Analytics