Java实现级联下拉结构的示例代码

发布时间:2023-10-25 14:00

目录
  • 前言
  • 构建统一返回下拉结构
  • 构建集合<对象>转下拉树工具类
  • 构建List转下拉或下拉树的工具类

前言

在开发过程中,会遇到很多的实体需要将查出的数据处理为下拉或者级联下拉的结构,提供给前端进行展示。

在数据库查出的结构中,可能是集合<实体类>的结构,也有可能是List的结构。

在下拉或者级联下拉的节点数据中,有时候还需要动态的携带其他的参数,已便于前端对某些数据的显示

如区域的级联下拉树中,需要携带经纬度的区域–在选择的时候在地图展示该区域

基于上面的业务场景,构建了下面的工具类,不当的地方请大家多多指教

注:在构建下拉树的时候,会存在父类id的判断,可能没有涵盖到你们的使用情况,自行修改添加

构建统一返回下拉结构

/**
 * Treeselect树结构实体类
 *
 * @author gongl
 */
@ApiModel(\"下拉树结构\")
public class TreeSelect implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 节点ID
     */
    @ApiModelProperty(\"节点id\")
    private String id;

    /**
     * 节点名称
     */
    @ApiModelProperty(\"节点名\")
    private String label;

    /**
     * 下拉节点中携带数据
     */
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    @ApiModelProperty(\"节点携带数据\")
    private Map dataMap;


    /**
     * 子节点
     */
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    @ApiModelProperty(\"子节点集合\")
    private List children;


    public TreeSelect() {

    }


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public List getChildren() {
        return children;
    }

    public void setChildren(List children) {
        this.children = children;
    }

    public Map getDataMap() {
        return dataMap;
    }

    public void setDataMap(Map dataMap) {
        this.dataMap = dataMap;
    }

构建集合<对象>转下拉树工具类

/**
 * 下拉和级联下拉通用生成工具类
 *
 * @Author gongl
 * @Create 2022-01-12
 */
public class TreeSelectUtils {
    private static final Logger log = LoggerFactory.getLogger(TreeSelectUtils.class);
    /**
     * 默认id名称
     */
    public static final String ID = \"id\";
    /**
     * 默认父类id名称
     */
    public static final String PARENT = \"parentId\";

    /**
     * 默认label名称
     */
    public static final String LABEL = \"name\";


    /**
     * 单层下拉结构
     *
     * @param collection 目标集合
     * @param id         节点编号字段
     * @param label      节点名字段
     * @param clazz      集合元素类型
     * @param args       需要携带的参数
     * @return 转换后的下拉结构 TreeSelect
     */
    public static  List singleTree(Collection collection, String id, String label,
                                                  Class clazz, String... args) {
        try {
            if (collection == null || collection.isEmpty()) {
                return null;
            }
            Field idField;
            try {
                idField = clazz.getDeclaredField(id);
            } catch (NoSuchFieldException e1) {
                idField = clazz.getSuperclass().getDeclaredField(id);
            }
            Field labelField;
            try {
                labelField = clazz.getDeclaredField(label);
            } catch (NoSuchFieldException e1) {
                labelField = clazz.getSuperclass().getDeclaredField(label);
            }
            idField.setAccessible(true);
            labelField.setAccessible(true);
            List list = new ArrayList<>();
            for (E e : collection) {
                TreeSelect select = new TreeSelect();
                select.setId(String.valueOf(idField.get(e)));
                select.setLabel(String.valueOf(labelField.get(e)));
                list.add(select);
                dynamicData(select, e, clazz, args);
            }
            idField.setAccessible(false);
            labelField.setAccessible(false);
            return list;
        } catch (Exception e) {
            log.error(\"单层下拉异常:\", e);
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 集合转树结构(默认树结构字段)
     *
     * @param collection 目标集合
     * @param clazz      集合元素类型
     * @param args       需要携带的参数
     * @return 转换后的树形结构 TreeSelect
     */
    public static  List toTree(@NotNull Collection collection, @NotNull Class clazz,
                                              String... args) {
        return toTree(collection, null, null, null, clazz, args);
    }

    /**
     * 集合转树结构(自定义名称字段)
     *
     * @param collection 目标集合
     * @param label      节点名字段
     * @param clazz      集合元素类型
     * @param args       需要携带的参数
     * @return 转换后的树形结构 TreeSelect
     */
    public static  List toTree(@NotNull Collection collection, @NotEmpty String label,
                                              @NotNull Class clazz, String... args) {
        return toTree(collection, null, null, label, clazz, args);
    }

    /**
     * 集合转树结构(默认父类id字段为parentId,其他自定义)
     *
     * @param collection 目标集合
     * @param id         节点编号字段
     * @param label      节点名字段
     * @param clazz      集合元素类型
     * @param args       需要携带的参数
     * @return 转换后的树形结构  TreeSelect
     */
    public static  List toTree(@NotNull Collection collection, @NotEmpty String id, @NotEmpty String label,
                                              @NotNull Class clazz, String... args) {
        return toTree(collection, id, null, label, clazz, args);
    }

    /**
     * 集合转树结构(自定义树结构的字段)
     *
     * @param collection 目标集合
     * @param id         节点编号字段
     * @param parent     父节点编号字段
     * @param label      节点名字段
     * @param clazz      集合元素类型
     * @param args       需要携带的参数
     * @return 转换后的树形结构  TreeSelect
     */
    public static  List toTree(@NotNull Collection collection, String id, String parent, String label,
                                              @NotNull Class clazz, String... args) {
        try {
            if (collection == null || collection.isEmpty()) {
                return null;
            }
            //可以默认名称
            if (StringUtils.isEmpty(id)) {
                id = ID;
            }
            if (StringUtils.isEmpty(parent)) {
                parent = PARENT;
            }
            if (StringUtils.isEmpty(label)) {
                label = LABEL;
            }
            //是对象
            return collectionObj(collection, id, parent, label, clazz, args);
        } catch (Exception e) {
            log.error(\"多层下拉树异常:\", e);
            return null;
        }
    }


    /**
     * 集合对象的封装
     */
    private static  List collectionObj(@NotNull Collection collection, String id, String parent, String label,
                                                     @NotNull Class clazz, String... args) throws NoSuchFieldException, IllegalAccessException {
        // 初始化根节点集合
        List list = new ArrayList<>();
        // 获取 id 字段, 从当前对象或其父类
        Field idField;
        try {
            idField = clazz.getDeclaredField(id);
        } catch (NoSuchFieldException e1) {
            idField = clazz.getSuperclass().getDeclaredField(id);
        }
        // 获取 parentId 字段, 从当前对象或其父类
        Field parentField;
        try {
            parentField = clazz.getDeclaredField(parent);
        } catch (NoSuchFieldException e1) {
            parentField = clazz.getSuperclass().getDeclaredField(parent);
        }
        // 获取 label 字段, 从当前对象或其父类
        Field labelField;
        try {
            labelField = clazz.getDeclaredField(label);
        } catch (NoSuchFieldException e1) {
            labelField = clazz.getSuperclass().getDeclaredField(label);
        }
        idField.setAccessible(true);
        parentField.setAccessible(true);
        labelField.setAccessible(true);
        // 找出所有的根节点
        for (E e : collection) {
            Object parentId = parentField.get(e);
            if (isParentNode(parentId, idField, collection)) {
                TreeSelect select = new TreeSelect();
                select.setId(String.valueOf(idField.get(e)));
                select.setLabel(String.valueOf(labelField.get(e)));
                list.add(select);
                dynamicData(select, e, clazz, args);
            }
        }
        // 依次添加子节点
        for (TreeSelect select : list) {
            addChild(select, collection, idField, parentField, labelField, clazz, args);
        }
        idField.setAccessible(false);
        parentField.setAccessible(false);
        labelField.setAccessible(false);
        return list;
    }


    /**
     * 添加跟随下拉的字段
     *
     * @param treeSelect 当前节点
     * @param e
     * @param clazz
     * @param args       需要跟随的字段
     * @throws IllegalAccessException
     * @throws NoSuchFieldException
     */
    private static  void dynamicData(@NotNull TreeSelect treeSelect, @NotNull Object e, @NotNull Class clazz, String... args) throws IllegalAccessException, NoSuchFieldException {
        if (args.length > 0) {
            Map dataMap = new HashMap<>();
            for (String arg : args) {
                Field field;
                try {
                    field = clazz.getDeclaredField(arg);
                } catch (NoSuchFieldException e1) {
                    field = clazz.getSuperclass().getDeclaredField(arg);
                }
                field.setAccessible(true);
                dataMap.put(arg, field.get(e));
                field.setAccessible(false);
            }
            treeSelect.setDataMap(dataMap);
        }
    }


    /**
     * 为目标节点添加孩子节点
     *
     * @param node        目标节点
     * @param collection  目标集合
     * @param idField     ID 字段
     * @param parentField 父节点字段
     * @param labelField  字节点字段
     */
    private static  void addChild(@NotNull TreeSelect node, @NotNull Collection collection,
                                     @NotNull Field idField, @NotNull Field parentField, @NotNull Field labelField,
                                     @NotNull Class clazz, String... args) throws IllegalAccessException, NoSuchFieldException {
        //父节点的id
        String id = node.getId();
        //子节点集合
        List children = new ArrayList<>();
        for (E e : collection) {
            String parentId = String.valueOf(parentField.get(e));
            if (id.equals(parentId)) {
                // 将当前节点添加到目标节点的孩子节点
                TreeSelect treeSelect = new TreeSelect();
                treeSelect.setId(String.valueOf(idField.get(e)));
                treeSelect.setLabel(String.valueOf(labelField.get(e)));
                dynamicData(treeSelect, e, clazz, args);
                children.add(treeSelect);
                // 递归添加子节点
                addChild(treeSelect, collection, idField, parentField, labelField, clazz, args);
            }
        }
        node.setChildren(children);
    }

    /**
     * 判断是否是根节点, 判断方式为:
     * 1、父节点编号为空或为 0, 则认为是根节点
     * 2、父节点在集合中不存在父节点
     *
     * @param parentId 父节点编号
     * @return 是否是根节点
     */
    private static  boolean isParentNode(Object parentId, Field idField, @NotNull Collection collection) throws IllegalAccessException {
        if (parentId == null) {
            return true;
        } else if (parentId instanceof String && (StringUtils.isEmpty(String.valueOf(parentId)) || parentId.equals(\"0\"))) {
            return true;
        } else if (parentId instanceof Long && Long.valueOf(0).equals(parentId)) {
            return true;
        } else {
            for (E e : collection) {
                Object o = idField.get(e);
                if (Objects.equals(o, parentId)) {
                    return false;
                }
            }
            return true;
        }
    }
}

构建List转下拉或下拉树的工具类

/**
 * 下拉和级联下拉通用生成工具类
 *
 * @Author gongl
 * @Create 2022-01-12
 */
public class MapToTreeSelectUtils {
    private static final Logger log = LoggerFactory.getLogger(MapToTreeSelectUtils.class);
    /**
     * 数据库默认父类id名称
     */
    public static final String DB_PARENT = \"parent_id\";

    /**
     * 集合转树结构(自定义树结构的字段)
     *
     * @param collection 目标集合
     * @param id         节点编号字段
     * @param parent     父节点编号字段
     * @param label      节点名字段
     * @param args       需要携带的参数
     * @return 转换后的树形结构  TreeSelect
     */
    public static List mapToTree(String id, String parent, String label,
                                             @NotNull List> collection, String... args) {
        try {
            if (collection == null || collection.isEmpty()) {
                return new ArrayList<>();
            }
            //可以默认名称
            if (StringUtils.isEmpty(id)) {
                id = TreeSelectUtils.ID;
            }
            if (StringUtils.isEmpty(parent)) {
                parent = DB_PARENT;
            }
            if (StringUtils.isEmpty(label)) {
                label = TreeSelectUtils.LABEL;
            }
            return collectionMap(id, parent, label, collection, args);
        } catch (Exception e) {
            log.error(\"多层下拉树异常:\", e);
            return null;
        }
    }

    /**
     * 集合map的封裝
     */
    private static List collectionMap(String id, String parent, String label,
                                                  @NotNull List> collection, String... args) throws IllegalAccessException, NoSuchFieldException {
        List list = new ArrayList<>();
        // 找出所有的根节点
        for (Map next : collection) {
            Object parentId = next.get(parent);
            if (isParentNodeMap(parentId, id, collection)) {
                TreeSelect select = new TreeSelect();
                select.setId(String.valueOf(next.get(id)));
                select.setLabel(String.valueOf(next.get(label)));
                list.add(select);
                dynamicData(select, next, args);
            }
        }
        // 依次添加子节点
        for (TreeSelect select : list) {
            addChildMap(select, id, parent, label, collection, args);
        }
        return list;
    }


    /**
     * 添加跟随下拉的字段
     *
     * @param treeSelect 当前节点
     * @param e
     * @param args       需要跟随的字段
     * @throws IllegalAccessException
     * @throws NoSuchFieldException
     */
    private static void dynamicData(@NotNull TreeSelect treeSelect, @NotNull Map e, String... args) throws IllegalAccessException, NoSuchFieldException {
        if (args.length > 0) {
            Map dataMap = new HashMap<>();
            for (String arg : args) {
                dataMap.put(arg, e.get(arg));
            }
            treeSelect.setDataMap(dataMap);
        }
    }

    /**
     * 为目标节点添加孩子节点
     *
     * @param node       目标节点
     * @param collection 目标集合
     * @param id         ID 字段
     * @param parent     父节点字段
     * @param label      字节点字段
     */
    private static void addChildMap(@NotNull TreeSelect node, String id, String parent, String label,
                                    @NotNull List> collection,
                                    String... args) throws IllegalAccessException, NoSuchFieldException {
        //父节点的id
        String nodeId = node.getId();
        //子节点集合
        List children = new ArrayList<>();
        for (Map e : collection) {
            String parentId = String.valueOf(e.get(parent));
            if (nodeId.equals(parentId)) {
                // 将当前节点添加到目标节点的孩子节点
                TreeSelect treeSelect = new TreeSelect();
                treeSelect.setId(String.valueOf(e.get(id)));
                treeSelect.setLabel(String.valueOf(e.get(label)));
                dynamicData(treeSelect, e, args);
                children.add(treeSelect);
                node.setChildren(children);
                // 递归添加子节点
                addChildMap(treeSelect, id, parent, label, collection, args);
            }
        }
    }


    /**
     * 判断是否是根节点, 判断方式为:
     * 1、父节点编号为空或为 0, 则认为是根节点
     * 2、父节点在集合中不存在父节点
     *
     * @param parentId 父节点编号
     * @return 是否是根节点
     */
    private static boolean isParentNodeMap(Object parentId, String id, @NotNull List> collection) {
        if (parentId == null) {
            return true;
        } else if (parentId instanceof String && (StringUtils.isEmpty(String.valueOf(parentId)) || parentId.equals(\"0\"))) {
            return true;
        } else if (parentId instanceof Long && Long.valueOf(0).equals(parentId)) {
            return true;
        } else {
            for (Map e : collection) {
                Object o = e.get(id);
                if (Objects.equals(o, parentId)) {
                    return false;
                }
            }
            return true;
        }
    }
}

到此这篇关于Java实现级联下拉结构的示例代码的文章就介绍到这了,更多相关Java级联下拉内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

你可能感兴趣的

相关推荐

Abbreviation 聊天常用缩略词及其解释 - English world

Numpy 数组的其他函数--索引argwhere、去重unique、排序sort

第一章 QEMU虚拟机与ARM64平台搭建

html css 圆形按钮 仿uc,10款基于jquery的web前端动画特效

基于Spark的案例:同义词识别

如何统计前端项目有多少行代码

POI-使用JSON实现Excel多级表头导出

OOM简介

轻量化网络总结[1]--SqueezeNet,Xception,MobileNetv1~v3

[STC单片机] STC32G单片机双CAN通信测试

MySQL的主从复制原理详细分析

Pytorch入门实战(6):基于GAN生成简单的动漫人物头像

直播课程 | 数据人都在学的可视化课程,赶紧报名!

从语言进化角度理解c#(委托篇)

SpringMVC+Vue实现前后端的智能新冠疫苗接种助手管理系统

聊聊支付流程的设计与实现逻辑

ETL 常用工具对比和选型

go nil 是什么

GUI之小学生口算系统

推荐一款实时翻译软件,通过鼠标进行翻译,小巧实用。

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号