对象修改日志
转自: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" parametername="code">/*** @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();}
/*** @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();}
/*** @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必须要有该元素
<statement id="getRkItemTotalLog" parameter --注意:如果其中只有一个参数可以使用java.lang.Long也可以为com.datadriver.risk.po.RkItemTotal,如果有超过一个参数值,则必须为Java Beanresultname="code">/*** 更新数据 包括删除添加修改 并保存操作记录以及详细步骤到数据库** @param obj statement节点配置的parameterClass参数实体* @param action xml文件中的statement的id**/void updateAttributeByPoJo(Object obj, String action){getSqlMapClientTemplate().update(action, obj);// 执行操作}
/*** @param obj 参数实体*/void updateRkItemTotal(RkItemTotal obj){commonDao.updateAttributeByPoJo(obj, "common.updateRkItemTotal");}
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;}
/*** @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方法返回一个ObjectDataDriverLog.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);}}}}