深度优先遍历
请先百度了解深度优先遍历
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();
}
}
}
}