【已测试通过】话接上文,你们期待得子列表版本日志记录它来了(利用注解实现实体类日志记录,包含子列表日志记录处理)~~


前言

需求:对业务模块基本信息进行版本记录和替换,记录下对应修改编辑得字段

实现方案:利用自定义注解@compare,利用反射记录下修改前后得值

承接上文: 利用方法注解和字段属性注解完成变更日志记录:


自定义@compare注解

/**
 * 字段标记注解
 * 自定义接口属性,有需要那些字段进特殊处理得都可以定义注解进行处理翻译
 * @author zyqok
 * @since 2022/05/05
 */
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Compare {

    /**
     * 字段名称
     */
    String value();

    /**
     * 字典类型(根据定义得字典来进行翻译,常用)
     */
    String dictType() default "";

    /**
     * 业务名称
     */
    String bizName() default "";
	/**
     * 表名
     */
    String tableName() default "";
    
    /**
     * 以下为自定义属性,根据业务情况自行定义
     */
    boolean isIndustryFocus() default false;

    boolean isDate() default false;

    boolean isProvince() default false;

    boolean isCity() default false;

    boolean isRegion() default false;
}

编写compareUtil方法

compareUtils完整代码如下:

/**
 * 使用须知: <br>
 * (1)该工具类主要用于两个同类对象的属性值比较; <br>
 * (2)使用本工具类前,请将对应的类属性上打上 @Compare("xxx") 注解,其中xxx为字段的表达名称;<br>
 * (3)为了比较灵活,只有打了该注解才会进行比较,不打的字段则不会进行比较 <br>
 * (4)比较后,只会返回有变化的字段,无变化的字符则不返回 <br>
 *
 * @author fzy
 * @since 2022/05/05
 */
public class CompareUtils<T> {
    @Autowired
    private SysAreaService areaService;
    private static final String COMMA = ",";
    // 数据版本表
    private static List<WfBusVersionOperLog> returnEndRecords;
    private static List<WfBusVersionOperLog> returnEndRecordsSon;

    public CompareUtils() {
        // 数据主表
        returnEndRecords = new ArrayList<>();
        // 数据子表
        returnEndRecordsSon = new ArrayList<>();
    }

    /**
     * 属性比较
     *
     * @param source 源数据对象
     * @param target 目标数据对象
     * @param operType 操作类型
     * @return 对应属性值的比较变化
     */
    public List<WfBusVersionOperLog> compare(T source, T target, String operType) {
        return compare(source, target, null, operType);
    }

    /**
     * 属性比较(子列表比较)
     *
     * @param source 源数据对象LIST
     * @param target 目标数据对象LIST
     * @return 对应属性值的比较变化
     */
    public List<WfBusVersionOperLog> compareSon(List<T> source, List<T> target, String operType) {
        return compareSon(source, target, null, operType);
    }


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

