深度优先遍历对比两个对象区别,得到一个updateList。(js&java)

64 阅读2分钟

深度优先遍历

请先百度了解深度优先遍历

js

// 环境 formerForm 是 表单数据 from 的未发生变化时的深拷贝数据
// vue 文件内
// 该部分代码在 export default 外
let formerForm = null;
function getkey(path, key) {
  if (path) {
    return path + "." + key;
  }
  return key;
}
function getType(data) {
  return Object.prototype.toString.call(data).slice(8, -1);
}
function arraysHaveSameElements(arr1, arr2) {
  if (!arr1 && !arr2 && arr1.length === 0 && arr2.length === 0) {
    return true;
  }
  if (arr1.length !== arr2.length) {
    return false;
  }
  if (arr1.length == 2 && arr2.length == 2) {
    for (let i = 0; i < arr1.length; i++) {
      if (arr1[i] !== arr2[i]) {
        return false;
      }
    }
  }
  return arr1.every((element) => arr2.includes(element));
}
function judgeComplexArray(array) {
  return array.some((element) => {
    return typeof element === "object" && element !== null; //&& !Array.isArray(element)
  });
}

//  methods内 

    // 深度优先遍历formerForm 对比保存时变化的数据
    compareDFS(formerForm, form, path) {
      let updateList = [];

      for (let key in form) {
        const from = formerForm[key];
        const to = form[key];
        if (form.hasOwnProperty(key) && formerForm.hasOwnProperty(key)) {
          if (getType(from) == "Array" || getType(to) == "Array") {
            let pass = true;
            if (from.length === 0 && to.length === 0) {
              pass = true;
            }
            if (from.length != to.length) {
              pass = false;
            }
            console.log(
              (path || key) + " - outside",
              from.length == to.length && pass
            );
            if (from.length == to.length && pass) {
              const complexType =
                judgeComplexArray(from) || judgeComplexArray(to);
              console.log((path || key) + " - complexType", complexType);
              if (complexType) {
                for (let i = 0; i < from.length; i++) {
                  let fromParam = from[i];
                  let toParam = to[i];
                  const secondaryUpdateList = this.compareDFS(
                    fromParam,
                    toParam,
                    getkey(path, key + `.${i}`)
                  );
                  console.log("secondaryUpdateList", secondaryUpdateList);
                  updateList = [...updateList, ...secondaryUpdateList];
                }
              } else {
                pass = arraysHaveSameElements(from, to);
              }
            }
            pass ||
              updateList.push({
                prop: getkey(path, key),
                from,
                to,
              });
          } else if (typeof from === "object" && typeof to === "object") {
            console.log("key object", key);
            const secondaryUpdateList = this.compareDFS(
              from,
              to,
              getkey(path, key)
            );
            updateList = [...updateList, ...secondaryUpdateList];
          } else {
            console.log("简单数据类型", key, from, to);
            console.log("from !== to", from !== to);
            if (from !== to) {
              updateList.push({
                prop: getkey(path, key),
                from,
                to,
              });
            }
          }
        } else {
          if (key.includes("brief")) {
            console.log("brief", key, to, from);
            console.log("brief", key, to, from);
          }
          // 两者使用或 防止数据类型是boolean 出现差异
          if (to || from) {
            updateList.push({
              prop: getkey(path, key),
              from: from,
              to,
            });
          }
        }
      }

      // Check for any keys in form that are missing in formerForm

      // for (let key in form) {
      //   if (!formerForm.hasOwnProperty(key) && formerForm[key]) {
      //     updateList.push({
      //       prop: getkey(path, key),
      //       from: "",
      //       to: form[key],
      //     });
      //   }
      // }
      return updateList;
    },

java

public static List compareResources(Resource oldResource, Resource newResource, Integer cycleNumber) { List updateList = new ArrayList<>(); compareFields(oldResource, newResource, "", updateList, cycleNumber); return updateList; }

private static final Set<Class<?>> SIMPLE_TYPES = new HashSet<>();

