springEl 構建通用樹

? ? ? ? 再項目開發中,需要構建組織的樹形,菜單的樹形,字典樹形。感覺相似的代碼寫了一堆,就想著有沒有辦法,寫個通用的方法去處理下??? ? ??

????????學習了《SpringEL詳解》,用springEl處理下。

構建樹形:

菜單實體:

@Data
@ToString
public class Menu {private Integer id;private String name;private Integer parentId;private Integer sortId;private String url;private List<Menu> subMenus;public Menu(Integer id, String name, String url, Integer parentId) {this.id = id;this.name = name;this.url = url;this.parentId = parentId;this.subMenus = new ArrayList<>();}public Menu(Integer id, String name, Integer parentId) {this.id = id;this.name = name;this.parentId = parentId;this.subMenus = new ArrayList<>();}public Menu(Integer id, String name, Integer parentId, List<Menu> subMenus) {this.id = id;this.name = name;this.parentId = parentId;this.subMenus = subMenus;}
}

遞歸的方式:

    //  容易出現 大量無效的循環public static List<Menu> recursiveBuildTree(List<Menu> menus, int parentId) {List<Menu> result = new ArrayList<>();for (Menu menu : menus) {if (menu.getParentId().equals(parentId)) {// 遞歸查找子菜單menu.setSubMenus(recursiveBuildTree(menus, menu.getId()));result.add(menu);}}return result;}

遞歸的方式,還要主要限制層級和效率的問題

