如何比较两个对象的字段,并记录下来?
思路
- 首先可以通过反射的手段获取field信息获取value进行比较
上代码
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE_PARAMETER})
public @interface Label {
String value() default "";
}
public class ComparisonResult {
/**
* 字段属性名
*/
private String key;
/**
* 字段注释名称
*/
private String label;
/**
* 新值
*/
private String previous;
/**
* 历史值
*/
private String later;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getPrevious() {
return previous;
}
public void setPrevious(String previous) {
this.previous = previous;
}
public String getLater() {
return later;
}
public void setLater(String later) {
this.later = later;
}
@Override
public String toString() {
return "ComparisonResult{" +
"key='" + key + '\'' +
", label='" + label + '\'' +
", previous='" + previous + '\'' +
", later='" + later + '\'' +
'}';
}
}
import com.alibaba.demo.annotation.Label;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
/**
* 比较两个对象的字段是否相等
* 并记录值
*/
public class ComparisonObjectUtil {
/**
* 比较两个对象的属性并记录对比值
* @param newObj 新对象
* @param oldObj 旧对象
* @param clazz class
* @return
*/
public static List<ComparisonResult> compareObj(Object newObj, Object oldObj, Class<?> clazz){
List<ComparisonResult> comparisonResults = new ArrayList<>();
try {
//如果传进来的object为空,为其初始化一下,防止null
if (Objects.isNull(newObj)){
newObj = clazz.newInstance();
}
if (Objects.isNull(oldObj)){
oldObj = clazz.newInstance();
}
//判断两个对象是否是统一类型
if (newObj.getClass() == oldObj.getClass()){
Map<String, Field> map = getAnnotationDesc(clazz);
for (Map.Entry<String,Field> entry : map.entrySet()) {
String desc = entry.getKey();//字段描述
Field field = entry.getValue();//字段对象
field.setAccessible(true);
Object newValue = field.get(newObj);//获取字段值
Object oldValue = field.get(oldObj);
//都为空直接跳过,没有可比对性
if (Objects.isNull(newValue) && Objects.isNull(oldValue)){
continue;
}
//创建存放结果对象,添加到List
ComparisonResult comparisonResult = new ComparisonResult();
comparisonResult.setKey(field.getName());//字段名称
comparisonResult.setLabel(desc);//字段描述
//新值为空情况下
if (newValue == null){
comparisonResult.setPrevious(null);
comparisonResult.setLater(objToString(oldValue));
comparisonResults.add(comparisonResult);
//旧值为空情况下
}else if (oldValue == null){
comparisonResult.setPrevious(objToString(newValue));
comparisonResult.setLater(null);
comparisonResults.add(comparisonResult);
//都不为空时
}else if (!newValue.equals(oldValue)){
comparisonResult.setPrevious(objToString(newValue));
comparisonResult.setLater(objToString(oldValue));
comparisonResults.add(comparisonResult);
}
}
}
} catch(Exception e){
e.printStackTrace();
}
return comparisonResults;
}
/**
* 将比较出来的值转成String类型
* @param obj 转换对象
* @return 字符串值
*/
public static String objToString(Object obj){
if (obj instanceof Byte || obj instanceof Short || obj instanceof Integer
|| obj instanceof Long || obj instanceof Boolean || obj instanceof Character
|| obj instanceof Float ||obj instanceof Double || obj instanceof List || obj instanceof Map){
return obj.toString();
}else if (obj instanceof Date){
return LocalDateTime.ofInstant(((Date)obj).toInstant(), ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:dd"));
}else if (obj instanceof LocalDateTime){
return ((LocalDateTime)obj).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:dd"));
}else if (obj instanceof LocalDate) {
return ((LocalDate)obj).format(DateTimeFormatter.ISO_LOCAL_DATE);
}else if (obj instanceof BigDecimal){
return ((BigDecimal)obj).setScale(2, RoundingMode.HALF_UP).toString();
}else if (obj instanceof String){
return (String) obj;
}
return "";
}
/**
* 获取对象的属性上有@Label注解的属性,通过LinkedHashMap存取,是为了保证按照字段的顺序,key:字段描述信息,value:Field对象
* @param clazz Class对象
* @return Map集合
*/
public static Map<String,Field> getAnnotationDesc(Class<?> clazz){
Map<String, Field> fieldMap = new LinkedHashMap<>();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
Label labelAno = field.getAnnotation(Label.class);
if (Objects.nonNull(labelAno)){
fieldMap.put(labelAno.value(),field);
}
}
return fieldMap;
}
}
public static void main(String[] args) {
Date now = new Date();
Person p1 = new Person(1L,"张三丰",now,BigDecimal.valueOf(10000.00));
Person p2 = new Person(2L,"张三丰",now,BigDecimal.valueOf(1000.996));
List<ComparisonResult> comparisonResults = compareObj(p1, p2, Person.class);
System.out.println(comparisonResults);
}
输出结果:
[ComparisonResult{key='id', label='id', previous='1', later='2'}, ComparisonResult{key='money', label='余额', previous='10000.00', later='1001.00'}]