Java利用遞歸實現樹形結構的工具類
需求描述
有時候,我們的數據是帶有層級的,比如常見的省市區三級聯動,就是一層套著一層,如下圖:
而我們在數據庫存放數據的時候,往往是列表形式的,如下圖:
那麼當我們從數據庫查詢出來,返回給前端的時候,前端又需要給出樹形層級的時候,這個時候可能就需要遞歸處理為樹形結構瞭,因此下面這個工具或許就可以用得上瞭。
使用示例
我們按照上面定義一個Place對象,打上工具註解:
- @TreeKey 標識唯一
- @TreeParentKey 標識父節點標識
- @TreeChildren 標識子孫節點集合
@Data @Data public class Place { @TreeKey private String id; @TreeParentKey private String parentId; private String name; @TreeChildren private List<Place> children; public Place(String id, String name, String parentId) { this.id = id; this.name = name; this.parentId = parentId; } }
測試:
public class Test { public static void main(String[] args) { List<Place> places = new ArrayList<>(); places.add(new Place("510000", "四川省", "0")); places.add(new Place("510100", "成都市", "510000")); places.add(new Place("510107", "武侯區", "510100")); places.add(new Place("510116", "雙流區", "510100")); places.add(new Place("511600", "廣安市", "510000")); places.add(new Place("511603", "前鋒區", "511600")); places.add(new Place("511621", "嶽池縣", "511600")); List<Place> treeList = TreeUtils.getTree(places, "0"); System.out.println(JSON.toJSONString(treeList)); } }
最終效果:
工具代碼
@TreeKey
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface TreeKey { }
@TreeParentKey
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface TreeParentKey { }
@TreeChildren
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface TreeChildren { }
@TreeUtils
package com.csd.utils.tree; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; /** * 遞歸求樹形工具類 * * @author Yuanqiang.Zhang * @since 2023/3/8 */ public class TreeUtils { /** * 集合轉化為樹形 * * @param list 集合 * @param highestParentKey 最高層父節點值 * @param <T> 泛型 * @return 樹形 */ public static <T> List<T> getTree(List<T> list, Object highestParentKey) { if (Objects.isNull(list) || list.isEmpty()) { return Collections.emptyList(); } Field key = null; Field parentKey = null; Field children = null; Field[] fields = list.get(0).getClass().getDeclaredFields(); for (Field field : fields) { if (Objects.isNull(key)) { TreeKey treeKey = field.getAnnotation(TreeKey.class); if (Objects.nonNull(treeKey)) { key = field; continue; } } if (Objects.isNull(parentKey)) { TreeParentKey treeParentKey = field.getAnnotation(TreeParentKey.class); if (Objects.nonNull(treeParentKey)) { parentKey = field; continue; } } if (Objects.isNull(children)) { TreeChildren treeChildren = field.getAnnotation(TreeChildren.class); if (Objects.nonNull(treeChildren)) { children = field; continue; } } } if (Objects.isNull(key) || Objects.isNull(parentKey) || Objects.isNull(children)) { return Collections.emptyList(); } key.setAccessible(true); parentKey.setAccessible(true); children.setAccessible(true); // 獲取最高層數據 List<T> highs = new ArrayList<>(); try { for (T t : list) { Object pk = parentKey.get(t); if (getString(pk).equals(getString(highestParentKey))) { highs.add(t); } } // 獲取最高層子孫節點 for (T t : highs) { setChildren(list, t, key, parentKey, children); } } catch (IllegalAccessException e) { e.printStackTrace(); } return highs; } /** * 獲取子孫節點 * * @param list 集合 * @param parent 父節點對象 * @param key 唯一屬性 * @param parentKey 父唯一屬性 * @param children 節點 * @param <T> 泛型 * @return 帶有子孫集合的父節點對象 * @throws IllegalAccessException */ private static <T> T setChildren(List<T> list, T parent, Field key, Field parentKey, Field children) throws IllegalAccessException { Object k = key.get(parent); List<T> tempList = new ArrayList<>(); for (T t : list) { Object pk = parentKey.get(t); if (getString(k).equals(getString(pk))) { tempList.add(setChildren(list, t, key, parentKey, children)); } } children.set(parent, tempList); return parent; } /** * 獲取字符串 * * @param o 值 * @return 字符串 */ private static String getString(Object o) { return Objects.isNull(o) ? "" : o.toString(); } }
以上就是Java利用遞歸實現樹形結構的工具類的詳細內容,更多關於Java樹形結構的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- 手寫一個@Valid字段校驗器的示例代碼
- Java循環對bean的屬性進行賦值的實現
- 淺談Java自定義註解相關知識
- java序列化對象根據不同配置動態改變屬性名的方法
- Java基礎之動態代理Cglib詳解