map的方式:

    public static List<Menu> buildTree(List<Menu> list, Integer matchParentId) {List<Menu> res = new ArrayList<>();// 創建一個Map,以id為鍵Map<Integer, List<Menu>> parentMenuMap = new HashMap<>();Integer parentId;for (Menu menu : list) {parentId = menu.getParentId();parentMenuMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(menu);}// 遍歷列表,將每個節點添加到其父節點的children列表中for (Menu menu : list) {menu.setSubMenus(parentMenuMap.getOrDefault(menu.getId(), new ArrayList<>()));// 從根節點開始構建樹,假設根節點的parentId為0if (matchParentId.equals(menu.getParentId())) {res.add(menu);}}return res;}

測試:
 public static void main(String[] args) {List<Menu> listMapTree = initMenus();List<Menu> result = MapBuildTree.buildTree(listMapTree, -1);System.out.println(JSON.toJSONString(result));} public static List<Menu> initMenus(){List<Menu> datas = new ArrayList<>();Menu root = new Menu(1, "root", "/", -1);Menu leaf2 = new Menu(2, "leaf1", "/", 1);Menu leaf3 = new Menu(3, "leaf2", "/", 1);Menu leaf4 = new Menu(4, "leaf11", "/api/v1/leaf11.html", 2);Menu leaf5 = new Menu(5, "leaf12", "/api/v1/leaf12.html", 2);datas.add(root);datas.add(leaf2);datas.add(leaf3);datas.add(leaf4);datas.add(leaf5);return datas;}

通用的方式

遞歸的方式:

過程:

1,獲取到父級id 用于匹配

2,設置子項

? ? ?

3,獲取id,用于遞歸

el 例子- 獲取值:
public static void main(String[] args) {Map<String, Object> myMap = new HashMap<>();myMap.put("name", "yan");myMap.put("id", 1222);myMap.put("position", "E");ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = new StandardEvaluationContext();// 設置變量context.setVariable("myMap", myMap);String value1 = parser.parseExpression("#myMap['name']").getValue(context, String.class);System.out.println(value1);Integer value2 = parser.parseExpression("#myMap['id']").getValue(context, Integer.class);System.out.println(value2);String value3 = parser.parseExpression("#myMap['position']").getValue(context, String.class);System.out.println(value3);}
el 例子-設置值:
?
public static void main(String[] args) {List<Map<String, Object>> listMapTree = initMenuMap();ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = new StandardEvaluationContext();String variableName ="myMap";Map<String, Object> mapList = new HashMap<>();mapList.put("id", 22);mapList.put("parentId", -1);mapList.put("children", new ArrayList<>());// 設置變量// 設置上下文中的變量context.setVariable(variableName, mapList);parser.parseExpression("#"+variableName+"['children']").setValue(context, listMapTree);System.out.println(JSON.toJSONString(mapList));}public static List<Map<String,Object>> initMenuMap(){return changeFormat(initData());}private static List<Map<String,Object>> changeFormat(String areaInfo){JSONArray areaArr = JSONArray.parseArray(areaInfo);return ListUtils.emptyIfNull(areaArr).stream().map(e -> (JSONObject) e).map(e -> (Map<String, Object>)JSONObject.parseObject( e.toJSONString())).collect(Collectors.toList());}public static String initData(){return "[{\"id\":1,\"name\":\"root\",\"parentId\":-1,\"subMenus\":[],\"url\":\"/\"},{\"id\":2,\"name\":\"leaf1\",\"parentId\":1,\"subMenus\":[],\"url\":\"/\"},{\"id\":3,\"name\":\"leaf2\",\"parentId\":1,\"subMenus\":[],\"url\":\"/\"},{\"id\":4,\"name\":\"leaf11\",\"parentId\":2,\"subMenus\":[],\"url\":\"/api/v1/leaf11.html\"},{\"id\":5,\"name\":\"leaf12\",\"parentId\":2,\"subMenus\":[],\"url\":\"/api/v1/leaf12.html\"}]";}

el 遞歸處理:
public static<T, E> List<T> buildTree(List<T> trees, String parentIdName,String idName, String childrenName, E matchParentId) {String variableName ="myMap";String parentIdVariName = "#" + variableName + "['" + parentIdName + "']";String childrenVariName = "#"+variableName+"['"+childrenName+"']";String idVariName = "#" + variableName + "['" + idName + "']";return buildTrees(trees, parentIdVariName, idVariName, childrenVariName, matchParentId, variableName);}public static<T, E> List<T> buildTrees(List<T> trees, String parentIdVariName,String idVariName, String childrenVariName, E matchParentId, String variableName ) {ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = new StandardEvaluationContext();List<T> result = new ArrayList<>();for (T node : trees) {//添加到下級數據中context.setVariable(variableName, node);E parentId = (E) parser.parseExpression(parentIdVariName).getValue(context);System.out.println(parentId);if(parentId == matchParentId){E id = (E) parser.parseExpression(idVariName).getValue(context);parser.parseExpression(childrenVariName).setValue(context, buildTrees(trees,parentIdVariName, idVariName, childrenVariName, id, variableName));result.add(node);}}return result;}
測試:
 public static void main(String[] args) {List<Menu> listMapTree = initMenus();List<Menu> result2 = RecurElBuildTree.buildTree(listMapTree, "parentId", "id", "subMenus", -1);System.out.println(JSON.toJSONString(result2));}

map的方式:

過程:

1,獲取到父級id 用于生成map對象

2,獲取id,設置子項

? ? ?

3,再獲取父節id,根據表達式判斷是否是父級

4,表達式可能多個點話,內容進行替換

?el-表達式:
 public static void main(String[] args) {ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = new StandardEvaluationContext();String variableName ="myMap";Map<String, Object> mapList = new HashMap<>();mapList.put("id", 22);mapList.put("parentId", -1);mapList.put("children", new ArrayList<>());// 設置變量// 設置上下文中的變量context.setVariable(variableName, mapList);Integer parentId = parser.parseExpression("#"+variableName+"['parentId']").getValue(context, Integer.class);System.out.println(parentId);Boolean equal  = parser.parseExpression(parentId +" == -1 || " + parentId+" == null").getValue(context, Boolean.class);System.out.println("express: " + equal);}
map處理:
import cn.hutool.core.util.StrUtil; 
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class TreeElUtil {public static<T, E> List<T> buildTreee(List<T> trees, String parentIdName,String idName, String childrenName, String parentIdExr) {ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = new StandardEvaluationContext();String variableName ="myMap";// 創建一個Map,以id為鍵Map<E, List<T>> parentMenuMap = new HashMap<>();String parentIdVariName = "#" + variableName + "['" + parentIdName + "']";for (T node : trees) {context.setVariable(variableName, node);E parentId = (E) parser.parseExpression(parentIdVariName).getValue(context);parentMenuMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(node);}List<T> result = new ArrayList<>();String childrenVariName = "#"+variableName+"['"+childrenName+"']";String idVariName = "#" + variableName + "['" + idName + "']";for (T node : trees) {//添加到下級數據中context.setVariable(variableName, node);E id = (E) parser.parseExpression(idVariName).getValue(context);
//            parser.parseExpression(childrenName).setValue(node, parentMenuMap.getOrDefault(id, new ArrayList<>()));parser.parseExpression(childrenVariName).setValue(context, parentMenuMap.getOrDefault(id, new ArrayList<>()));//如里是根節點,加入結構E parentId = (E) parser.parseExpression(parentIdVariName).getValue(context);// 這邊的String format = formatResult(parentIdExr, parentId);Boolean parent  = parser.parseExpression(format).getValue(context, Boolean.class);if (parent != null && parent) {result.add(node);}}return result;}private static String formatResult(String str, Object... param){String regExp = "\\{}";Pattern pattern = Pattern.compile(regExp);Matcher matcher = pattern.matcher(str);while(matcher.find()){str = StrUtil.format(str, param);;}return str;}}

測試:

map數據:

    public static void main(String[] args) {List<Map<String, Object>> listMapTree = initOrgMaps();String parentExr= "{} == -1 || {} == null";List<Map<String, Object>> result = TreeElUtil.buildTreee(listMapTree, "parentOrgId", "orgId", "subOrgs", parentExr);System.out.println(JSON.toJSONString(result));}public static List<Map<String, Object>> initOrgMaps(){List<Map<String, Object>> datas = new ArrayList<>();Map<String, Object> root = generateMap(1, "主部門", -1);Map<String, Object> leaf2 = generateMap(2, "業務部門", 1);Map<String, Object> leaf3 = generateMap(3, "開發部門", 1);Map<String, Object> leaf4 = generateMap(4, "業務部門11", 2);Map<String, Object> leaf5 = generateMap(5, "業務部門12", 2);datas.add(root);datas.add(leaf2);datas.add(leaf3);datas.add(leaf4);datas.add(leaf5);return datas;}public static Map<String, Object> generateMap(Integer orgId, String name, Integer parentOrgId){Map<String, Object> map = new HashMap<>();map.put("orgId", orgId);map.put("parentOrgId", parentOrgId);map.put("name", name);map.put("subOrgs", new ArrayList<>());return map;}

bean格式數據:

org:
@Data
@ToString
public class Org {private Integer orgId;private String name;private Integer parentOrgId;private Integer sortId;private List<Org> subOrgs;public Org(Integer orgId, String name, Integer parentOrgId) {this.orgId = orgId;this.parentOrgId = parentOrgId;this.name = name;this.subOrgs = new ArrayList<>();}
}
測試:
public static void main(String[] args) {List<Org> listMapTree = initOrgs();String parentExr= "{} == -1 || {} == null";List<Org> result = TreeElUtil.buildTreee(listMapTree, "parentOrgId", "orgId", "subOrgs", parentExr);System.out.println(JSON.toJSONString(result));}public static List<Org> initOrgs(){List<Org> datas = new ArrayList<>();Org root = new Org(1, "主部門", -1);Org leaf2 = new Org(2, "業務部門", 1);Org leaf3 = new Org(3, "開發部門", 1);Org leaf4 = new Org(4, "業務部門11", 2);Org leaf5 = new Org(5, "業務部門12", 2);datas.add(root);datas.add(leaf2);datas.add(leaf3);datas.add(leaf4);datas.add(leaf5);return datas;}

總結:

? ? ? ? 如果相似的代碼出現多次,就可以考慮做一個通用的處理。SpringEL的功能很強大,不過這個用java8的特性去處理,看起來更直觀。

? ? ? ? 學習了SpringEl,就想辦法多應用,遇到不懂的再學習,這樣才會學得更深,才容易舉一反三。

? ? ? ? 關聯文章:《java8 構建通用樹》

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/66853.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/66853.shtml
英文地址,請注明出處:http://en.pswp.cn/web/66853.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++ 入門速通-第1章【黑馬】

內容來源于&#xff1a;黑馬 集成開發環境&#xff1a;CLion CLion的官方下載網址&#xff1a;CLion: A Cross-Platform IDE for C and C by JetBrains 我在b站找到了一個安裝教程&#xff0c;可以按照這個視頻教程進行安裝&#xff08;內置漢化教程&#xff09;&#xff1a; …

Python的進程和線程

ref 接受幾個設定: 進程是一家almost密不透風的公司,緬甸KK園區 線程里面工作的…人 進程**[園區]**內公共資源對于進程來說,可以共享. 別的園區[進程],一般不能和自己的園區共享人員資源,除非… 好的,現在再接受設定: 單個CPU在任一時刻只能執行單個線程&#xff0c;只有…

算法基礎 -- AVL樹初識

AVL樹初識 一、AVL樹簡介 AVL樹是一種自平衡二叉搜索樹&#xff08;Binary Search Tree, BST&#xff09;&#xff0c;于1962年由Georgy Adelson-Velsky和Evgenii Landis提出&#xff0c;名字也來自他們兩位的姓氏首字母組合。它通過在插入、刪除節點后維持平衡性&#xff0c…

MySQL數值型函數詳解

簡介 本文主要講解MySQL數值型函數&#xff0c;包括&#xff1a;ROUND、RAND、ABS、MOD、TRUNCATE、CEIL、CEILING、FLOOR、POW、POWER、SQRT、LOG、LOG2、LOG10、SIGN、PI。 本文所有示例中&#xff0c;雙橫杠左邊為執行的SQL語句&#xff0c;右邊為執行語句的返回值。 ROU…

自動化01

測試用例的萬能公式&#xff1a;功能測試界面測試性能測試易用性測試安全性測試兼容性測試 自動化的主要目的就是用來進行回歸測試 新產品--第一個版本 (具備豐富的功能)&#xff0c;將產品的整體進行測試&#xff0c;人工創造一個自動化測試用例&#xff0c;在n個版本的時候…

Spring中的事務管理器TransactionManager

目錄 一、主要功能 二、使用場景說明 在Spring框架中&#xff0c;事務管理器&#xff08;TransactionManager&#xff09;是用于管理事務的重要接口。它提供了對事務的全面控制&#xff0c;包括事務的狀態管理和資源管理等功能。本文將詳細介紹TransactionManager的主要功能、…

c語言(轉義字符)

前言&#xff1a; 內容&#xff1a; 然后記一下轉義字符 \? 在書寫連續多個問號時使用&#xff0c;防止他們被解析成三字母詞 \ 用于表示字符常量 \\ 用于表示一個反斜杠&#xff0c;防止他被解析為一個轉義序列符 \n 換行 \r …

Vue3 30天精進之旅:Day02 - 環境搭建

引言 在前一天的學習中&#xff0c;我們了解了Vue.js的基本概念和優勢。今天&#xff0c;我們將進入實際開發的第一步——環境搭建。良好的開發環境是順利開展項目的基礎&#xff0c;本文將指導你在本地設置Vue開發環境&#xff0c;并快速上手第一個Vue項目。 1. 環境準備 在…

代碼隨想錄 棧與隊列 test 7

347. 前 K 個高頻元素 - 力扣&#xff08;LeetCode&#xff09; 首先想到哈希&#xff0c;用key來存元素&#xff0c;value來存出現次數&#xff0c;最后進行排序&#xff0c;時間復雜度約為o(nlogn)。由于只需求前k個&#xff0c;因此可以進行優化&#xff0c;利用堆來維護這…

匯編實驗·子程序設計

一、實驗目的: 1.掌握匯編中子程序編寫方法 2.掌握程序傳遞參數的基本方法,返回值的方法。 3.掌握理解子程序(函數)調用的過程 二、實驗內容 1.編寫匯編語言子程序,實現C表達式SUM=X+Y的功能,具體要求: 1)函數的參數傳遞采用寄存器實現 2)函數的參數傳遞采用堆棧…

jmeter中對接口進行循環請求后獲取相應數據

1、工作中遇到一個場景就是對某個單一接口進行循環請求&#xff0c;并需要獲取每次請求后返回的相應數據&#xff1b; 2、首先就在jmeter對接口相關組件進行配置&#xff0c;需要組件有&#xff1a;循環控制器、CSV數據文件設置、計數器、訪問接口、HTTP信息頭管理器、正則表達…

trimesh 旋轉

trimesh.transformations.rotation_matrix(np.radians(rot_angle), rot_axis) np.radians(rot_angle)&#xff1a;將角度 rot_angle 轉換為弧度。trimesh 和大多數 3D 庫通常使用弧度來表示旋轉角度&#xff0c;而不是角度。 rot_axis&#xff1a;表示旋轉軸的向量。例如&…

Jetson Xavier NX 安裝 CUDA 支持的 PyTorch 指南

本指南將幫助開發者完成在 Jetson Xavier NX 上安裝 CUDA 支持的 PyTorch。 安裝方法 在 Jetson 上安裝 Pytorch 只有兩種方法。 一種是直接安裝他人已經編譯好的 PyTorch 輪子&#xff1b;一種是自己從頭開始開始構建 PyTorch 輪子并且安裝。 使用輪子安裝 可以從我的 Gi…

Ansible fetch模塊詳解:輕松從遠程主機抓取文件

在自動化運維的過程中&#xff0c;我們經常需要從遠程主機下載文件到本地&#xff0c;以便進行分析或備份。Ansible的fetch模塊正是為了滿足這一需求而設計的&#xff0c;它可以幫助我們輕松地從遠程主機獲取文件&#xff0c;并將其保存到本地指定的位置。在這篇文章中&#xf…

【AI論文】生成式視頻模型是否通過觀看視頻學習物理原理?

摘要&#xff1a;AI視頻生成領域正經歷一場革命&#xff0c;其質量和真實感在迅速提升。這些進步引發了一場激烈的科學辯論&#xff1a;視頻模型是否學習了能夠發現物理定律的“世界模型”&#xff0c;或者&#xff0c;它們僅僅是復雜的像素預測器&#xff0c;能夠在不理解現實…

論文速讀|Matrix-SSL:Matrix Information Theory for Self-Supervised Learning.ICML24

論文地址&#xff1a;Matrix Information Theory for Self-Supervised Learning 代碼地址&#xff1a;https://github.com/yifanzhang-pro/matrix-ssl bib引用&#xff1a; article{zhang2023matrix,title{Matrix Information Theory for Self-Supervised Learning},author{Zh…

視覺語言模型 (VLMs):跨模態智能的探索

文章目錄 一. VLMs 的重要性與挑戰&#xff1a;連接視覺與語言的橋梁 &#x1f309;二. VLMs 的核心訓練范式&#xff1a;四種主流策略 &#x1f5fa;?1. 對比訓練 (Contrastive Training)&#xff1a;拉近正例&#xff0c;推遠負例 ??2. 掩碼方法 (Masking)&#xff1a;重構…

數據結構——堆(介紹,堆的基本操作、堆排序)

我是一個計算機專業研0的學生卡蒙Camel&#x1f42b;&#x1f42b;&#x1f42b;&#xff08;剛保研&#xff09; 記錄每天學習過程&#xff08;主要學習Java、python、人工智能&#xff09;&#xff0c;總結知識點&#xff08;內容來自&#xff1a;自我總結網上借鑒&#xff0…

c++迷宮問題(migong)

今天的題目叫“迷宮問題(migong&#xff09;”&#xff0c;是“DFS深度優先搜索 遞歸”一類的。 題目描述 設有一個N*N(2<N<10)方格的迷宮&#xff0c;入口和出口分別在左上角和右上角。迷宮格子中 分別放0和1&#xff0c;0表示可通&#xff0c;1表示不能&#xff0c;入…

機器學習-線性回歸(簡單回歸、多元回歸)

這一篇文章&#xff0c;我們主要來理解一下&#xff0c;什么是線性回歸中的簡單回歸和多元回歸&#xff0c;順便掌握一下特征向量的概念。 一、簡單回歸 簡單回歸是線性回歸的一種最基本形式&#xff0c;它用于研究**一個自變量&#xff08;輸入&#xff09;與一個因變量&…