对象修改日志

转自:[url]http://hi.baidu.com/419848854/blog/item/4aef20de4464785a95ee37de.html[/url]

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);
}
}
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值