java父子節(jié)點(diǎn)parentid樹形結(jié)構(gòu)數(shù)據(jù)的規(guī)整
java父子節(jié)點(diǎn)parentid樹形結(jié)構(gòu)數(shù)據(jù)
這幾天寫一個(gè)父子節(jié)點(diǎn)的數(shù)據(jù)規(guī)整,在網(wǎng)上找了一些方法,都太繁瑣,自己寫了一個(gè),感覺比較簡單
先說一下原理
第一,我們從數(shù)據(jù)庫中將需要的數(shù)據(jù)查詢出來,得到一個(gè)Object集合的list
第二,定義一個(gè)map,key為id,value為Object,這個(gè)的目的是為了方便后面的查找
第三,遍歷第一步中查詢到的數(shù)據(jù)集合list,取出Object中的parentid,根據(jù)parentid從第二步map中取出它的父節(jié)點(diǎn),將其放入到父節(jié)點(diǎn)中去
第四,刪除map中父節(jié)點(diǎn)parentid不為空的數(shù)據(jù),這樣我們的數(shù)據(jù)結(jié)構(gòu)就組成了。
這里主要使用了java在參數(shù)傳遞時(shí),如果參數(shù)是一個(gè)object時(shí),那么它傳遞的是引用這么一個(gè)思想來進(jìn)行實(shí)現(xiàn),貼出代碼供大家參考
public class Test { public List<Goal> test(List<Goal> listGoal) { Map<Integer, Goal> goalMap = new HashMap<Integer, Goal>(); for (Goal g : listGoal) { int id = g.getId(); goalMap.put(id, g); } for (Goal g : listGoal) { int pid = g.getParentId(); if (pid != 0) { Goal tempGoal = goalMap.get(pid); List<Goal> tempListGoal = tempGoal.getListGoal(); if (tempListGoal == null) { tempListGoal = new ArrayList<Goal>(); } tempListGoal.add(g); tempGoal.setListGoal(tempListGoal); } } List<Integer> list = new ArrayList<Integer>(); for (Integer k : goalMap.keySet()) { Goal tempGoal = goalMap.get(k); if (tempGoal.getParentId() != 0) { list.add(k); } } for (int i : list) { goalMap.remove(i); } return new ArrayList<Goal>(goalMap.values()); } public static void main(String[] args) { List<Goal> listGoal = new ArrayList<Goal>(); Goal g1 = new Goal(); g1.setId(1); g1.setParentId(0); g1.setGoalName("g1"); Goal g2 = new Goal(); g2.setId(2); g2.setParentId(1); g2.setGoalName("g2"); Goal g3 = new Goal(); g3.setId(3); g3.setParentId(2); g3.setGoalName("g3"); Goal g4 = new Goal(); g4.setId(4); g4.setParentId(2); g4.setGoalName("g4"); Goal g5 = new Goal(); g5.setId(5); g5.setParentId(3); g5.setGoalName("g5"); Goal g6 = new Goal(); g6.setId(6); g6.setParentId(0); g6.setGoalName("g6"); Goal g7 = new Goal(); g7.setId(7); g7.setParentId(3); g7.setGoalName("g7"); Goal g8 = new Goal(); g8.setId(8); g8.setParentId(7); g8.setGoalName("g8"); Goal g9 = new Goal(); g9.setId(9); g9.setParentId(7); g9.setGoalName("g9"); Goal g10 = new Goal(); g10.setId(10); g10.setParentId(4); g10.setGoalName("g10"); Goal g11 = new Goal(); g11.setId(11); g11.setParentId(10); g11.setGoalName("g1"); Goal g12 = new Goal(); g12.setId(12); g12.setParentId(7); g12.setGoalName("g12"); Goal g13 = new Goal(); g13.setId(13); g13.setParentId(0); g13.setGoalName("g13"); listGoal.add(g1); listGoal.add(g2); listGoal.add(g3); listGoal.add(g4); listGoal.add(g5); listGoal.add(g6); listGoal.add(g7); listGoal.add(g8); listGoal.add(g9); listGoal.add(g10); listGoal.add(g11); listGoal.add(g12); listGoal.add(g13); Test t = new Test(); List<Goal> listT = t.test(listGoal); System.out.println(listT); }
java將有父子關(guān)系的數(shù)據(jù)轉(zhuǎn)換成樹形結(jié)構(gòu)數(shù)據(jù)
數(shù)據(jù)庫父子結(jié)構(gòu)數(shù)據(jù)設(shè)計(jì)
大部分采用 parentId的形式來存儲(chǔ)父id,并且只存儲(chǔ)父id,祖父Id不存儲(chǔ)。也可以添加存儲(chǔ)層級(jí)級(jí)別或者層級(jí)關(guān)系等字段。
CREATE TABLE `t_resource` ( `id` varchar(255) NOT NULL COMMENT '主鍵', `parent_id` varchar(255) DEFAULT NULL COMMENT '父ID', `name` varchar(255) DEFAULT NULL COMMENT '名稱', `url` varchar(255) DEFAULT NULL COMMENT '資源url', `level` varchar(255) DEFAULT NULL COMMENT '層級(jí)級(jí)別', `decode` varchar(255) DEFAULT NULL COMMENT '層級(jí)ID的關(guān)系,用”_“分割', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
將有父子關(guān)系的數(shù)據(jù)轉(zhuǎn)換成樹形結(jié)構(gòu)數(shù)據(jù)
mapper層獲取數(shù)據(jù)庫數(shù)據(jù)和 controller層處理很簡單,將有父子關(guān)系的數(shù)據(jù)轉(zhuǎn)換成樹形結(jié)構(gòu)數(shù)據(jù)交給 service層處理。
@PostMapping("/getMuneTree") @ResponseBody public ResponseEntity<Map<String, Object>> getMuneTree(){ Map<String, Object> map = new HashMap<>(); map.put("menuList", resourceDOService.getMuneTree()); return ResponseEntity.ok(map); }
1、方式一:遞歸:從樹的最頂級(jí)獲取子級(jí),然后子級(jí)獲取其子級(jí)。
返回時(shí),需要哪些字段值就添加哪些字段值到 map中。結(jié)果圖如上
/** * 將有父子關(guān)系的數(shù)據(jù)轉(zhuǎn)換成樹形結(jié)構(gòu)數(shù)據(jù) * * @return 最終的樹狀結(jié)構(gòu)的集合數(shù)據(jù) */ @Override public List<Map<String, Object>> getMuneTree() { // 獲取數(shù)據(jù)庫中帶有有父子關(guān)系的數(shù)據(jù) List<ResourceDO> data = resourceDOMapper.selectAll(); //創(chuàng)建一個(gè)List集合來存放最終的樹狀結(jié)構(gòu)數(shù)據(jù) List<Map<String, Object>> menuList = new ArrayList<>(); // 先存入最頂級(jí)的樹(0代表沒有父級(jí),即最頂級(jí)),然后通過最頂級(jí)的id遞歸獲取子級(jí) for (ResourceDO entity : data) { Map<String, Object> map = new HashMap<>(); if ("0".equals(entity.getParentId())) { map.put("id", entity.getId()); map.put("parentId", entity.getParentId()); map.put("name", entity.getName()); map.put("children", getChildren(data, entity.getId())); menuList.add(map); } } return menuList; } /** * 遞歸處理:通過id獲取子級(jí),查詢子級(jí)下的子級(jí) * * @param data 數(shù)據(jù)庫的原始數(shù)據(jù) * @param id 主id * @return 該id下得子級(jí) */ public List<Map<String, Object>> getChildren(List<ResourceDO> data, String id) { List<Map<String, Object>> list = new ArrayList<>(); if (data == null || data.size() == 0 || id == null) { return list; } for (ResourceDO entity : data) { Map<String, Object> map = new HashMap<>(); //如果本級(jí)id與數(shù)據(jù)的父id相同,就說明是子父級(jí)關(guān)系 if (id.equals(entity.getParentId())) { map.put("id", entity.getId()); map.put("parentId", entity.getParentId()); map.put("name", entity.getName()); //查詢子級(jí)下的子級(jí) map.put("children", getChildren(data, entity.getId())); list.add(map); } } return list; }
2、方式二:組裝帶有children關(guān)聯(lián)性的對(duì)象
在實(shí)體列中定義一個(gè) children集合:
private List<ResourceDO> children = new ArrayList<>();
返回的是實(shí)體類對(duì)象的所有值,這里操作的都是集合存儲(chǔ)對(duì)象的引用
/** * 將有父子關(guān)系的數(shù)據(jù)轉(zhuǎn)換成樹形結(jié)構(gòu)數(shù)據(jù) * * @return 最終的樹狀結(jié)構(gòu)的集合數(shù)據(jù) */ @Override public List<ResourceDO> getMuneTree2() { // 獲取數(shù)據(jù)庫中帶有有父子關(guān)系的數(shù)據(jù) List<ResourceDO> data = resourceDOMapper.selectAll(); // 復(fù)制data數(shù)據(jù) List<ResourceDO> menuList = new ArrayList<>(data); // 遍歷兩次data來組裝帶有children關(guān)聯(lián)性的對(duì)象,如果找到子級(jí)就刪除menuList的數(shù)據(jù) for (ResourceDO entity : data) { for (ResourceDO entity2 : data) { //如果本級(jí)id與數(shù)據(jù)的父id相同,就說明是子父級(jí)關(guān)系 if (entity.getId().equals(entity2.getParentId())) { entity.getChildren().add(entity2); menuList.remove(entity2); } } } return menuList; }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Java 遞歸查詢部門樹形結(jié)構(gòu)數(shù)據(jù)的實(shí)踐
- java返回前端樹形結(jié)構(gòu)數(shù)據(jù)的2種實(shí)現(xiàn)方式
- 詳解如何使用Java流API構(gòu)建樹形結(jié)構(gòu)數(shù)據(jù)
- java遞歸實(shí)現(xiàn)樹形結(jié)構(gòu)數(shù)據(jù)完整案例
- Java?處理樹形結(jié)構(gòu)數(shù)據(jù)的過程
- Java樹形結(jié)構(gòu)數(shù)據(jù)生成導(dǎo)出excel文件方法記錄
- Java如何使用遞歸查詢多級(jí)樹形結(jié)構(gòu)數(shù)據(jù)(多級(jí)菜單)
相關(guān)文章
SpringBoot中注冊(cè)Bean的10種方式總結(jié)
在Spring Boot應(yīng)用中,Bean是構(gòu)成應(yīng)用的核心組件,Spring容器負(fù)責(zé)管理這些Bean,包括它們的創(chuàng)建、配置、組裝、管理和銷毀,在Spring Boot中,有多種方式可以注冊(cè)Bean,本文將詳細(xì)介紹這些不同的注冊(cè)方式,并給出相應(yīng)的示例代碼和適用場景,需要的朋友可以參考下2024-08-08淺析如何在SpringBoot中實(shí)現(xiàn)數(shù)據(jù)脫敏
脫敏是指在不改變?cè)瓟?shù)據(jù)結(jié)構(gòu)的前提下,通過某種方式處理數(shù)據(jù),使數(shù)據(jù)不能直接暴露用戶的真實(shí)信息,下面我們就來看看SpringBoot中實(shí)現(xiàn)數(shù)據(jù)脫敏的具體方法吧2024-03-03解決Eclipse發(fā)布到Tomcat丟失依賴jar包的問題
這篇文章介紹了如何在Eclipse中配置部署裝配功能,以確保在將Web項(xiàng)目發(fā)布到Tomcat服務(wù)器時(shí)不會(huì)丟失任何依賴jar包,通過手動(dòng)配置或使用構(gòu)建工具腳本,可以自動(dòng)化這個(gè)過程,提高開發(fā)效率和應(yīng)用程序的穩(wěn)定性,感興趣的朋友跟隨小編一起看看吧2025-01-01Java CountDownLatch應(yīng)用場景代碼實(shí)例
這篇文章主要介紹了Java CountDownLatch應(yīng)用場景代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09Springboot微服務(wù)打包Docker鏡像流程解析
這篇文章主要介紹了Springboot微服務(wù)打包Docker鏡像流程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08