树状工具类升级版

/**
 * @author yqlin
 * @description 树结构实体通用工具类
 * @tip pid 和 id 的类型必须一致 排序字段最好是数值类型
 */
@Slf4j
public final class TreeUtil {
    /**
     * Map<FieldType String> ---> Map<[注解属性类型,[字段名]>
     */
    private static Map<FieldType, String> fieldsMap = new HashMap<>(8);

    /**
     * @param list      所有列表
     * @param rootNode  根节点
     * @param treeClazz 树状元素类型
     * @param <E>       传入元素
     *
     * @return 树状结构实体
     */
    public static <E> E toTree(List<E> list, E rootNode, Class<E> treeClazz) {
        if (fieldsMap.size() < 6 >> 1) {
            fieldsMap = getFieldsMap(treeClazz);
        }
        Map<Object, E> map = new HashMap<>(2);
        Object id = ReflectUtil.getFieldValue(rootNode, fieldsMap.get(FieldType.ID));
        Object pid = ReflectUtil.getFieldValue(rootNode, fieldsMap.get(FieldType.PID));
        map.put(id, rootNode);
        for (E childNode : list) {
            buildChildNodes(pid, map, childNode, false, false);
        }
        return map.get(id);
    }

    /**
     * 引用写法 绕过递归
     *
     * @param list      所有列表
     * @param pid       父级id
     * @param treeClazz 树状元素类型
     * @param <E>       传入元素
     *
     * @return 树状结构集合
     */
    public static <E> List<E> toTreeList(List<E> list, Object pid, Class<E> treeClazz) {
        if (fieldsMap.size() < 6 >> 1) {
            fieldsMap = getFieldsMap(treeClazz);
        }
        TreeEntity treeEntity = treeClazz.getAnnotation(TreeEntity.class);
        SortType sortType = treeEntity.sortType();
        String sortField = fieldsMap.get(FieldType.SORT);
        boolean sort = false;
        boolean asc = false;
        if (StringUtils.isNotBlank(sortField)) {
            sort = true;
            if (sortType == SortType.ASC) {
                asc = true;
            }
        }
        Map<Object, E> map = new HashMap<>(2);
        List<E> rootNodes = new ArrayList<>();
        for (E o : list) {
            Object tPid = ReflectUtil.getFieldValue(o, fieldsMap.get(FieldType.PID));
            if (tPid.equals(pid)) {
                rootNodes.add(o);
                map.put(pid, o);
            }
        }
        if (sort) {
            treeNodesSort(rootNodes, asc);
        }
        for (E childNode : list) {
            if (childNode != null) {
                buildChildNodes(pid, map, childNode, sort, asc);
            }
        }
        return rootNodes;
    }

    /**
     * 集合排序
     *
     * @param nodes 节点集合
     * @param asc   是否升序
     * @param <E>   类型
     */
    private static <E> void treeNodesSort(List<E> nodes, boolean asc) {
        if (asc) {
            nodes.sort(Comparator.comparing(e -> Integer.valueOf(ReflectUtil.getFieldValue(e, fieldsMap.get(FieldType.SORT)).toString())));
        } else {
            nodes.sort(Comparator.comparing(e -> Integer.valueOf(ReflectUtil.getFieldValue(e, fieldsMap.get(FieldType.SORT)).toString())).reversed());
        }
    }

    /**
     * 构建子节点集合
     */
    private static <E> void buildChildNodes(Object pid, Map<Object, E> map, E childNode, boolean sort, boolean asc) {
        Object tId = ReflectUtil.getFieldValue(childNode, fieldsMap.get(FieldType.ID));
        map.put(tId, childNode);
        Object tPid = ReflectUtil.getFieldValue(childNode, fieldsMap.get(FieldType.PID));
        if (!tPid.equals(pid)) {
            E parentNode = map.get(tPid);
            List<E> tChildNodes = (List<E>) ReflectUtil.getFieldValue(parentNode, fieldsMap.get(FieldType.CHILD));
            if (tChildNodes == null) {
                tChildNodes = new ArrayList<>();
            }
            tChildNodes.add(childNode);
            if (sort) {
                treeNodesSort(tChildNodes, asc);
            }
            if (parentNode != null) {
                ReflectUtil.setFieldValue(parentNode, fieldsMap.get(FieldType.CHILD), tChildNodes);
            }
        }
    }

