Java对象比较器,详细记录对象前后变化的方法

需求说明##

需求是客户想跟踪数据修改前和后数据发生了那些变化,并将其输出到日志里面

思路

  1. JavaBean 增加注解,监控那些字段发生变化才会记录到日志中。
  2. 利用内省机制动态获取JavaBean对象监控的属性值(注意这里不能BeanUtils.getProperty(bean, name)这个方法,因为其转化出来的数值都是String类型的
  3. 将变更前的对象和变更后的对象分别保存到Map中,并对齐进行逐行比对,如果有不同则进行记录。

Java代码

/**
注解
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface LogCompar {
	  /**
	   * 汉字全称
	   * @return
	   */
	  String name();
	  
	  /**
	   * Date 如何格式化,默认可以为空
	   * @return
	   */
	  String dateFormat() default "";

}

核心Java代码如下


package bcode.capinfo.com.modules.sys.utils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.math.NumberUtils;

import bcode.capinfo.com.common.utils.StringUtils;
import bcode.capinfo.com.modules.enclosure.entity.CapFilesDemo;
import bcode.capinfo.com.modules.sys.anno.LogCompar;

public class Snippet {
		public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, ParseException, IntrospectionException {
	//		Log log = new Log();
	//		log.setId("f7afefe497f1428da91c3e836e9a047b");
	//		deleteOutCycleLog();
			
			CapFilesDemo c = new CapFilesDemo();
			c.setId("1");
			c.setFilename("我操");
			c.setFilesrc("你好");
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
			c.setSd(sdf.parse("2018年10月12日"));
			CapFilesDemo c2 = new CapFilesDemo();
			c2.setId("1");
			c2.setFilename("我");
			c2.setFilesrc("你好");
			c2.setSd(sdf.parse("2018年10月15日"));
			
			
			
			Map<String,LogValue> oldMap= getValuesToMap(c);
			Map<String,LogValue> newMap= getValuesToMap(c2);
			StringBuffer sb = comparatorObject(oldMap, newMap);
			System.out.println(sb.toString());
		}
		
