【Java】比较业务实体信息变化的工具类
一、业务需求
需要将业务表每次更新操作的前后记录进行保存,写入更新历史表中
方便用户查阅该业务记录发生的历史变化
二、代码实现
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* 判断实体记录是否变更工具类
*/
public class DtoChangeUtil {
public static <Dto> void dtoCompare(Dto beforeDto, Dto afterDto, Consumer<CompareInfo> consumer) {
Class<?> dtoClass = beforeDto.getClass();
List<Field> requiredFields = Arrays.stream(dtoClass.getDeclaredFields())
.filter(f -> Objects.nonNull(f.getAnnotation(CompareRequire.class)))
.collect(Collectors.toList());
for (Field requiredField : requiredFields) {
requiredField.setAccessible(true);
String labelName = requiredField.getAnnotation(CompareRequire.class).labelName();
String fieldName = requiredField.getName();
Class<?> fieldType = requiredField.getType();
try {
Object beforeVal = requiredField.get(beforeDto);
Object afterVal = requiredField.get(afterDto);
boolean[] isEquals = compareFieldIsEquals(beforeVal, afterVal, fieldType);
// if (isEquals[0]) continue;
consumer.accept(CompareInfo.builder()
.labelName(labelName)
.fieldName(fieldName)
.isEquals(isEquals[0])
.before(isEquals[1] ? "" : beforeVal.toString())
.after(isEquals[2] ? "" : afterVal.toString())
.build());
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 判断该字段前后值是否相等
* @param beforeVal 之前值
* @param afterVal 之后值
* @param fieldType 类型
* @return [是否相等, before是否空值, after是否空值]
*/
private static boolean[] compareFieldIsEquals(Object beforeVal, Object afterVal, Class<?> fieldType) {
boolean isEmptyBeforeVal = Objects.isNull(beforeVal);
boolean isEmptyAfterVal = Objects.isNull(afterVal);
if (isEmptyBeforeVal && isEmptyAfterVal) return new boolean[] { true, true, true };
else if (isEmptyBeforeVal && !isEmptyAfterVal) return new boolean[] { false, true, false };
else if (!isEmptyBeforeVal && isEmptyAfterVal) return new boolean[] { false, false, true };
boolean isString = String.class.equals(fieldType);
boolean isDate = Date.class.equals(fieldType);
boolean isBigDecimal = BigDecimal.class.equals(fieldType);
boolean isBoolean = boolean.class.equals(fieldType) || Boolean.class.equals(fieldType);
boolean isByte = byte.class.equals(fieldType) || Byte.class.equals(fieldType);
boolean isChar = char.class.equals(fieldType) || Character.class.equals(fieldType);
boolean isShort = short.class.equals(fieldType) || Short.class.equals(fieldType);
boolean isInt = int.class.equals(fieldType) || Integer.class.equals(fieldType);
boolean isLong = long.class.equals(fieldType) || Long.class.equals(fieldType);
boolean isFloat = float.class.equals(fieldType) || Float.class.equals(fieldType);
boolean isDouble = double.class.equals(fieldType) || Double.class.equals(fieldType);
/* 其他类型以此类推 */
if (isString || isDate) return new boolean[] { beforeVal.equals(afterVal), false, false };
int compareResult = 0;
if (isBigDecimal) compareResult = ((BigDecimal) beforeVal).compareTo((BigDecimal) afterVal);
if (isBoolean) compareResult = ((Boolean) beforeVal).compareTo((Boolean) afterVal);
if (isByte) compareResult = ((Byte) beforeVal).compareTo((Byte) afterVal);
if (isChar) compareResult = ((Character) beforeVal).compareTo((Character) afterVal);
if (isShort) compareResult = ((Short) beforeVal).compareTo((Short) afterVal);
if (isInt) compareResult = ((Integer) beforeVal).compareTo((Integer) afterVal);
if (isLong) compareResult = ((Long) beforeVal).compareTo((Long) afterVal);
if (isFloat) compareResult = ((Float) beforeVal).compareTo((Float) afterVal);
if (isDouble) compareResult = ((Double) beforeVal).compareTo((Double) afterVal);
return new boolean[] { compareResult == 0, false, false };
}
/**
* 需要比较注解:
* 对实体类需要进行比较的字段进行注解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public static @interface CompareRequire {
String labelName(); /* 字段业务名称 */
}
/**
* 需要比较注解:
* 比较信息
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static final class CompareInfo {
private String labelName;
private boolean isEquals;
private String fieldName;
private String before;
private String after;
}
/**
* 测试用例,模拟同一条记录,表单提交的和数据库保存的内容发生了哪些变化
* 仅注解了[需要比较]的字段才会处理
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
static class TestDemo {
private Integer id;
@CompareRequire(labelName = "业务编号")
private String code;
@CompareRequire(labelName = "业务时间")
private Date busTime;
@CompareRequire(labelName = "操作用户")
private String userName;
}
public static void main(String[] args) {
Date date = new Date();
TestDemo t1 = TestDemo.builder().id(1).busTime(new Date(date.getTime() + 1000)).code("1234").userName("admin").build();
TestDemo t2 = TestDemo.builder().id(1).busTime(new Date(date.getTime() - 3000)).code("5678").userName("admin").build();
dtoCompare(t1, t2, System.out::println);
}
}

浙公网安备 33010602011771号