Java实现级联下拉结构的示例代码
作者:执拗的小豆芽
在开发过程中,会遇到很多的实体需要将查出的数据处理为下拉或者级联下拉的结构,提供给前端进行展示。本文为大家介绍了java封装下拉和级联下拉的通用工具类,需要的可以参考一下
前言
在开发过程中,会遇到很多的实体需要将查出的数据处理为下拉或者级联下拉的结构,提供给前端进行展示。
在数据库查出的结构中,可能是集合<实体类>的结构,也有可能是List<Map>的结构。
在下拉或者级联下拉的节点数据中,有时候还需要动态的携带其他的参数,已便于前端对某些数据的显示
如区域的级联下拉树中,需要携带经纬度的区域–在选择的时候在地图展示该区域
基于上面的业务场景,构建了下面的工具类,不当的地方请大家多多指教
注:在构建下拉树的时候,会存在父类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<String, Object> dataMap; /** * 子节点 */ @JsonInclude(JsonInclude.Include.NON_EMPTY) @ApiModelProperty("子节点集合") private List<TreeSelect> 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<TreeSelect> getChildren() { return children; } public void setChildren(List<TreeSelect> children) { this.children = children; } public Map<String, Object> getDataMap() { return dataMap; } public void setDataMap(Map<String, Object> 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 <E> List<TreeSelect> singleTree(Collection<E> 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<TreeSelect> 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 <E> List<TreeSelect> toTree(@NotNull Collection<E> 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 <E> List<TreeSelect> toTree(@NotNull Collection<E> 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 <E> List<TreeSelect> toTree(@NotNull Collection<E> 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 <E> List<TreeSelect> toTree(@NotNull Collection<E> 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 <E> List<TreeSelect> collectionObj(@NotNull Collection<E> collection, String id, String parent, String label, @NotNull Class<?> clazz, String... args) throws NoSuchFieldException, IllegalAccessException { // 初始化根节点集合 List<TreeSelect> 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 <E> void dynamicData(@NotNull TreeSelect treeSelect, @NotNull Object e, @NotNull Class<E> clazz, String... args) throws IllegalAccessException, NoSuchFieldException { if (args.length > 0) { Map<String, Object> 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 <E> void addChild(@NotNull TreeSelect node, @NotNull Collection<E> collection, @NotNull Field idField, @NotNull Field parentField, @NotNull Field labelField, @NotNull Class<?> clazz, String... args) throws IllegalAccessException, NoSuchFieldException { //父节点的id String id = node.getId(); //子节点集合 List<TreeSelect> 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 <E> boolean isParentNode(Object parentId, Field idField, @NotNull Collection<E> 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<Map>转下拉或下拉树的工具类
/** * 下拉和级联下拉通用生成工具类 * * @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<TreeSelect> mapToTree(String id, String parent, String label, @NotNull List<Map<String, Object>> 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<TreeSelect> collectionMap(String id, String parent, String label, @NotNull List<Map<String, Object>> collection, String... args) throws IllegalAccessException, NoSuchFieldException { List<TreeSelect> list = new ArrayList<>(); // 找出所有的根节点 for (Map<String, Object> 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<String, Object> e, String... args) throws IllegalAccessException, NoSuchFieldException { if (args.length > 0) { Map<String, Object> 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<Map<String, Object>> collection, String... args) throws IllegalAccessException, NoSuchFieldException { //父节点的id String nodeId = node.getId(); //子节点集合 List<TreeSelect> children = new ArrayList<>(); for (Map<String, Object> 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<Map<String, Object>> 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<String, Object> e : collection) { Object o = e.get(id); if (Objects.equals(o, parentId)) { return false; } } return true; } } }
到此这篇关于Java实现级联下拉结构的示例代码的文章就介绍到这了,更多相关Java级联下拉内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!