		/**
		 * 对象比较器
		 * @param oldMap 原对象参数
		 * @param newMap 现对象参数
		 * @return 返回比较之后的结果
		 */
		private static StringBuffer comparatorObject(
				Map<String, LogValue> oldMap, Map<String, LogValue> newMap) {
			StringBuffer sb = new StringBuffer();
			if(oldMap!=null&&!oldMap.isEmpty()){
				Set<Entry<String,LogValue>> comparSet= oldMap.entrySet();
				for (Entry<String, LogValue> entry : comparSet) {
					LogValue newVo = newMap.get(entry.getKey());
					LogValue oldVo = entry.getValue();
					Object newValue = newVo.getValue();
					Object oldValue =  oldVo.getValue();
					Class<?> type = newValue.getClass();
					String typeName = newValue.getClass().getName();
					if (newVo!=null) {
						if ("java.lang.String".equals(typeName)) {
							String newStr = (String)newValue;
							String oldStr = (String)oldValue;
							if (!StringUtils.equals(newStr, oldStr)) {
								sb.append(showMsg(newVo, newStr, oldStr));
							}
						}else if ("java.sql.Timestamp".equals(typeName)) {
							DateFormat format = new SimpleDateFormat(StringUtils.isBlank(newVo.getFormat())?"yyyy-MM-dd HH:mm:ss":newVo.getFormat());
							java.sql.Timestamp newTime = (java.sql.Timestamp)newValue;
							java.sql.Timestamp oldTime = (java.sql.Timestamp)oldValue;
							String newTempTimeStr = "";
							String oldTimeTimeStr = "";
							if (newTime!=null) {
								 newTempTimeStr = format.format(newTime);
							}
							if(oldTime!=null)  {
								oldTimeTimeStr = format.format(oldTime);
							}
							if (!StringUtils.equals(newTempTimeStr, oldTimeTimeStr)) {
								sb.append(showMsg(newVo, format.format(newTime), format.format(oldTime)));
							}
						}else if ("java.lang.Long".equals(typeName) || Long.TYPE == type) {
							java.lang.Long newLog = NumberUtils.createLong(NumberUtils.isNumber(newValue+"")?newValue+"":"0");
							java.lang.Long oldLog = NumberUtils.createLong(NumberUtils.isNumber(oldValue+"")?oldValue+"":"0");
							if(newLog.compareTo(oldLog)!=0){
								sb.append(showMsg(newVo, newLog, oldLog));
							}
						}else if ("java.lang.Integer".equals(typeName) || Integer.TYPE == type) {
							java.lang.Integer newInt = NumberUtils.createInteger(NumberUtils.isNumber(newValue+"")?newValue+"":"0");
							java.lang.Integer oldInt = NumberUtils.createInteger(NumberUtils.isNumber(oldValue+"")?oldValue+"":"0");
							if(newInt.compareTo(oldInt)!=0){
								sb.append(showMsg(newVo, newInt, oldInt));
							}
						}else if ("java.lang.Boolean".equals(typeName) || Boolean.TYPE == type) {
							java.lang.Boolean newbool = BooleanUtils.toBoolean(newValue+"")?true:false;
							java.lang.Boolean oldbool = BooleanUtils.toBoolean(oldValue+"")?true:false;
							if(newbool!=oldbool){
								sb.append(showMsg(newVo, newbool, oldbool));
							}
						} else if ("java.lang.Character".equals(typeName)
								|| Character.TYPE == type) {
							// 预留
						} else if ("java.lang.Byte".equals(typeName) || Byte.TYPE == type) {
							//预留不处理
						} else if ("java.lang.Short".equals(typeName) || Short.TYPE == type) {
							//预留不处理 有需要在处理
						} else if ("java.lang.Float".equals(typeName) || Float.TYPE == type) {
							java.lang.Float newFloat = NumberUtils.createFloat(NumberUtils.isNumber(newValue+"")?newValue+"":"0");
							java.lang.Float oldFloat = NumberUtils.createFloat(NumberUtils.isNumber(oldValue+"")?oldValue+"":"0");
							if(newFloat.compareTo(oldFloat)!=0){
								sb.append(showMsg(newVo, newFloat, oldFloat));
							}
						} else if ("java.lang.Double".equals(typeName) || Double.TYPE == type) {
							java.lang.Double newDouble = NumberUtils.createDouble(NumberUtils.isNumber(newValue+"")?newValue+"":"0");
							java.lang.Double oldDouble = NumberUtils.createDouble(NumberUtils.isNumber(oldValue+"")?oldValue+"":"0");
							if(newDouble.compareTo(oldDouble)!=0){
								sb.append(showMsg(newVo, newDouble, oldDouble));
							}
						} else if ("java.util.Date".equals(typeName)) {
							DateFormat format = new SimpleDateFormat(StringUtils.isBlank(newVo.getFormat())?"yyyy-MM-dd":newVo.getFormat());
							java.util.Date newTime = (java.util.Date)newValue;
							java.util.Date oldTime = (java.util.Date)oldValue;
							String newTempTimeStr = "";
							String oldTimeTimeStr = "";
							if (newTime!=null) {
								 newTempTimeStr = format.format(newTime);
							}
							if(oldTime!=null)  {
								oldTimeTimeStr = format.format(oldTime);
							}
							if (!StringUtils.equals(newTempTimeStr, oldTimeTimeStr)) {
								sb.append(showMsg(newVo, format.format(newTime), format.format(oldTime)));
							}
						}
					}
				}
			}
			return sb;
		}
		/**
		 * 页面标记
		 * @param newVo
		 * @param newLog
		 * @param oldLog
		 * @return
		 */
		private static String showMsg(LogValue newVo, Object newLog,
				Object oldLog) {
			return "["+newVo.getName()+"]发生变化由原先的:"+oldLog+"改变为:"+newLog+"<br>";
		}
		/**
		 * 将要转化的对象进行拆分为Map<String,LogValue> LogValue 保存自定义标签的名称 和 数值等内容
		 * @param entity
		 * @return
		 * @throws IllegalAccessException
		 * @throws InvocationTargetException
		 * @throws NoSuchMethodException
		 * @throws IntrospectionException 
		 */
		private static Map<String,LogValue> getValuesToMap(Object entity)
				throws IllegalAccessException, InvocationTargetException,
				NoSuchMethodException, IntrospectionException {
			Map<String,LogValue> comparMap = new HashedMap();
	        java.lang.reflect.Field[] fields = entity.getClass().getDeclaredFields();
	        for (int i = 0; i < fields.length; i++) {
	            String name = fields[i].getName();
	            if(PropertyUtils.isReadable(entity, name) && PropertyUtils.isWriteable(entity, name)) {
	            	if(fields[i].isAnnotationPresent(LogCompar.class)){
	            		LogCompar logVo = fields[i].getAnnotation(LogCompar.class);
	            		LogValue lv = new LogValue(logVo.name(),getProperties(entity, name),logVo.dateFormat());
	            		comparMap.put(name, lv);
	            	}
	            }
	        }
	        return comparMap;
		}
		
