最近有个业务需求,要把那些被更改过值得字段名称、字段变量名称,改动前后的值记录下来,然后就写了个工具类,各位大佬要是有啥地方可以优化或者是存在BUG,可以给我留言。
public class CompareClassFields {
/**
* 比较相同或不同的类对象中相同的字段名称的值是否存在差异
* @param changedClass 被改变后的类对象
* @param initialClass 原始的类对象
* @return 被改变的字段的变量名,以逗号分隔开
*/
public static <T> String compareToFields(T changedClass, T initialClass) {
if(null == changedClass || null == initialClass ){
throw new CompareClassFieldException("Parameters are not allowed null");
}
StringJoiner stringJoiner = new StringJoiner(",");
//获得类对象
Class<?> firstClass = changedClass.getClass();
Class<?> secondClass = initialClass.getClass();
//获得类中所有的字段
Field[] changedFields = firstClass.getDeclaredFields();
for(int i = 0; i < changedFields.length; i++) {
changedFields[i].setAccessible(true);
//判断有没有自定义的注解
if (changedFields[i].isAnnotationPresent(CompareField.class)) {
try{
String fieldName = changedFields[i].getName();
Field declaredField = secondClass.getDeclaredField(fieldName);
declaredField.setAccessible(true);
if(null != secondClass.getDeclaredField(fieldName)
&& checkFields(changedFields[i].get(changedClass), declaredField.get(initialClass))){
stringJoiner.add(fieldName);
}
} catch(IllegalAccessException | NoSuchFieldException ignore){}
}
}
return stringJoiner.toString();
}
/**
* 比较相同或不同的类对象中相同的字段名称的值是否存在差异
* @param changedClass 被改变的类对象
* @param initialClass 原始的类对象
* @return 被改变的字段名称,改动前和改动后的值
*/
public static <T> List<CompareFieldsDomain> compareToFieldsAndGetValue(T changedClass, T initialClass) {
if(null == changedClass || null == initialClass ){
throw new CompareClassFieldException("Parameters are not allowed null");
}
//获得类对象
Class<?> firstClass = changedClass.getClass();
Class<?> secondClass = initialClass.getClass();
List<CompareFieldsDomain> list = new ArrayList<>();
//获得被改动的类中所有的字段
Field[] changedFields = firstClass.getDeclaredFields();
//遍历,进行改动前后的值比较
for(int i = 0; i < changedFields.length; i++) {
changedFields[i].setAccessible(true);
CompareField annotation = changedFields[i].getAnnotation(CompareField.class);
//判断有没有自定义的注解
if (changedFields[i].isAnnotationPresent(CompareField.class)) {
try{
String fieldName = changedFields[i].getName();
//获得初始类的字段,并设置权限
Field declaredField = secondClass.getDeclaredField(fieldName);
declaredField.setAccessible(true);
if(null != secondClass.getDeclaredField(fieldName)
&& checkFields(changedFields[i].get(changedClass), declaredField.get(initialClass))){
//如果等于1,证明需要进行“是,否”与“1,0”的转换
if("1".equals(annotation.type())){
//记录改动的值
list.add(new CompareFieldsDomain(annotation.name(),
(Integer) declaredField.get(initialClass) == 1 ? "是" : "否",
(Integer) changedFields[i].get(changedClass) == 1 ? "是" : "否"));
}else{
list.add(new CompareFieldsDomain(annotation.name(),
declaredField.get(initialClass), changedFields[i].get(changedClass)));
}
}
} catch(IllegalAccessException | NoSuchFieldException ignore){}
}
}
return list;
}
private static boolean checkFields(Object o1, Object o2){
if(null != o1){
return !o1.equals(o2);
}else {
return null != o2;
}
}
}
public class CompareClassFieldException extends RuntimeException {
public CompareClassFieldException(String message){
super(message);
}
}
@Data
public class CompareFieldsDomain {
/**
* 字段的名字
*/
private String fieldName;
/**
* 字段改动前的值
*/
private Object beforeValue;
/**
* 字段改动后的值
*/
private Object afterValue;
public CompareFieldsDomain(String fieldName, Object beforeValue, Object afterValue) {
this.fieldName = fieldName;
this.beforeValue = beforeValue;
this.afterValue = afterValue;
}
public CompareFieldsDomain() {
}
}
下面是相应注解,实体类中哪个字段需要进行比较,就写上去,如下图所示
@Target({FIELD})
@Retention(RUNTIME)
public @interface CompareField {
String name() default "";
/**
* type = 1,需要进行Integer与是否对应转换
*/
String type() default "";
}