一、 测试效果
二、代码结构
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/*
* 类属性描述注解
* 作用范围:运行时,属性上
* */
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.FIELD} )
public @interface AttributeInformation {
/* 是否开启字段比较,默认关闭 */
boolean ifOpen() default false;
/* 中文描述,默认空串 */
String fieldName() default "";
/* 校验顺序,默认为0 */
int order() default 0;
/* 如果是Date类型,需要的格式 */
String dateFormat() default "yyyy-MM-dd HH:mm:ss";
}
import ClassComparerOrgan.annotation.AttributeInformation;
import ClassComparerOrgan.model.ChangeTypeEnum;
import ClassComparerOrgan.model.ChangeModel;
import ClassComparerOrgan.util.FieldOrderUtil;
import ClassComparerOrgan.util.FieldChangeUtil;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* @ClassName IPropertyProcessImpl
* @Description 改变模型实现
* @Author syh
* @Date 2022/12/10 22:15
* @Version 1.0
*/
public class IPropertyProcessService {
private volatile static IPropertyProcessService iPropertyProcessService;
private IPropertyProcessService() {
}
// 单例模式,懒汉式,双重校验锁
public static IPropertyProcessService getSingleton() {
if (iPropertyProcessService == null) {
synchronized (IPropertyProcessService.class) {
if (iPropertyProcessService == null) {
iPropertyProcessService = new IPropertyProcessService();
}
}
}
return iPropertyProcessService;
}
/**
* @description 对象字段变化访问入口
* @author syh
* @date 2022/12/11 15:45
* @param beforePm 对象 对于修改,该字段表示旧数据
* @param afterPm 对象 对于修改,该字段表示新数据 对于新增和删除,该字段直接new一个空对象
* @param code 比较类型 1 新增数据 2 删除数据 3 修改数据
* @param fieldOrAnnotation 字段描述方式 true 字段属性名 false 字段注释
* @return java.lang.String
*/
public String process(Object beforePm, Object afterPm, Integer code, boolean fieldOrAnnotation) throws IllegalAccessException {
StringBuilder stringBuilder = new StringBuilder();
List<ChangeModel> listChangeModelBefore = new ArrayList<>();
// 对于删除和修改是旧数据排序,对于新增是新数据排序
if (code == 2 || code == 3) {
listChangeModelBefore = getListChangeModelBefore(beforePm, true);
} else {
listChangeModelBefore = getListChangeModelBefore(beforePm, false);
}
listChangeModelBefore = FieldOrderUtil.fieldOrder(listChangeModelBefore);
// 修改数据
if (Objects.equals(code, ChangeTypeEnum.MODIFIED.getCode())) {
// 新数据排序
List<ChangeModel> listChangeModelAfter = getListChangeModelAfter(afterPm);
listChangeModelAfter = FieldOrderUtil.fieldOrder(listChangeModelAfter);
for (int i = 0; i < listChangeModelBefore.size(); i++) {
listChangeModelBefore.get(i).setAfter(listChangeModelAfter.get(i).getAfter());
FieldChangeUtil fieldChangeUtil = FieldChangeUtil.getSingleton();
String s = fieldChangeUtil.fieldChange(listChangeModelBefore.get(i), fieldOrAnnotation);
stringBuilder.append(s);
}
}
// 删除数据
if (Objects.equals(code, ChangeTypeEnum.REMOVED.getCode())){
for (ChangeModel changeModel : listChangeModelBefore) {
FieldChangeUtil fieldChangeUtil = FieldChangeUtil.getSingleton();
String s = fieldChangeUtil.fieldChange(changeModel, fieldOrAnnotation);
stringBuilder.append(s);
}
}
// 新增数据
if (Objects.equals(code, ChangeTypeEnum.ADDED.getCode())){
for (ChangeModel changeModel : listChangeModelBefore) {
FieldChangeUtil fieldChangeUtil = FieldChangeUtil.getSingleton();
String s = fieldChangeUtil.fieldChange(changeModel, fieldOrAnnotation);
stringBuilder.append(s);
}
}
return stringBuilder.toString();
}
/**
* @description 获取对象字段的全部字段信息
* @author syh
* @date 2022/12/10 23:52
* @param beforePm 对象信息
* @return java.util.List<classComparerOrgan.KernelPackage.model.ChangeModel>
*/
public List<ChangeModel> getListChangeModelBefore(Object beforePm, boolean type) throws IllegalAccessException {
// 获取改变之前的字段
Field[] declaredFieldsBefore = beforePm.getClass().getDeclaredFields();
// 改变之前的字段信息封装
List<ChangeModel> changeModelListBefore = new ArrayList<>();
for (Field k : declaredFieldsBefore) {
// 判断是否拥开启注解
boolean ifOpen = false;
ChangeModel changeModel = new ChangeModel();
// 获取注解
Annotation[] annotations = k.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof AttributeInformation) {
if (((AttributeInformation) annotation).ifOpen()) {
// 中文描述
changeModel.setFieldName(((AttributeInformation) annotation).fieldName());
// 序号
changeModel.setOrder(((AttributeInformation) annotation).order());
// Date类型格式解析
changeModel.setDateFormat(((AttributeInformation) annotation).dateFormat());
ifOpen = true;
}
break;
}
}
if (!ifOpen) {
continue;
}
// 属性名称
changeModel.setPropertyName(k.getName());
// 改变之前的数据
k.setAccessible(true);
if (type) {
changeModel.setBefore(k.get(beforePm));
} else {
changeModel.setAfter(k.get(beforePm));
}
// 数据类型
changeModel.setPropertyType(k.getGenericType());
changeModelListBefore.add(changeModel);
}
return changeModelListBefore;
}
/**
* @description 获取对象的字段数据信息
* @author syh
* @date 2022/12/11 0:07
* @param afterPm 对象信息
* @return java.util.List<classComparerOrgan.KernelPackage.model.ChangeModel>
*/
public List<ChangeModel> getListChangeModelAfter(Object afterPm) throws IllegalAccessException {
// 获取改变之后的字段
Field[] declaredFieldsAfter = afterPm.getClass().getDeclaredFields();
// 改变之后的字段信息封装
List<ChangeModel> changeModelListAfter = new ArrayList<>();
for (Field k : declaredFieldsAfter) {
// 判断是否拥开启注解
ChangeModel changeModel = new ChangeModel();
// 获取注解
Annotation[] annotations = k.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof AttributeInformation) {
if (((AttributeInformation) annotation).ifOpen()) {
// 改变之后的数据
k.setAccessible(true);
changeModel.setAfter(k.get(afterPm));
// 序号
changeModel.setOrder(((AttributeInformation) annotation).order());
changeModelListAfter.add(changeModel);
}
break;
}
}
}
return changeModelListAfter;
}
}
import java.lang.reflect.Type;
/**
* 功能描述: 改变模型 <br/>
*/
public class ChangeModel {
/* 属性名称 */
private String propertyName;
/* 中文描述 */
private String fieldName;
/* 属性类型 */
private Type propertyType;
/** 改变前的数据 */
private Object before;
/** 改变后的数据 */
private Object after;
/* 序号 */
private int order;
/* Date类型解析格式 */
private String dateFormat;
public String getDateFormat() {
return dateFormat;
}
public void setDateFormat(String dateFormat) {
this.dateFormat = dateFormat;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public Type getPropertyType() {
return propertyType;
}
public void setPropertyType(Type propertyType) {
this.propertyType = propertyType;
}
public String getPropertyName() {
return propertyName;
}
public void setPropertyName(String propertyName) {
this.propertyName = propertyName;
}
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public Object getBefore() {
return before;
}
public void setBefore(Object before) {
this.before = before;
}
public Object getAfter() {
return after;
}
public void setAfter(Object after) {
this.after = after;
}
}
/**
* 功能描述: 变化类型枚举 <br/>
*/
public enum ChangeTypeEnum {
ADDED(1, "新增数据"),
REMOVED(2, "删除数据"),
MODIFIED(3, "修改数据"),
;
private final String desc;
private final Integer code;
ChangeTypeEnum(Integer code, String desc) {
this.code = code;
this.desc = desc;
}
public Integer getCode() {
return code;
}
public String getDesc() {
return desc;
}
}
import ClassComparerOrgan.model.ChangeModel;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @ClassName MakeSureTypeUtil
* @Description 字段变化
* @Author syh
* @Date 2022/12/11 10:04
* @Version 1.0
*/
public class FieldChangeUtil {
private volatile static FieldChangeUtil fieldChangeUtil;
private FieldChangeUtil() {
}
// 单例模式,懒汉式,双重校验锁
public static FieldChangeUtil getSingleton() {
if (fieldChangeUtil == null) {
synchronized (FieldChangeUtil.class) {
if (fieldChangeUtil == null) {
fieldChangeUtil = new FieldChangeUtil();
}
}
}
return fieldChangeUtil;
}
private static final String titleStartStr = "<";
private static final String titleEndStr = ">";
private static final String andStr = ":";
private static final String describeStartStr = "{";
private static final String describeEndStr = "}";
private static final String divisionStr = " —> ";
private static final String filedDivisionStr = "; ";
private static final String noneStr = "' '";
/**
* @param changeModel 字段信息对象
* @param fieldOrAnnotation 字段描述方式 true 注释 false 字段属性名
* @return java.lang.String
* @description 字段变化
* @author syh
* @date 2022/12/11 13:13
*/
public String fieldChange(ChangeModel changeModel, boolean fieldOrAnnotation) {
StringBuilder stringBuilder = new StringBuilder();
String beforeStr;
String afterStr;
// byte
if (changeModel.getPropertyType().getTypeName().equals(byte.class.getTypeName())) {
if (changeModel.getBefore() == null) {
beforeStr = noneStr;
} else {
beforeStr = (byte) changeModel.getBefore() + "";
}
if (changeModel.getAfter() == null) {
afterStr = noneStr;
} else {
afterStr = (byte) changeModel.getAfter() + "";
}
if (!beforeStr.equals(afterStr)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, beforeStr, afterStr);
}
return stringBuilder.toString();
}
// Byte
if (changeModel.getPropertyType().getTypeName().equals(Byte.class.getTypeName())) {
Byte before = (Byte) changeModel.getBefore();
Byte after = (Byte) changeModel.getAfter();
if (before == null) {
beforeStr = noneStr;
} else {
beforeStr = before.toString();
}
if (after == null) {
afterStr = noneStr;
} else {
afterStr = after.toString();
}
if (!beforeStr.equals(afterStr)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, beforeStr, afterStr);
}
return stringBuilder.toString();
}
// short
if (changeModel.getPropertyType().getTypeName().equals(short.class.getTypeName())) {
if (changeModel.getBefore() == null) {
beforeStr = noneStr;
} else {
beforeStr = (short) changeModel.getBefore() + "";
}
if (changeModel.getAfter() == null) {
afterStr = noneStr;
} else {
afterStr = (short) changeModel.getAfter() + "";
}
if (!beforeStr.equals(afterStr)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, beforeStr, afterStr);
}
return stringBuilder.toString();
}
// Short
if (changeModel.getPropertyType().getTypeName().equals(Short.class.getTypeName())) {
Short before = (Short) changeModel.getBefore();
Short after = (Short) changeModel.getAfter();
if (before == null) {
beforeStr = noneStr;
} else {
beforeStr = before.toString();
}
if (after == null) {
afterStr = noneStr;
} else {
afterStr = after.toString();
}
if (!beforeStr.equals(afterStr)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, beforeStr, afterStr);
}
return stringBuilder.toString();
}
// int
if (changeModel.getPropertyType().getTypeName().equals(int.class.getTypeName())) {
if (changeModel.getBefore() == null) {
beforeStr = noneStr;
} else {
beforeStr = (int) changeModel.getBefore() + "";
}
if (changeModel.getAfter() == null) {
afterStr = noneStr;
} else {
afterStr = (int) changeModel.getAfter() + "";
}
if (!beforeStr.equals(afterStr)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, beforeStr, afterStr);
}
return stringBuilder.toString();
}
// Integer
if (changeModel.getPropertyType().getTypeName().equals(Integer.class.getTypeName())) {
Integer before = (Integer) changeModel.getBefore();
Integer after = (Integer) changeModel.getAfter();
if (before == null) {
beforeStr = noneStr;
} else {
beforeStr = before.toString();
}
if (after == null) {
afterStr = noneStr;
} else {
afterStr = after.toString();
}
if (!beforeStr.equals(afterStr)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, beforeStr, afterStr);
}
return stringBuilder.toString();
}
// long
if (changeModel.getPropertyType().getTypeName().equals(long.class.getTypeName())) {
if (changeModel.getBefore() == null) {
beforeStr = noneStr;
} else {
beforeStr = (long) changeModel.getBefore() + "";
}
if (changeModel.getAfter() == null) {
afterStr = noneStr;
} else {
afterStr = (long) changeModel.getAfter() + "";
}
if (!beforeStr.equals(afterStr)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, beforeStr, afterStr);
}
return stringBuilder.toString();
}
// Long
if (changeModel.getPropertyType().getTypeName().equals(Long.class.getTypeName())) {
Long before = (Long) changeModel.getBefore();
Long after = (Long) changeModel.getAfter();
if (before == null) {
beforeStr = noneStr;
} else {
beforeStr = before.toString();
}
if (after == null) {
afterStr = noneStr;
} else {
afterStr = after.toString();
}
if (!beforeStr.equals(afterStr)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, beforeStr, afterStr);
}
return stringBuilder.toString();
}
// float
if (changeModel.getPropertyType().getTypeName().equals(float.class.getTypeName())) {
if (changeModel.getBefore() == null) {
beforeStr = noneStr;
} else {
beforeStr = (float) changeModel.getBefore() + "";
}
if (changeModel.getAfter() == null) {
afterStr = noneStr;
} else {
afterStr = (float) changeModel.getAfter() + "";
}
if (!beforeStr.equals(afterStr)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, beforeStr, afterStr);
}
return stringBuilder.toString();
}
// Float
if (changeModel.getPropertyType().getTypeName().equals(Float.class.getTypeName())) {
Float before = (Float) changeModel.getBefore();
Float after = (Float) changeModel.getAfter();
if (before == null) {
beforeStr = noneStr;
} else {
beforeStr = before.toString();
}
if (after == null) {
afterStr = noneStr;
} else {
afterStr = after.toString();
}
if (!beforeStr.equals(afterStr)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, beforeStr, afterStr);
}
return stringBuilder.toString();
}
// double
if (changeModel.getPropertyType().getTypeName().equals(double.class.getTypeName())) {
if (changeModel.getBefore() == null) {
beforeStr = noneStr;
} else {
beforeStr = (double) changeModel.getBefore() + "";
}
if (changeModel.getAfter() == null) {
afterStr = noneStr;
} else {
afterStr = (double) changeModel.getAfter() + "";
}
if (!beforeStr.equals(afterStr)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, beforeStr, afterStr);
}
return stringBuilder.toString();
}
// Double
if (changeModel.getPropertyType().getTypeName().equals(Double.class.getTypeName())) {
Double before = (Double) changeModel.getBefore();
Double after = (Double) changeModel.getAfter();
if (before == null) {
beforeStr = noneStr;
} else {
beforeStr = before.toString();
}
if (after == null) {
afterStr = noneStr;
} else {
afterStr = after.toString();
}
if (!beforeStr.equals(afterStr)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, beforeStr, afterStr);
}
return stringBuilder.toString();
}
// char
if (changeModel.getPropertyType().getTypeName().equals(char.class.getTypeName())) {
if (changeModel.getBefore() == null) {
beforeStr = noneStr;
} else {
beforeStr = (char) changeModel.getBefore() + "";
}
if (changeModel.getAfter() == null) {
afterStr = noneStr;
} else {
afterStr = (char) changeModel.getAfter() + "";
}
if (!beforeStr.equals(afterStr)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, beforeStr, afterStr);
}
return stringBuilder.toString();
}
// Character
if (changeModel.getPropertyType().getTypeName().equals(Character.class.getTypeName())) {
Character before = (Character) changeModel.getBefore();
Character after = (Character) changeModel.getAfter();
if (before == null) {
beforeStr = noneStr;
} else {
beforeStr = before.toString();
}
if (after == null) {
afterStr = noneStr;
} else {
afterStr = after.toString();
}
if (!beforeStr.equals(afterStr)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, beforeStr, afterStr);
}
return stringBuilder.toString();
}
// String 类型
if (changeModel.getPropertyType().getTypeName().equals(String.class.getTypeName())) {
String before = (String) changeModel.getBefore();
if (before == null) {
before = noneStr;
}
String after = (String) changeModel.getAfter();
if (after == null) {
after = noneStr;
}
if (!before.equals(after)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, before + "", after + "");
}
return stringBuilder.toString();
}
// Date类型
if (changeModel.getPropertyType().getTypeName().equals(Date.class.getTypeName())) {
Date before = (Date) changeModel.getBefore();
if (before == null) {
beforeStr = noneStr;
} else {
beforeStr = new SimpleDateFormat(changeModel.getDateFormat()).format(before);
}
Date after = (Date) changeModel.getAfter();
if (after == null) {
afterStr = noneStr;
} else {
afterStr = new SimpleDateFormat(changeModel.getDateFormat()).format(after);
}
if (!beforeStr.equals(afterStr)) {
strJoint(changeModel, fieldOrAnnotation, stringBuilder, beforeStr, afterStr);
}
return stringBuilder.toString();
}
return stringBuilder.toString();
}
/**
* @param changeModel 字段信息对象
* @param fieldOrAnnotation 字段描述方式 true 注释 false 字段属性名
* @param stringBuilder 拼接串
* @param before 旧数据
* @param after 新数据
* @return void
* @description 字符串拼接
* @author syh
* @date 2022/12/11 13:43
*/
public void strJoint(ChangeModel changeModel, boolean fieldOrAnnotation, StringBuilder stringBuilder, String before, String after) {
if (!before.equals(after)) {
stringBuilder.append(titleStartStr);
if (fieldOrAnnotation) {
stringBuilder.append(changeModel.getPropertyName());
} else {
stringBuilder.append(changeModel.getFieldName());
}
stringBuilder.append(titleEndStr)
.append(andStr)
.append(describeStartStr)
.append(before)
.append(divisionStr)
.append(after)
.append(describeEndStr)
.append(filedDivisionStr);
}
}
}
import ClassComparerOrgan.model.ChangeModel;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* @ClassName FieldOrder
* @Description 字段排序
* @Author syh
* @Date 2022/12/11 11:15
* @Version 1.0
*/
public class FieldOrderUtil {
public static List<ChangeModel> fieldOrder(List<ChangeModel> changeModelList) {
return changeModelList.stream()
.sorted(Comparator.comparing(ChangeModel::getOrder))
.collect(Collectors.toList());
}
}
三、测试
import java.util.Date;
/**
* @ClassName Interface1
* @Description 比较测试对象
* @Author syh
* @Date 2022/12/10 16:27
* @Version 1.0
*/
public class Interface1 {
@AttributeInformation(ifOpen = true, fieldName = "性别", order = 0)
private String sex;
@AttributeInformation(ifOpen = true, fieldName = "年龄", order = 1)
private int age;
@AttributeInformation(ifOpen = true, fieldName = "出生时间", order = 2, dateFormat = "yyyy-MM-dd")
private Date dateTime;
@AttributeInformation(ifOpen = true, fieldName = "序号", order = 3)
private Integer order;
@AttributeInformation(ifOpen = true, fieldName = "long类型测试", order = 5)
private Integer longText;
@AttributeInformation(ifOpen = true, fieldName = "Long测试", order = 4)
private Integer llongText;
@AttributeInformation(ifOpen = true, fieldName = "double类型测试", order = 6)
private double doubleText;
@AttributeInformation(ifOpen = true, fieldName = "Double类型测试", order = 7)
private Double ddoubleText;
public double getDoubleText() {
return doubleText;
}
public void setDoubleText(double doubleText) {
this.doubleText = doubleText;
}
public Double getDdoubleText() {
return ddoubleText;
}
public void setDdoubleText(Double ddoubleText) {
this.ddoubleText = ddoubleText;
}
public Integer getLongText() {
return longText;
}
public void setLongText(Integer longText) {
this.longText = longText;
}
public Integer getLlongText() {
return llongText;
}
public void setLlongText(Integer llongText) {
this.llongText = llongText;
}
public Integer getOrder() {
return order;
}
public void setOrder(Integer order) {
this.order = order;
}
private int a;
public Date getDateTime() {
return dateTime;
}
public void setDateTime(Date dateTime) {
this.dateTime = dateTime;
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
import ClassComparerOrgan.corePackage.IPropertyProcessService;
import ClassComparerOrgan.model.ChangeTypeEnum;
import java.util.Date;
/**
* @ClassName Text
* @Description 测试类
* @Author syh
* @Date 2022/12/10 16:09
* @Version 1.0
*/
public class Text {
public static void main(String[] args) throws IllegalAccessException {
Interface1 interface1 = new Interface1();
interface1.setAge(12);
interface1.setSex("男");
interface1.setLlongText(7228);
interface1.setLongText(7);
interface1.setDateTime(new Date());
interface1.setDdoubleText(1137923749483204802043242432432432432D);
Interface1 interface2 = new Interface1();
interface2.setAge(11);
interface2.setSex("女");
interface2.setOrder(89);
interface2.setLlongText(78);
interface2.setLongText(788);
interface2.setDdoubleText(113792374948320480243242432432432432D);
interface2.setDoubleText(89);
// 新增测试
System.out.println("====================新增测试====================");
IPropertyProcessService iPropertyProcessService = IPropertyProcessService.getSingleton();
String process = iPropertyProcessService.process(interface1, new Interface1(), ChangeTypeEnum.ADDED.getCode(), true);
System.out.println(process);
// 删除测试
System.out.println("=====================删除测试=====================");
String process1 = iPropertyProcessService.process(interface2, new Interface1(), ChangeTypeEnum.REMOVED.getCode(), false);
System.out.println(process1);
// 修改测试
System.out.println("=====================修改测试=====================");
String process2 = iPropertyProcessService.process(interface1, interface2, ChangeTypeEnum.MODIFIED.getCode(), false);
System.out.println(process2);
}
}
测试对象尽量不要用基本类型,因为有默认值,一定程度影响程序结果 !!!!