    /**
     * 属性比较
     *
     * @param source              源数据对象List
     * @param target              目标数据对象List
     * @param ignoreCompareFields 忽略比较的字段
     * @return 对应属性值的比较变化
     */
    public List<WfBusVersionOperLog> compareSon(List<T> source, List<T> target, List<String> ignoreCompareFields, String operType) {
        if (CollectionUtils.isEmpty(source) && CollectionUtils.isEmpty(target)) {
            return returnEndRecordsSon;
        }
        /**
         * 先比较列表数据个数是否变化(是否是新增。新增则无需比较,
         * 如果是修改(如果某一个是空,要么进行了删除,要么进行了新增///,个数一致,则进行比较属性变化,个数不一致,先将新增得插入日志,再比对旧数据属性是否变化))
         */
//        if (StringUtils.isNotBlank(operType) && OperTypeEnum.INSERT.getTypeNum().equals(operType)) {
//            // 新增
//            for (T t : target) {
//                Map<String, CompareNode> filedValueMap = this.getFiledValueMap(t);
//                if (!filedValueMap.isEmpty()) {
//                    doEmptySon(filedValueMap, ignoreCompareFields, operType);
//                }
//            }
//        }
        // 修改
        if (StringUtils.isNotBlank(operType) && OperTypeEnum.UPDATE.getTypeNum().equals(operType)) {
            // 比较个数
            if (CollectionUtils.isEmpty(source) || CollectionUtils.isEmpty(target)) {
                // 新增了数据,或者删除了数据
                if (CollectionUtils.isEmpty(source)) {
                    // 新增了数据
                    for (T t : target) {
                        Map<String, CompareNode> filedValueMap = this.getFiledValueMap(t);
                        if (!filedValueMap.isEmpty()) {
                            doEmptySon(filedValueMap, ignoreCompareFields, OperTypeEnum.INSERT.getTypeNum());
                        }
                    }
                }

                if (CollectionUtils.isEmpty(target)) {
                    // 删除了数据
                    for (T t : source) {
                        Map<String, CompareNode> filedValueMap = this.getFiledValueMap(t);
                        if (!filedValueMap.isEmpty()) {
                            doEmptySon(filedValueMap, ignoreCompareFields, OperTypeEnum.DELETE.getTypeNum());
                        }
                    }
                }

            }

            if (CollectionUtils.isNotEmpty(source) &&CollectionUtils.isNotEmpty(target)) {
                // 比较个数
                // 如果个数不一致(先将原有得  找的到的来进行比对 如果找的到就比较找不到就是删除了 然后再找另一个id为null得 都是新增)
                // 那么遍历size最大得来进行查找
                for (T t : source) {
                    // 在旧数据里面找到对应id得数据
                    Field[] declaredFields = t.getClass().getSuperclass().getDeclaredFields();
                    Optional<Field> first = Arrays.stream(declaredFields).filter(field -> "id".equals(field.getName())).findFirst();
                    first.get().setAccessible(true);
                    Object o = null;
                    try {
                        o = first.get().get(t);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    // 有id数据
                    String idValue = (String) o;
                    T n = getOtherObjByid(idValue, target);
                    if (Objects.isNull(n)) {
                        // 被删除了
                        Map<String, CompareNode> filedValueMapDe = this.getFiledValueMap(t);
                        if (!filedValueMapDe.isEmpty()) {
                            doEmptySon(filedValueMapDe, ignoreCompareFields, OperTypeEnum.DELETE.getTypeNum());
                        }
                    } else {
                        // 比对
                        getChangeParamsSon(t, n, ignoreCompareFields, operType);
                    }
                }
                for (T t : target) {
                    Field[] declaredFields = t.getClass().getDeclaredFields();
                    Optional<Field> first = Arrays.stream(declaredFields).filter(field -> "oriId".equals(field.getName())).findFirst();
                    first.get().setAccessible(true);
                    Object o = null;
                    try {
                        o = first.get().get(t);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    if (Objects.isNull(o)) {
                        // 新增
                        // 新增
                        Map<String, CompareNode> filedValueMap = this.getFiledValueMap(t);
                        if (!filedValueMap.isEmpty()) {
                            doEmptySon(filedValueMap, ignoreCompareFields, OperTypeEnum.INSERT.getTypeNum());
                        }
                    } else {
                        continue;
                    }
                }
            }
        }
        return returnEndRecordsSon;
    }

    /**
     * 在每个子表里面加上字段,记录之前得子列表id
     *
     * @param idValue
     * @param source
     * @return
     */
    private T getOtherObjByid(String idValue, List<T> source) {
        T endObj = null;
        for (T t : source) {
            // 在旧数据里面找到对应id得数据
            Field[] declaredFields = t.getClass().getDeclaredFields();
            Optional<Field> first = Arrays.stream(declaredFields).filter(field -> "oriId".equals(field.getName())).findFirst();
            first.get().setAccessible(true);
            Object o = null;
            try {
                o = first.get().get(t);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            String idValueIn = (String) o;
            if (!Objects.isNull(o) && idValue.equals(idValueIn)) {
                endObj = t;
            }
        }
        return endObj;
    }

    private List<WfBusVersionOperLog> getChangeParamsSon(T source, T target, List<String> ignoreCompareFields, String operType) {
        Map<String, CompareNode> sourceMap = this.getFiledValueMap(source);
        Map<String, CompareNode> targetMap = this.getFiledValueMap(target);
        if (sourceMap.isEmpty() && targetMap.isEmpty()) {
            return returnEndRecordsSon;
        }
        // 如果源数据为空,则只显示目标数据,不显示属性变化情况
        if (sourceMap.isEmpty()) {
            doEmptySon(targetMap, ignoreCompareFields, operType);
        }
        // 如果源数据为空,则显示属性变化情况
        doCompareSon(sourceMap, targetMap, ignoreCompareFields, operType);
        return returnEndRecordsSon;
    }

    private void doEmpty(Map<String, CompareNode> targetMap, List<String> ignoreCompareFields, String operType) {
        StringBuilder sb = new StringBuilder();
        Collection<CompareNode> values = targetMap.values();
        int size = values.size();
        int current = 0;
        String tableName = "";
        String bizName = "";
        for (CompareNode node : values) {
            current++;
            Object o = Optional.ofNullable(node.getFieldValue()).orElse("");
            tableName = node.getTableName();
            bizName = node.getBizName();
            if (Objects.nonNull(ignoreCompareFields) && ignoreCompareFields.contains(node.getFieldKey())) {
                continue;
            }
            if (o.toString().length() > 0) {
                if (operType.equals(OperTypeEnum.INSERT.getTypeNum()) && !sb.toString().contains("新增")) {
                    sb.append("【新增】->");
                }
                if (operType.equals(OperTypeEnum.DELETE.getTypeNum()) && !sb.toString().contains("删除")) {
                    sb.append("【删除】->");
                }

                sb.append("[" + node.getFieldName() + ":" + o + "]");
                if (current < size) {
                    sb.append(COMMA);
                }
            }
        }
        if (StringUtils.isNotBlank(sb.toString())) {
            WfBusVersionOperLog changeParams = new WfBusVersionOperLog();
            changeParams.setOperType(operType);
            changeParams.setOperContent(sb.toString());
            changeParams.setSonRowName(tableName);
            changeParams.setBizName(bizName);
            returnEndRecords.add(changeParams);
        }
    }

    private void doEmptySon(Map<String, CompareNode> targetMap, List<String> ignoreCompareFields, String operType) {
        StringBuilder sb = new StringBuilder();
        Collection<CompareNode> values = targetMap.values();
        int size = values.size();
        int current = 0;
        String tableName = "";
        String bizName = "";
        for (CompareNode node : values) {
            current++;
            Object o = Optional.ofNullable(node.getFieldValue()).orElse("");
            tableName = node.getTableName();
            bizName = node.getBizName();
            if (Objects.nonNull(ignoreCompareFields) && ignoreCompareFields.contains(node.getFieldKey())) {
                continue;
            }
            if (o.toString().length() > 0) {
                if (operType.equals(OperTypeEnum.INSERT.getTypeNum()) && !sb.toString().contains("新增")) {
                    sb.append("【新增】->");
                }
                if (operType.equals(OperTypeEnum.DELETE.getTypeNum()) && !sb.toString().contains("删除")) {
                    sb.append("【删除】->");
                }

                sb.append("[" + node.getFieldName() + ":" + o + "]");
                if (current < size) {
                    sb.append(COMMA);
                }
            }
        }
        if (StringUtils.isNotBlank(sb.toString())) {
            WfBusVersionOperLog changeParams = new WfBusVersionOperLog();
            changeParams.setOperType(operType);
            changeParams.setOperContent(sb.toString());
            changeParams.setSonRowName(tableName);
            changeParams.setBizName(bizName);
            returnEndRecordsSon.add(changeParams);
        }
    }

    private void doCompare(Map<String, CompareNode> sourceMap, Map<String, CompareNode> targetMap, List<String> ignoreCompareFields, String operType) {
        Set<String> keys = sourceMap.keySet();
        for (String key : keys) {
            CompareNode sn = sourceMap.get(key);
            CompareNode tn = targetMap.get(key);
            if (Objects.nonNull(ignoreCompareFields) && ignoreCompareFields.contains(sn.getFieldKey())) {
                continue;
            }
            Object o = Optional.ofNullable(sn.getFieldValue()).orElse("");
            String sv = Optional.ofNullable(sn.getFieldValue()).orElse("").toString();
            String tv = Optional.ofNullable(tn.getFieldValue()).orElse("").toString();
            // 只有两者属性值不一致时, 才显示变化情况
            WfBusVersionOperLog params = new WfBusVersionOperLog();
            if (o instanceof BigDecimal) {
                // 当为空串置为0处理
                if (StringUtils.isBlank(sv)) {
                    sv = "0";
                }
                if (StringUtils.isBlank(tv)) {
                    tv = "0";
                }
                if (new BigDecimal(sv).compareTo(new BigDecimal(tv)) != 0) {
                    params.setFieldKey(sn.getFieldKey());
                    params.setFieldName(sn.getFieldName());
                    params.setFieldOldValue(String.valueOf(new BigDecimal(sv).setScale(2,BigDecimal.ROUND_HALF_UP)));
                    params.setFieldNewValue(String.valueOf(new BigDecimal(tv).setScale(2,BigDecimal.ROUND_HALF_UP)));
                    params.setOperType(operType);
                    params.setSonRowName(sn.getTableName());
                    params.setBizName(sn.getBizName());
                    returnEndRecords.add(params);
                }
            } else {
                // 投资时间类得比较
                if (!sv.equals(tv)) {
                    params.setFieldKey(sn.getFieldKey());
                    params.setFieldName(sn.getFieldName());
                    params.setFieldOldValue(sv);
                    params.setFieldNewValue(tv);
                    params.setOperType(operType);
                    params.setSonRowName(sn.getTableName());
                    params.setBizName(sn.getBizName());
                    returnEndRecords.add(params);
                }
            }
        }
    }

    private void doCompareSon(Map<String, CompareNode> sourceMap, Map<String, CompareNode> targetMap, List<String> ignoreCompareFields, String operType) {
        Set<String> keys = sourceMap.keySet();
        for (String key : keys) {
            CompareNode sn = sourceMap.get(key);
            CompareNode tn = targetMap.get(key);
            if (Objects.nonNull(ignoreCompareFields) && ignoreCompareFields.contains(sn.getFieldKey())) {
                continue;
            }
            Object o = Optional.ofNullable(sn.getFieldValue()).orElse("");
            String sv = Optional.ofNullable(sn.getFieldValue()).orElse("").toString();
            String tv = Optional.ofNullable(tn.getFieldValue()).orElse("").toString();
            // 只有两者属性值不一致时, 才显示变化情况
            WfBusVersionOperLog params = new WfBusVersionOperLog();
            if (o instanceof BigDecimal) {
                // 当为空串置为0处理
                if (StringUtils.isBlank(sv)) {
                    sv = "0";
                }
                if (StringUtils.isBlank(tv)) {
                    tv = "0";
                }
                if (new BigDecimal(sv).compareTo(new BigDecimal(tv)) != 0) {
                    params.setFieldKey(sn.getFieldKey());
                    params.setFieldName(sn.getFieldName());
                    params.setFieldOldValue(String.valueOf(new BigDecimal(sv).setScale(2,BigDecimal.ROUND_HALF_UP)));
                    params.setFieldNewValue(String.valueOf(new BigDecimal(tv).setScale(2,BigDecimal.ROUND_HALF_UP)));
                    params.setOperType(operType);
                    params.setSonRowName(sn.getTableName());
                    params.setBizName(sn.getBizName());
                    returnEndRecordsSon.add(params);
                }
            } else {
                // 投资时间类得比较
                if (!sv.equals(tv)) {
                    params.setFieldKey(sn.getFieldKey());
                    params.setFieldName(sn.getFieldName());
                    params.setFieldOldValue(sv);
                    params.setFieldNewValue(tv);
                    params.setOperType(operType);
                    params.setSonRowName(sn.getTableName());
                    params.setBizName(sn.getBizName());
                    returnEndRecordsSon.add(params);
                }
            }
        }
    }

    private Map<String, CompareNode> getFiledValueMap(T t) {
        if (Objects.isNull(t)) {
            return Collections.emptyMap();
        }
        Field[] fields = t.getClass().getDeclaredFields();
        List<Field> list = new ArrayList<>();
        if (!Objects.isNull(t.getClass().getSuperclass())) {
            Field[] declaredFields = t.getClass().getSuperclass().getDeclaredFields();
            list = Arrays.stream(declaredFields).filter(field -> !Objects.isNull(field.getAnnotation(Compare.class))).collect(Collectors.toList());
        }
        List<Field> asList = Arrays.asList(fields);
        List<Field> end = new ArrayList<>();
        end.addAll(list);
        end.addAll(asList);
        if (Objects.isNull(fields) || fields.length == 0) {
            return Collections.emptyMap();
        }
        System.out.println(end);
        Map<String, CompareNode> map = new LinkedHashMap();
        Compare annotation = t.getClass().getAnnotation(Compare.class);
        String oneJobValue = "";
        for (Field field : end) {
            Compare compareAnnotation = field.getAnnotation(Compare.class);
            if (Objects.isNull(compareAnnotation)) {
                continue;
            }
            field.setAccessible(true);
            try {
                String fieldKey = field.getName();
                CompareNode node = new CompareNode();
                node.setFieldKey(fieldKey);
                node.setFieldValue(field.get(t));
                // 如果是id,那么进行跳过
                if (fieldKey.equals("id") || fieldKey.equals("oriId")) {
                    continue;
                }
                // 字典翻译
                if (StringUtils.isNotBlank(compareAnnotation.dictType())) {
                    String dictValue = "";
                    if (ObjectUtil.isNotNull(field.get(t))) {
                        dictValue = DictUtils.getDictLabel(field.get(t).toString(), compareAnnotation.dictType(), "");
                    }
                    node.setFieldValue(dictValue);
                }
                // 是否是投资伦茨
                if (compareAnnotation.isRound()) {
                    String roundsName = "";
                    if (ObjectUtil.isNotNull(field.get(t))) {
                        if (field.get(t).toString().contains(",") && field.get(t).toString().contains("[") && field.get(t).toString().contains("]")) {
                            String s = field.get(t).toString().substring(2, field.get(t).toString().length() - 2);
                            // 分割逗号
                            String[] split = s.split(",");
                            roundsName = getRoundAll(split);
                        } else {
                            roundsName = getRoundOne(field.get(t).toString());
                        }
                    }
                    node.setFieldValue(roundsName);
                }
                // 是否是聚焦行业
                if (compareAnnotation.isIndustryFocus()) {
                    node.setFieldValue(convertToCascadeShow(field.get(t).toString()));
                }

                // 是否是时间
                if (compareAnnotation.isDate() && ObjectUtil.isNotNull(field.get(t))) {
                    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
                    String string = format.format((Date) field.get(t));
                    node.setFieldValue(string);
                }

                // 是否是省 是否是市 是否是区
                if ((compareAnnotation.isProvince() || compareAnnotation.isCity() || compareAnnotation.isRegion()) && ObjectUtil.isNotNull(field.get(t))) {
                    node.setFieldValue(AreaUtils.getNameById(field.get(t).toString()));
                }

                // 是否是基金管理人
                if (compareAnnotation.isManageIds() && ObjectUtil.isNotNull(field.get(t))) {
                    node.setFieldValue(FundManageUtils.getName(field.get(t).toString()));
                }

                // 是否是用户
                if (compareAnnotation.isUser() && ObjectUtil.isNotNull(field.get(t))) {
                    node.setFieldValue(UserUtils.getUser(field.get(t).toString()).getNickName());
                }

                // 是否是多选用户
                if (compareAnnotation.isUsers() && ObjectUtil.isNotNull(field.get(t))) {
                    String roundsName = "";
                    if (ObjectUtil.isNotNull(field.get(t))) {
                        if (field.get(t).toString().contains(",") && field.get(t).toString().contains("[") && field.get(t).toString().contains("]")) {
                            String s = field.get(t).toString().substring(2, field.get(t).toString().length() - 2);
                            // 分割逗号
                            String[] split = s.split(",");
                            roundsName = getUserAll(split);
                        } else {
                            roundsName = getUserOne(field.get(t).toString());
                        }
                    }
                    node.setFieldValue(roundsName);
                }

                // 是否是多选字典
                if (compareAnnotation.isMultiple() && ObjectUtil.isNotNull(field.get(t))) {
                    String roundsName = "";
                    if (ObjectUtil.isNotNull(field.get(t))) {
                        if (field.get(t).toString().contains(",") && field.get(t).toString().contains("[") && field.get(t).toString().contains("]")) {
                            String s = field.get(t).toString().substring(2, field.get(t).toString().length() - 2);
                            // 分割逗号
                            String[] split = s.split(",");
                            roundsName = getDictAll(split, compareAnnotation.dictType());
                        } else {
                            roundsName = getDictOne(field.get(t).toString(), compareAnnotation.dictType());
                        }
                    }
                    node.setFieldValue(roundsName);
                }
                // 一级职业
                if (compareAnnotation.isOneJob() && ObjectUtil.isNotNull(field.get(t))) {
                    String roundsName = "";
                    if (ObjectUtil.isNotNull(field.get(t))) {
                        oneJobValue = field.get(t).toString();
                        roundsName = getDictOne(field.get(t).toString(), compareAnnotation.dictType());
                    }
                    node.setFieldValue(roundsName);
                }
                // 二级职业根据一级职业来进行筛选
                if (compareAnnotation.isTwoJob() && ObjectUtil.isNotNull(field.get(t))) {
                    String dictType = compareAnnotation.dictType();
                    String type = dictType + "_" + oneJobValue;
                    node.setFieldValue(DictUtils.getDictLabel(field.get(t).toString(), type, ""));
                }

                // 公司翻译
                node.setFieldName(compareAnnotation.value());
                // 表名
                node.setTableName(annotation.tableName());
                // 业务名称
                node.setBizName(annotation.bizName());
                map.put(field.getName(), node);
            } catch (IllegalArgumentException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return map;
    }

    /**
     * 将输入框中得级联行业数据格式化成字符数组显示
     *
     * @param value
     * @return
     */
    private static String convertToCascadeShow(String value) {
        if (value.contains(",")) {
            // 分割逗号进行取最后一级显示
            String[] split = value.split(",");
            // 查询str对应得行业
            return IndustryUtils.getNameById(split[0], split[split.length - 2], split[split.length - 1]);
        }
        return IndustryUtils.getNameById(value);
    }

    /**
     * 格式化方法
     *
     * @param split
     * @return
     */
    private static String getRoundOne(String split) {
        if (split.contains("[")) {
            String substring = split.substring(2);
            if (substring.contains("]")) {
                String s = substring.substring(0, substring.length() - 2);
                return FormatUtils.getDictLabel(s, "rounds_investment", split.toString());
            }
        }
        return "null";
    }

    /**
     * 格式化方法
     *
     * @param split
     * @return
     */
    private static String getUserOne(String split) {
        if (split.contains("[")) {
            String substring = split.substring(2);
            if (substring.contains("]")) {
                String s = substring.substring(0, substring.length() - 2);
                return UserUtils.getUser(s).getNickName();
            }
        }
        return "null";
    }

    private static String getDictOne(String split, String dict) {
        if (split.contains("[")) {
            String substring = split.substring(2);
            if (substring.contains("]")) {
                String s = substring.substring(0, substring.length() - 2);
                return FormatUtils.getDictLabel(s, dict, split.toString());
            }
        }
        return "null";
    }

    /**
     * 格式化方法
     *
     * @param split
     * @return
     */
    private static String getRoundAll(String[] split) {
        String str = "";
        for (int i = 0; i < split.length; i++) {
            String replace = split[i].replace("\"", "");
            if (i != 0) {
                str += "、" + FormatUtils.getDictLabel(replace, "rounds_investment", split.toString());
            } else {
                str = FormatUtils.getDictLabel(replace, "rounds_investment", split.toString());
            }
        }
        return str;
    }

    /**
     * 格式化方法
     *
     * @param split
     * @return
     */
    private static String getUserAll(String[] split) {
        String str = "";
        for (int i = 0; i < split.length; i++) {
            String replace = split[i].replace("\"", "");
            if (i != 0) {
                str += "、" + UserUtils.getUser(replace).getNickName();
            } else {
                str = UserUtils.getUser(replace).getNickName();
            }
        }
        return str;
    }

    private static String getDictAll(String[] split, String dict) {
        String str = "";
        for (int i = 0; i < split.length; i++) {
            String replace = split[i].replace("\"", "");
            if (i != 0) {
                str += "、" + FormatUtils.getDictLabel(replace, dict, split.toString());
            } else {
                str = FormatUtils.getDictLabel(replace, dict, split.toString());
            }
        }
        return str;
    }
}
  1. 核心方法是doCompare()、getFiledValueMap()方法,主要就是再这两个方法进行逻辑业务扩展,比如注解中得isDate格式化,isDicttype这些处理。
  1. 这里面主要是有两套逻辑,一套是无son结尾得,这是主表数据得逻辑处理;另一个是带son关键字得方法,这一套是针对子列表进行得逻辑处理判断。

模块测试

简单得实体类测试:

  1. 主表逻辑测试

    主表字段修改(新增值或者修改删除值,查询是否输出记录)

  2. 子表逻辑测试

    子表之前无,现在新增
    子表之前有,现在删除
    子表之前有1条,现在有两条
    子表之前和现在是同一个数据,只是改变了子表字段值
    子表之前有,现在再之前的基础上新增了一条

	    SysUser user1 = new SysUser();
        user1.setUserName("张三");
        user1.setPhonenumber("112");
        SysDept sysDept = new SysDept();
        sysDept.setDeptName("wanwan1");
        sysDept.setLeader("张三");
        List<SysDept> depts=new ArrayList<>();
        SysDept sysDept11 = new SysDept();
        sysDept11.setId("333");
        sysDept11.setDeptName("wanwan3");
        sysDept11.setLeader("张三2");
        depts.add(sysDept);
        depts.add(sysDept11);
        user1.setDepts(depts);
        user1.setDept(sysDept);
        SysUser user2 = new SysUser();
        user2.setUserName("李四");
        user2.setPhonenumber("110");
        SysDept sysDept2 = new SysDept();
        sysDept2.setDeptName("wanwan2");
        sysDept2.setLeader("李四");
//        SysDept sysDept3 = new SysDept();
//        sysDept3.setId("333");
//        sysDept3.setDeptName("wanwan4");
//        sysDept3.setLeader("李四2");
//        SysDept sysDept4 = new SysDept();
//        sysDept4.setDeptName("wanwan5");
//        sysDept4.setLeader("李四2");
        List<SysDept> deptss = new ArrayList<>();
        deptss.add(sysDept2);
//        deptss.add(sysDept3);
//        deptss.add(sysDept4);
        user2.setDepts(deptss);
        user2.setDept(sysDept2);

        List<WfBusVersionOperLog> result = new CompareUtils<SysUser>().compare(user1, user2, OperTypeEnum.UPDATE.getTypeNum());
        List<WfBusVersionOperLog> result2 = new CompareUtils<SysDept>().compare(user1.getDept(), user2.getDept(), OperTypeEnum.UPDATE.getTypeNum());
        List<WfBusVersionOperLog> results = new CompareUtils<SysDept>().compareSon(user1.getDepts(), user2.getDepts(), OperTypeEnum.UPDATE.getTypeNum());
//        for (ChangeParams changeParams : result) {
//            System.out.println("字段:" + changeParams.getFieldKey() + "  字段名: " + changeParams.getFieldName() + "  旧值:" + changeParams.getFieldOldValue() + "  新值:" + changeParams.getFieldNewValue());
//        }
        for (WfBusVersionOperLog changeParams : result2) {
            System.out.println("字段:" + changeParams.getFieldKey() + "  字段名: " + changeParams.getFieldName() + "  旧值:" + changeParams.getFieldOldValue() + "  新值:" + changeParams.getFieldNewValue());
        }
        for (WfBusVersionOperLog changeParams : results) {
            System.out.println(changeParams.getOperContent());

        }

业务模块接入使用

// 主表前后版本字段比较,返回修改记录
List<WfBusVersionOperLog> compare = new CompareUtils<>().compare(oldDealBases, dealBase, OperTypeEnum.UPDATE.getTypeNum());

// 主表扩展表字段比较
List<WfBusVersionOperLog> compare2 = new CompareUtils<>().compare(oldDealBases.getDealBaseEquity(), dealBase.getDealBaseEquity(), OperTypeEnum.UPDATE.getTypeNum());

// 附件信息(同子表处理)
List<WfBusVersionOperLog> compareFile = new CompareUtils<FileBase>().compareSon(oldDealBases.getFileList(), dealBase.getFileList(), OperTypeEnum.UPDATE.getTypeNum());

效果展示

  1. 版本表

  1. 版本结合日志展示(主表变更数据日志展示)

  1. 版本结合日志展示(子表变更数据日志展示=>>新增或者删除格式)

  1. 版本结合日志展示(子表变更数据日志展示=>>修改)

版本表和日志表sql

  1. 版本表建表sql
-- 版本表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for wf_bus_version_records
-- ----------------------------
DROP TABLE IF EXISTS `wf_bus_version_records`;
CREATE TABLE `wf_bus_version_records`  (
  `id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键id',
  `bus_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '业务id',
  `bus_type` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '业务类型',
  `bus_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '业务名称',
  `bus_ori_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '业务主版本id',
  `version_num` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '版本号',
  `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者',
  `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
  `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者',
  `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
  `remark` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '备注',
  `del_flag` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '删除标识',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '业务表数据操作日志版本表' ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

  1. 日志表建表sql
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for wf_bus_version_oper_log
-- ----------------------------
DROP TABLE IF EXISTS `wf_bus_version_oper_log`;
CREATE TABLE `wf_bus_version_oper_log`  (
  `id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键id',
  `biz_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '业务名称',
  `field_key` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '字段名',
  `field_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '字段中文名',
  `field_old_value` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '字段修改前得值',
  `field_new_value` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '字段修改后得值',
  `oper_type` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作类型',
  `version_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '版本id',
  `oper_content` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '操作描述',
  `son_row_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '子表名称',
  `son_tab_flag` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '子表行标识',
  `del_flag` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '删除标识',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '业务数据操作日志' ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;


总结

本文主要是针对实体类中包含子列表list数据得日志记录,我们很多文章都讲述了主列表的变更日志记录处理,但是针对子列表的日志记录处理相对较少,这是我在项目做的版本日志记录,亲测可用~

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

〆﹏destiny 筑梦)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值