测试
1:User类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {@FieldLabel("姓名")private String name;@FieldLabel("年龄")private Integer age;@FieldLabel("手机")private String phone;@FieldLabel("手机号")private String phoneNumber;@Nullableprivate Address address;
}
2:自定义注解
import java.lang.annotation.*;@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface FieldLabel {String value(); // 中文标识
}
3:工具类
依赖:
<!-- google java lib --><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>17.0</version></dependency><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.5</version></dependency>
utils:
package com.example.juc.utils.比较对象的差异工具类;import com.google.gson.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.converter.json.GsonFactoryBean;import java.util.*;/*** @author: xlj* @create: 2024-10-09 15:29* @description: 对象比较工具类*/
@Slf4j
public class ModelDiffUtil {private static final Gson gson = new Gson();private final static String SOURCE_VALUE = "source";private final static String TARGET_VALUE = "target";private final static String DOT_SEPARATOR = ".";/*** 将两个对象的差异转换为Map格式。** @param sourceObject 原始对象* @param targetObject 当前对象* @return 包含差异的Map*/public static<T> Map<String, Map<String, String>> getDiffMap(T sourceObject, T targetObject) {return getDiffMap(sourceObject, targetObject, null);}/*** 将两个对象的差异转换为Map格式,可以指定忽略的字段。** @param sourceObject 原始对象* @param targetObject 当前对象* @param ignoreFields 忽略的字段列表* @return 包含差异的Map*/public static <T> Map<String, Map<String, String>> getDiffMap(T sourceObject, T targetObject, List<String> ignoreFields) {try {String sourceJsonStr = gson.toJson(sourceObject);String targetJsonStr = gson.toJson(targetObject);return getDiffMap(sourceJsonStr, targetJsonStr, ignoreFields);} catch (JsonSyntaxException e) {log.error("Failed to parse object to JSON", e);return new HashMap<>();}}/*** 从JSON字符串中提取差异。** @param sourceJsonStr 原始JSON字符串* @param targetJsonStr 当前JSON字符串* @return 包含差异的Map*/public static Map<String, Map<String, String>> getDiffMap(String sourceJsonStr, String targetJsonStr) {return getDiffMap(sourceJsonStr, targetJsonStr, null);}/*** 从JSON字符串中提取差异,可以指定忽略的字段。** @param sourceJsonStr 原始JSON字符串* @param targetJsonStr 当前JSON字符串* @param ignoreFields 忽略的字段列表* @return 包含差异的Map*/public static Map<String, Map<String, String>> getDiffMap(String sourceJsonStr, String targetJsonStr, List<String> ignoreFields) {try {JsonObject sourceJson = new JsonParser().parse(sourceJsonStr).getAsJsonObject();JsonObject targetJson = new JsonParser().parse(targetJsonStr).getAsJsonObject();Map<String, String> sourceMap = new LinkedHashMap<>();Map<String, String> targetMap = new LinkedHashMap<>();convertJsonToMap(sourceJson, StringUtils.EMPTY, sourceMap, ignoreFields);convertJsonToMap(targetJson, StringUtils.EMPTY, targetMap, ignoreFields);return doCompare(sourceMap, targetMap);} catch (JsonSyntaxException e) {log.error("Failed to parse JSON string", e);return new HashMap<>();}}/*** 将JSON对象转换为Map,忽略指定的字段。** @param json JSON对象* @param root 当前JSON路径* @param resultMap 存储转换结果的Map* @param ignoreFields 忽略的字段列表*//*** 将JSON对象转换为Map,忽略指定的字段。** @param json JSON对象* @param root 当前JSON路径* @param resultMap 存储转换结果的Map* @param ignoreFields 忽略的字段列表*/private static void convertJsonToMap(JsonElement json, String root, Map<String, String> resultMap, List<String> ignoreFields) {if (json.isJsonObject()) {JsonObject jsonObject = json.getAsJsonObject();for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {String key = entry.getKey();if (CollectionUtils.isNotEmpty(ignoreFields) && ignoreFields.contains(key)) {continue;}JsonElement value = entry.getValue();String newRoot = (root.isEmpty())? key : root + DOT_SEPARATOR + key;if (value.isJsonObject() || value.isJsonArray()) {convertJsonToMap(value, newRoot, resultMap, ignoreFields);} else if(value.isJsonPrimitive()){resultMap.put(newRoot, value.getAsJsonPrimitive().getAsString());}}} else if (json.isJsonArray()) {JsonArray jsonArray = json.getAsJsonArray();for (int i = 0; i < jsonArray.size(); i++) {JsonElement value = jsonArray.get(i);String newRoot = (root.isEmpty())? "[" + i + "]" : root + "[" + i + "]";if (value.isJsonObject() || value.isJsonArray()) {convertJsonToMap(value, newRoot, resultMap, ignoreFields);} else if(value.isJsonPrimitive()){resultMap.put(newRoot, value.getAsJsonPrimitive().getAsString());}}}}/*** 执行实际的比较操作,返回包含差异的Map** @param sourceMap 原始Map* @param targetMap 当前Map* @return 包含差异的Map*/private static Map<String, Map<String, String>> doCompare(Map<String, String> sourceMap, Map<String, String> targetMap) {Map<String, Map<String, String>> diffMap = new HashMap<>();for (Map.Entry<String, String> entry : targetMap.entrySet()) {String key = entry.getKey();String newValue = entry.getValue();String oldValue = sourceMap.get(key);if (sourceMap.containsKey(key)) {if (!ObjectUtils.equals(newValue, oldValue)) {addDiffMap(diffMap, key, oldValue, newValue);}} else {addDiffMap(diffMap, key, StringUtils.EMPTY, newValue);}}return diffMap;}/*** 将差异项添加到差异映射中。** 此方法用于在处理两个数据集的差异时,将特定的差异项添加到一个映射中,* 其中每个差异项由一个键值对表示,包括源值和目标值。** @param diffMap 保存差异项的映射,其中键是差异项的标识,值是包含源值和目标值的映射。* @param key 差异项的标识,用于在diffMap中作为键。* @param value 源对象中的值,表示差异的起始点。* @param targetValue 目标对象中的值,表示与源值不同的目标值。*/private static void addDiffMap(Map<String, Map<String, String>> diffMap, String key, String value, String targetValue) {Map<String, String> diffItemMap = new HashMap<>();diffItemMap.put(SOURCE_VALUE, value);diffItemMap.put(TARGET_VALUE, targetValue);diffMap.put(key, diffItemMap);}
}
测试:
public class 对象字段差异 {public static void main(String[] args) {User user = new User();user.setName("夏天");user.setAge(18);user.setPhone("苹果");user.setPhoneNumber("177");List<String> ignoreFields = Collections.singletonList("address");User user1 = new User();user1.setName("夏天");user1.setAge(188);user1.setPhone("华为");user1.setPhoneNumber("177");Map<String, Map<String, String>> diffMap = ModelDiffUtil.getDiffMap(user, user1, ignoreFields);System.out.println(diffMap);Map<String, String> map = AnnotationUtil.printFieldLabels(User.class);System.out.println(map);System.out.println("--------------------------");List<String> diff = new java.util.ArrayList<>(Collections.emptyList());diffMap.forEach((k, v) -> {String object = map.get(k);if (StrUtil.isNotBlank(object)) {diff.add(object);}});System.out.println(diff);}
}