static {
    SIMPLE_TYPES.add(Boolean.class);
    SIMPLE_TYPES.add(Character.class);
    SIMPLE_TYPES.add(Byte.class);
    SIMPLE_TYPES.add(Short.class);
    SIMPLE_TYPES.add(Integer.class);
    SIMPLE_TYPES.add(Long.class);
    SIMPLE_TYPES.add(Float.class);
    SIMPLE_TYPES.add(Double.class);
    SIMPLE_TYPES.add(String.class);
    SIMPLE_TYPES.add(java.util.Date.class);
    SIMPLE_TYPES.add(java.sql.Date.class);
    SIMPLE_TYPES.add(java.sql.Time.class);
    SIMPLE_TYPES.add(java.sql.Timestamp.class);
    SIMPLE_TYPES.add(java.math.BigDecimal.class);
    SIMPLE_TYPES.add(java.math.BigInteger.class);
    SIMPLE_TYPES.add(java.time.LocalDate.class);
    SIMPLE_TYPES.add(java.time.LocalTime.class);
    SIMPLE_TYPES.add(java.time.LocalDateTime.class);
    SIMPLE_TYPES.add(java.time.ZonedDateTime.class);
}

public static boolean isSimpleType(Class<?> clazz) {
    return SIMPLE_TYPES.contains(clazz) || clazz.isEnum() || clazz.isPrimitive();
}

public static void updateAddList(Object from, Object to, List<Update> updateList, String fieldName, String prefix){
    if (!prefix.isEmpty()) {
        fieldName = prefix + "." + fieldName;
    }
    Update update = new Update();
    update.setProp(fieldName);
    update.setFrom(from);
    update.setTo(to);
    updateList.add(update);
};

public static boolean judgeComplexList(List<?> list){
    for(int i = 0; i < list.size(); i++){
        Object element = list.get(i);
        if(!isSimpleType(element.getClass())){
            return true;
        }
    }
    return false;
};

private static void compareFields(Object oldObj, Object newObj, String prefix, List<Update> updateList, Integer cycleNumber) {
    if(cycleNumber > 0){
        if (oldObj == null || newObj == null) {
            // 如果 oldObj 或者 newObj 为空,直接返回,避免空指针异常
            return;
        }
        Class<?> clazz = oldObj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            String fieldName = field.getName();
            try {
                Object oldValue = field.get(oldObj);
                Object newValue = field.get(newObj);
                Boolean pass = true;
                if (oldValue == null || newValue == null) {
                    if(oldValue != null || newValue != null){
                        updateAddList(oldValue, newValue, updateList, fieldName , prefix);
                    }
                    pass = false;
                }
                if(pass){
                    //                        用于过滤不存在的key
                    BeanWrapper oldValueWrapper = new BeanWrapperImpl(oldObj);
                    BeanWrapper newObjWrapper = new BeanWrapperImpl(newObj);
                    pass = oldValueWrapper.isReadableProperty(fieldName) && newObjWrapper.isReadableProperty(fieldName);
                }

                if(pass){
                    String type = field.getType().getName();
                    if(type != null){
                        Class<?> clazz1 = field.getType();
                        if (isSimpleType(clazz1)) {
                            if (!oldValue.equals(newValue)) {
                                updateAddList(oldValue, newValue, updateList, fieldName , prefix);
                            }
                        }else{
                            log.error("field.getType().getName().contains("List"):{}", field.getType().getName().contains("List"));
                            if(field.getType().getName().contains("List")){

                                List<?> oldList = (List<?>) oldValue;
                                Integer oldLength = oldList.size();
                                List<?> newList = (List<?>) newValue;
                                Integer newLength = newList.size();
                                Boolean pass2 = true;
                                if (oldLength.equals(0) && newLength.equals(0)) {
                                    pass2 = false;
                                }

                                if(oldLength.equals(newLength)&&pass2){
                                    Boolean isComplex = judgeComplexList(oldList)||judgeComplexList(newList);
                                    for (int i = 0; i < oldLength; i++) {
                                        Object before = oldList.get(i);
                                        Object after = newList.get(i);
                                        if(isComplex){
                                            compareFields(before, after, fieldName + "." + i, updateList, cycleNumber-1);
                                        }else{

                                           if(!oldList.contains(after)||!newList.contains(before)){
                                                updateAddList(oldList, newList, updateList, fieldName , prefix);
                                                //跳出循环
                                                break;
                                            }
                                        }

                                    }
                                }else if(!oldLength.equals(newLength)){
                                    updateAddList(oldList, newList, updateList, fieldName , prefix);
                                }
                            }else{
                                compareFields(oldValue, newValue, field.getName(), updateList, cycleNumber-1);
                            }
                        }
                    }

                };

            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

}