		/**
		 * 利用内省机制来获取参数
		 * @param b
		 * @param name
		 * @return
		 * @throws IntrospectionException
		 * @throws IllegalAccessException
		 * @throws InvocationTargetException
		 */
	    private static Object getProperties(Object b, String name)  
	            throws IntrospectionException, IllegalAccessException,  
	            InvocationTargetException {  
	        /*  
	        PropertyDescriptor p = new PropertyDescriptor(name, b.getClass());  
	        //通过内省的方法来执行制定字段的get方法  
	        Method mathGet = p.getReadMethod();  
	        mathGet.setAccessible(true);  
	        Object age = mathGet.invoke(b);*/  
	
	        BeanInfo beanInfo = Introspector.getBeanInfo(b.getClass());  
	        PropertyDescriptor[] mathAll = beanInfo.getPropertyDescriptors();  
	        Object value = null;  
	        for(PropertyDescriptor pd:mathAll){  
	            if(pd.getName().equals(name)){  
	                Method mathGet = pd.getReadMethod();  
	                mathGet.setAccessible(true);  
	                value = mathGet.invoke(b);  
	            }  
	        }  
	          
	        return value;  
	    } 
		
}




测试JavaBean

/**
 * 测试的JavaBean
 * @author litaolin
 * @version 2018-04-23
 */
public class CapFilesDemo extends DataEntity<CapFilesDemo> {
	
	private static final long serialVersionUID = 1L;
	@LogCompar(name="文件名")
	private String filename;		// 文件名
	@LogCompar(name="地址")
	private String filesrc;		// 文件地址
	@LogCompar(name="日期验证",dateFormat="yyyy年MM月dd日")
	private Date sd;
	
	
	public CapFilesDemo() {
		super();
	}

	public CapFilesDemo(String id){
		super(id);
	}

	@Length(min=0, max=64, message="文件名长度必须介于 0 和 64 之间")
	public String getFilename() {
		return filename;
	}

	public void setFilename(String filename) {
		this.filename = filename;
	}
	
	@Length(min=0, max=500, message="文件地址长度必须介于 0 和 500 之间")
	public String getFilesrc() {
		return filesrc;
	}

	public void setFilesrc(String filesrc) {
		this.filesrc = filesrc;
	}

	public Date getSd() {
		return sd;
	}

	public void setSd(Date sd) {
		this.sd = sd;
	}
}

补充一下: 这个就是一个普通的javabean类,上次写文档的时候没有加,这次补上


/**
 * 用于保存自定义注解中解析后的数据
 *
 */
public class LogValue {
	/**
	 * 中文名称
	 */
	private String name;
	/**
	 * 属性值
	 */
	private Object value;
	/**
	 * 日期格式化
	 */
	private String format;
	
	public LogValue(String name, Object value,String format) {
		super();
		this.name = name;
		this.value = value;
		this.format=format;
		
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

	public Object getValue() {
		return value;
	}
	public void setValue(Object value) {
		this.value = value;
	}
	public String getFormat() {
		return format;
	}
	public void setFormat(String format) {
		this.format = format;
	}

}

执行结果

[日期验证]发生变化由原先的:2018年10月12日改变为:2018年10月15日
[文件名]发生变化由原先的:我操改变为:我

说明执行成功

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值