对象内容变更比较

记录业务操作日志可能需要比较前后信息变更,方便记录,实现简单工具方便比较信息;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Compare {
    /**
     * 字段名称
     */
    String value();

    /**
     * 内容转换
     */
    CompareContent[] content() default {};
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CompareContent {

    /**
     * 值
     */
    String value();

    /**
     * 值描述
     */
    String valueDesc();
}

@Getter
@Setter
public class CompareNode {
    /**
     * 字段
     */
    private String fieldKey;

    /**
     * 字段值
     */
    private Object fieldValue;

    /**
     * 字段名称
     */
    private String fieldName;

}

public class CompareUtils<T> {

    private static final String COMMA = ",";

    /**
     * 属性比较
     *
     * @param source 源数据对象
     * @param target 目标数据对象
     * @return 对应属性值的比较变化
     */
    public String compare(T source, T target) {
        return compare(source, target, null);
    }

    /**
     * 属性比较
     *
     * @param source 源数据对象
     * @param target 目标数据对象
     * @param ignoreCompareFields 忽略比较的字段
     * @return 对应属性值的比较变化
     */
    public String compare(T source, T target, List<String> ignoreCompareFields) {
        if (Objects.isNull(source) && Objects.isNull(target)) {
            return "";
        }
        Map<String, CompareNode> sourceMap = this.getFiledValueMap(source);
        Map<String, CompareNode> targetMap = this.getFiledValueMap(target);
        if (sourceMap.isEmpty() && targetMap.isEmpty()) {
            return "";
        }
        // 如果源数据为空,则只显示目标数据,不显示属性变化情况
        if (sourceMap.isEmpty()) {
            return doEmpty(targetMap, ignoreCompareFields);
        }
        // 如果源数据为空,则显示属性变化情况
        String s = doCompare(sourceMap, targetMap, ignoreCompareFields);
        if (!s.endsWith(COMMA)) {
            return s;
        }
        return s.substring(0, s.length() - 1);
    }

    private String doEmpty(Map<String, CompareNode> targetMap, List<String> ignoreCompareFields) {
        StringBuilder sb = new StringBuilder();
        Collection<CompareNode> values = targetMap.values();
        int size = values.size();
        int current = 0;
        for (CompareNode node : values) {
            current++;
            Object o = Optional.ofNullable(node.getFieldValue()).orElse("");
            if (Objects.nonNull(ignoreCompareFields) && ignoreCompareFields.contains(node.getFieldKey())) {
                continue;
            }
            if (!o.toString().isEmpty()) {
                sb.append("[").append(node.getFieldName()).append(":").append(o).append("]");
                if (current < size) {
                    sb.append(COMMA);
                }
            }
        }
        return sb.toString();
    }

    private String doCompare(Map<String, CompareNode> sourceMap, Map<String, CompareNode> targetMap,
        List<String> ignoreCompareFields) {
        StringBuilder sb = new StringBuilder();
        Set<String> keys = sourceMap.keySet();
        int size = keys.size();
        int current = 0;
        for (String key : keys) {
            current++;
            CompareNode sn = sourceMap.get(key);
            CompareNode tn = targetMap.get(key);
            if (Objects.nonNull(ignoreCompareFields) && ignoreCompareFields.contains(sn.getFieldKey())) {
                continue;
            }
            String sv = Optional.ofNullable(sn.getFieldValue()).orElse("").toString();
            String tv = Optional.ofNullable(tn.getFieldValue()).orElse("").toString();
            // 只有两者属性值不一致时, 才显示变化情况
            if (!sv.equals(tv)) {
                sb.append(String.format("%s:从 [%s] -> 变为 [%s]", sn.getFieldName(), sv, tv));
                if (current < size) {
                    sb.append(COMMA);
                }
            }
        }
        return sb.toString();
    }

    private Map<String, CompareNode> getFiledValueMap(T t) {
        if (Objects.isNull(t)) {
            return Collections.emptyMap();
        }
        Field[] fields = t.getClass().getDeclaredFields();
        if (fields.length == 0) {
            return Collections.emptyMap();
        }
        Map<String, CompareNode> map = new LinkedHashMap<>();
        for (Field field : fields) {
            Compare compareAnnotation = field.getAnnotation(Compare.class);
            if (Objects.isNull(compareAnnotation)) {
                continue;
            }
            String fieldKey = field.getName();
            String fieldName = compareAnnotation.value();

            Object fieldValue;
            try {
                fieldValue = FieldUtils.readField(field, t, true);
            } catch (IllegalAccessException e) {
                continue;
            }
            // 值内容转换
            CompareContent[] content = compareAnnotation.content();
            List<CompareContent> compareContents = Arrays.asList(content);
            Map<String, String> valueConvert = compareContents.stream()
                .collect(Collectors.toMap(CompareContent::value, CompareContent::valueDesc, (key1, key2) -> key1));
            if (Objects.nonNull(valueConvert.get(String.valueOf(fieldValue)))) {
                fieldValue = valueConvert.get(String.valueOf(fieldValue));
            }
            CompareNode node = new CompareNode();
            node.setFieldKey(fieldKey);
            node.setFieldName(fieldName);
            node.setFieldValue(fieldValue);
            map.put(field.getName(), node);
        }
        return map;
    }

}

使用示例:

public class Test {

    public static void main(String[] args) {
        CompareTest test1 = new CompareTest("测试1", "0");
        CompareTest test2 = new CompareTest("测试2", "1");
        String compare = new CompareUtils<CompareTest>().compare(test1, test2);
        System.out.println("对象信息内容变化:\n" + compare);
    }
}

@Data
@AllArgsConstructor
class CompareTest {

    @Compare(value = "名称")
    private String name;

    @Compare(value = "内容",
        content = {@CompareContent(value = "0", valueDesc = "零"), @CompareContent(value = "1", valueDesc = "壹")})
    private String value;
}

运行后输出信息变化:

对象信息内容变化:
名称:从 [测试1] -> 变为 [测试2],内容:从 [] -> 变为 []
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值