Java實(shí)現(xiàn)級(jí)聯(lián)下拉結(jié)構(gòu)的示例代碼
前言
在開發(fā)過程中,會(huì)遇到很多的實(shí)體需要將查出的數(shù)據(jù)處理為下拉或者級(jí)聯(lián)下拉的結(jié)構(gòu),提供給前端進(jìn)行展示。
在數(shù)據(jù)庫(kù)查出的結(jié)構(gòu)中,可能是集合<實(shí)體類>的結(jié)構(gòu),也有可能是List<Map>的結(jié)構(gòu)。
在下拉或者級(jí)聯(lián)下拉的節(jié)點(diǎn)數(shù)據(jù)中,有時(shí)候還需要?jiǎng)討B(tài)的攜帶其他的參數(shù),已便于前端對(duì)某些數(shù)據(jù)的顯示
如區(qū)域的級(jí)聯(lián)下拉樹中,需要攜帶經(jīng)緯度的區(qū)域–在選擇的時(shí)候在地圖展示該區(qū)域
基于上面的業(yè)務(wù)場(chǎng)景,構(gòu)建了下面的工具類,不當(dāng)?shù)牡胤秸?qǐng)大家多多指教
注:在構(gòu)建下拉樹的時(shí)候,會(huì)存在父類id的判斷,可能沒有涵蓋到你們的使用情況,自行修改添加
構(gòu)建統(tǒng)一返回下拉結(jié)構(gòu)
/** * Treeselect樹結(jié)構(gòu)實(shí)體類 * * @author gongl */ @ApiModel("下拉樹結(jié)構(gòu)") public class TreeSelect implements Serializable { private static final long serialVersionUID = 1L; /** * 節(jié)點(diǎn)ID */ @ApiModelProperty("節(jié)點(diǎn)id") private String id; /** * 節(jié)點(diǎn)名稱 */ @ApiModelProperty("節(jié)點(diǎn)名") private String label; /** * 下拉節(jié)點(diǎn)中攜帶數(shù)據(jù) */ @JsonInclude(JsonInclude.Include.NON_EMPTY) @ApiModelProperty("節(jié)點(diǎn)攜帶數(shù)據(jù)") private Map<String, Object> dataMap; /** * 子節(jié)點(diǎn) */ @JsonInclude(JsonInclude.Include.NON_EMPTY) @ApiModelProperty("子節(jié)點(diǎn)集合") 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; }
構(gòu)建集合<對(duì)象>轉(zhuǎn)下拉樹工具類
/** * 下拉和級(jí)聯(lián)下拉通用生成工具類 * * @Author gongl * @Create 2022-01-12 */ public class TreeSelectUtils { private static final Logger log = LoggerFactory.getLogger(TreeSelectUtils.class); /** * 默認(rèn)id名稱 */ public static final String ID = "id"; /** * 默認(rèn)父類id名稱 */ public static final String PARENT = "parentId"; /** * 默認(rèn)label名稱 */ public static final String LABEL = "name"; /** * 單層下拉結(jié)構(gòu) * * @param collection 目標(biāo)集合 * @param id 節(jié)點(diǎn)編號(hào)字段 * @param label 節(jié)點(diǎn)名字段 * @param clazz 集合元素類型 * @param args 需要攜帶的參數(shù) * @return 轉(zhuǎn)換后的下拉結(jié)構(gòu) 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; } } /** * 集合轉(zhuǎn)樹結(jié)構(gòu)(默認(rèn)樹結(jié)構(gòu)字段) * * @param collection 目標(biāo)集合 * @param clazz 集合元素類型 * @param args 需要攜帶的參數(shù) * @return 轉(zhuǎn)換后的樹形結(jié)構(gòu) TreeSelect */ public static <E> List<TreeSelect> toTree(@NotNull Collection<E> collection, @NotNull Class<?> clazz, String... args) { return toTree(collection, null, null, null, clazz, args); } /** * 集合轉(zhuǎn)樹結(jié)構(gòu)(自定義名稱字段) * * @param collection 目標(biāo)集合 * @param label 節(jié)點(diǎn)名字段 * @param clazz 集合元素類型 * @param args 需要攜帶的參數(shù) * @return 轉(zhuǎn)換后的樹形結(jié)構(gòu) 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); } /** * 集合轉(zhuǎn)樹結(jié)構(gòu)(默認(rèn)父類id字段為parentId,其他自定義) * * @param collection 目標(biāo)集合 * @param id 節(jié)點(diǎn)編號(hào)字段 * @param label 節(jié)點(diǎn)名字段 * @param clazz 集合元素類型 * @param args 需要攜帶的參數(shù) * @return 轉(zhuǎn)換后的樹形結(jié)構(gòu) 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); } /** * 集合轉(zhuǎn)樹結(jié)構(gòu)(自定義樹結(jié)構(gòu)的字段) * * @param collection 目標(biāo)集合 * @param id 節(jié)點(diǎn)編號(hào)字段 * @param parent 父節(jié)點(diǎn)編號(hào)字段 * @param label 節(jié)點(diǎn)名字段 * @param clazz 集合元素類型 * @param args 需要攜帶的參數(shù) * @return 轉(zhuǎn)換后的樹形結(jié)構(gòu) 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; } //可以默認(rèn)名稱 if (StringUtils.isEmpty(id)) { id = ID; } if (StringUtils.isEmpty(parent)) { parent = PARENT; } if (StringUtils.isEmpty(label)) { label = LABEL; } //是對(duì)象 return collectionObj(collection, id, parent, label, clazz, args); } catch (Exception e) { log.error("多層下拉樹異常:", e); return null; } } /** * 集合對(duì)象的封裝 */ private static <E> List<TreeSelect> collectionObj(@NotNull Collection<E> collection, String id, String parent, String label, @NotNull Class<?> clazz, String... args) throws NoSuchFieldException, IllegalAccessException { // 初始化根節(jié)點(diǎn)集合 List<TreeSelect> list = new ArrayList<>(); // 獲取 id 字段, 從當(dāng)前對(duì)象或其父類 Field idField; try { idField = clazz.getDeclaredField(id); } catch (NoSuchFieldException e1) { idField = clazz.getSuperclass().getDeclaredField(id); } // 獲取 parentId 字段, 從當(dāng)前對(duì)象或其父類 Field parentField; try { parentField = clazz.getDeclaredField(parent); } catch (NoSuchFieldException e1) { parentField = clazz.getSuperclass().getDeclaredField(parent); } // 獲取 label 字段, 從當(dāng)前對(duì)象或其父類 Field labelField; try { labelField = clazz.getDeclaredField(label); } catch (NoSuchFieldException e1) { labelField = clazz.getSuperclass().getDeclaredField(label); } idField.setAccessible(true); parentField.setAccessible(true); labelField.setAccessible(true); // 找出所有的根節(jié)點(diǎn) 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); } } // 依次添加子節(jié)點(diǎn) 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 當(dāng)前節(jié)點(diǎn) * @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); } } /** * 為目標(biāo)節(jié)點(diǎn)添加孩子節(jié)點(diǎn) * * @param node 目標(biāo)節(jié)點(diǎn) * @param collection 目標(biāo)集合 * @param idField ID 字段 * @param parentField 父節(jié)點(diǎn)字段 * @param labelField 字節(jié)點(diǎn)字段 */ 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 { //父節(jié)點(diǎn)的id String id = node.getId(); //子節(jié)點(diǎn)集合 List<TreeSelect> children = new ArrayList<>(); for (E e : collection) { String parentId = String.valueOf(parentField.get(e)); if (id.equals(parentId)) { // 將當(dāng)前節(jié)點(diǎn)添加到目標(biāo)節(jié)點(diǎn)的孩子節(jié)點(diǎn) 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); // 遞歸添加子節(jié)點(diǎn) addChild(treeSelect, collection, idField, parentField, labelField, clazz, args); } } node.setChildren(children); } /** * 判斷是否是根節(jié)點(diǎn), 判斷方式為: * 1、父節(jié)點(diǎn)編號(hào)為空或?yàn)?0, 則認(rèn)為是根節(jié)點(diǎn) * 2、父節(jié)點(diǎn)在集合中不存在父節(jié)點(diǎn) * * @param parentId 父節(jié)點(diǎn)編號(hào) * @return 是否是根節(jié)點(diǎn) */ 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; } } }
構(gòu)建List<Map>轉(zhuǎn)下拉或下拉樹的工具類
/** * 下拉和級(jí)聯(lián)下拉通用生成工具類 * * @Author gongl * @Create 2022-01-12 */ public class MapToTreeSelectUtils { private static final Logger log = LoggerFactory.getLogger(MapToTreeSelectUtils.class); /** * 數(shù)據(jù)庫(kù)默認(rèn)父類id名稱 */ public static final String DB_PARENT = "parent_id"; /** * 集合轉(zhuǎn)樹結(jié)構(gòu)(自定義樹結(jié)構(gòu)的字段) * * @param collection 目標(biāo)集合 * @param id 節(jié)點(diǎn)編號(hào)字段 * @param parent 父節(jié)點(diǎn)編號(hào)字段 * @param label 節(jié)點(diǎn)名字段 * @param args 需要攜帶的參數(shù) * @return 轉(zhuǎn)換后的樹形結(jié)構(gòu) 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<>(); } //可以默認(rèn)名稱 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<>(); // 找出所有的根節(jié)點(diǎn) 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); } } // 依次添加子節(jié)點(diǎn) for (TreeSelect select : list) { addChildMap(select, id, parent, label, collection, args); } return list; } /** * 添加跟隨下拉的字段 * * @param treeSelect 當(dāng)前節(jié)點(diǎn) * @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); } } /** * 為目標(biāo)節(jié)點(diǎn)添加孩子節(jié)點(diǎn) * * @param node 目標(biāo)節(jié)點(diǎn) * @param collection 目標(biāo)集合 * @param id ID 字段 * @param parent 父節(jié)點(diǎn)字段 * @param label 字節(jié)點(diǎn)字段 */ private static void addChildMap(@NotNull TreeSelect node, String id, String parent, String label, @NotNull List<Map<String, Object>> collection, String... args) throws IllegalAccessException, NoSuchFieldException { //父節(jié)點(diǎn)的id String nodeId = node.getId(); //子節(jié)點(diǎn)集合 List<TreeSelect> children = new ArrayList<>(); for (Map<String, Object> e : collection) { String parentId = String.valueOf(e.get(parent)); if (nodeId.equals(parentId)) { // 將當(dāng)前節(jié)點(diǎn)添加到目標(biāo)節(jié)點(diǎn)的孩子節(jié)點(diǎn) 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); // 遞歸添加子節(jié)點(diǎn) addChildMap(treeSelect, id, parent, label, collection, args); } } } /** * 判斷是否是根節(jié)點(diǎn), 判斷方式為: * 1、父節(jié)點(diǎn)編號(hào)為空或?yàn)?0, 則認(rèn)為是根節(jié)點(diǎn) * 2、父節(jié)點(diǎn)在集合中不存在父節(jié)點(diǎn) * * @param parentId 父節(jié)點(diǎn)編號(hào) * @return 是否是根節(jié)點(diǎn) */ 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; } } }
到此這篇關(guān)于Java實(shí)現(xiàn)級(jí)聯(lián)下拉結(jié)構(gòu)的示例代碼的文章就介紹到這了,更多相關(guān)Java級(jí)聯(lián)下拉內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java學(xué)生信息管理系統(tǒng)設(shè)計(jì)(數(shù)據(jù)庫(kù)版)
這篇文章主要為大家詳細(xì)介紹了數(shù)據(jù)庫(kù)版的Java學(xué)生信息管理系統(tǒng)設(shè)計(jì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11SpringBoot+Ajax+redis實(shí)現(xiàn)隱藏重要接口地址的方法
這篇文章主要介紹了SpringBoot+Ajax+redis實(shí)現(xiàn)隱藏重要接口地址,本篇文章主要講訴使用SpringBoot項(xiàng)目配合Ajax和redis實(shí)現(xiàn)隱藏重要接口地址,這里我以隱藏秒殺地址為例,需要的朋友可以參考下2024-03-03Dwr3.0純注解(純Java Code配置)配置與應(yīng)用淺析一之零配置文件化
Dwr對(duì)我來(lái)說(shuō)最重要的功能點(diǎn)就是反向Ajax調(diào)用,通俗來(lái)將就是后端可以直接調(diào)用前端的JS方法(只要在所能訪問的范圍內(nèi)),這也就是Dwr的真正來(lái)由,當(dāng)然它也有最基本的前端直接調(diào)用后端的特性,省去了我們經(jīng)常的一般Ajax調(diào)用2016-04-04Java object wait notify notifyAll代碼解析
這篇文章主要介紹了Java object wait notify notifyAll代碼解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11