    /**
     * 获取 Field Map
     *
     * @param clazz 类名
     *
     * @return Map<FieldType String> ---> Map<[注解属性类型,[字段名]>
     */
    private static <E> Map<FieldType, String> getFieldsMap(Class<E> clazz) {
        if (!clazz.isAnnotationPresent(TreeEntity.class)) {
            throw new RuntimeException("缺少注解: @TreeEntity");
        }
        TreeEntity treeEntity = clazz.getAnnotation(TreeEntity.class);
        IdType idType = treeEntity.idType();
        Stream.of(clazz.getDeclaredFields()).forEach(field -> {
            if (field.isAnnotationPresent(TreeField.class)) {
                TreeField treeField = field.getAnnotation(TreeField.class);
                switch (treeField.fieldType()) {
                    case ID:
                        if (!idType.getClazz().equals(field.getType())) {
                            throw new RuntimeException("ID类型与idType类型不一致");
                        }
                        fieldsMap.put(FieldType.ID, field.getName());
                        break;
                    case PID:
                        if (!idType.getClazz().equals(field.getType())) {
                            throw new RuntimeException("PID类型与idType类型不一致");
                        }
                        fieldsMap.put(FieldType.PID, field.getName());
                        break;
                    case CHILD:
                        fieldsMap.put(FieldType.CHILD, field.getName());
                        break;
                    case SORT:
                        fieldsMap.put(FieldType.SORT, field.getName());
                        break;
                    default:
                        break;
                }
            }
        });
        if (fieldsMap.size() < 6 >> 1) {
            throw new RuntimeException("缺少某一个属性: FieldType.ID | FieldType.PID | FieldType.CHILD)");
        }
        return fieldsMap;
    }
}
/**
 * @author yqlin
 */
public enum FieldType {
    /**
     * 主Id
     */
    ID,
    /**
     * 父ID
     */
    PID,
    /**
     * 子数据
     */
    CHILD,
    /**
     * 排序字段
     */
    SORT
}

@AllArgsConstructor
@Getter
public enum IdType {
    /**
     * 支持三种数值类型
     */
    STRING(String.class),
    LONG(Long.class),
    INTEGER(Integer.class),
    ;
    private Class<?> clazz;
}

public enum SortType {
    /**
     * 支持升序和降序
     */
    ASC,
    DESC,
    ;
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TreeEntity {
    IdType idType();

    SortType sortType() default SortType.ASC;
}
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TreeField {
    /**
     * 所属类型
     * 三种: ID,PID,CHILD
     */
    FieldType fieldType();
}

用法: 支持所在层级节点排序 以及构建树结构集合Json字符串

@ToString
@Data
@Accessors(chain = true)
@TreeEntity(idType = IdType.INTEGER)
public class ProdCateOaTreeVO implements Serializable {
    @TreeField(fieldType = FieldType.ID)
    private Integer value;

    @TreeField(fieldType = FieldType.PID)
    private Integer parentValue;

    private String title;

    private boolean checked;

    @TreeField(fieldType = FieldType.SORT)
    private Integer sort;

    @TreeField(fieldType = FieldType.CHILD)
    private List<ProdCateOaTreeVO> data;
}
 voList = TreeUtil.toTreeList(treeVoList, Constants.PARENT_ID, ProdCateOaTreeVO.class);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

枫吹过的柚

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

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

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

打赏作者

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

抵扣说明:

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

余额充值