Element的el-tree控件后臺數據結構的生成以及方法的抽取
時間:2020-03-05來源:電腦系統城作者:電腦系統城
最近用到了el-tree控件,主要是數據的格式,按照官網的數據格式來就可以顯示節點的樹形結構了。
代碼參考很多
這里給出一個比較好的鏈接:https://www.jb51.net/article/181990.htm
代碼說明在注釋里寫的很詳細了已經,這里不再敘述說明。至于為什么抽取成這種格式的數據,那是因為ElementUI-tree規定的數據格式,你想要用這個控件,就必須按照他們規定的這個格式 來。
數據格式如下:

Controller代碼
- @RequestMapping("/cateList")
- @ResponseBody
- public List<TbCategory> cateList() {
-
- // 整體思路:
- // 1、取得所有數據、放入集合List1 (tbCategories)
- // 2、將List1所有數據都放入到map(treeMap)中:元素id為鍵,元素本身對象為值
- // 3、取得頂層節點放入集合List2中(resultList)
- // 4、遍歷List1中的所有數據,通過數據的parentId為鍵在map中取值
- // 1)如果能取到,則說明該元素有父節點
- // 1、判斷該父節點下的childList中是否有已經子節點
- // 1、若無:則創建一個集合,將子節點放入
- // 2、若有:則直接將子節點放入即可
- // 5、把放好的數據放回到map中
- // 6、返回List2(resultList)
-
- // 注意:整個過程將所有數據取出放入list2(resultList),返回的也是 //list2
-
-
- List<TbCategory> tbCategories = categoryService.cateList();
-
- List<TbCategory> resultList = new ArrayList<TbCategory>(); // 存貯頂層的數據
-
- Map<Object ,Object> treeMap = new HashMap();
- Object itemTree;
-
- for(int i = 0;i<tbCategories.size() && !tbCategories.isEmpty();i++){
- itemTree = tbCategories.get(i);
- treeMap.put(tbCategories.get(i).getNodeId(),tbCategories.get(i));// 把所有的數據都放到map中
-
-
- }
-
-
- // 這里也可以用另一種方法,就是拿到集合里的每個元素的父id去數據庫中查詢,但是,這樣與數據庫的交互次數就太多了
- // 遍歷map得到頂層節點(游離節點也算作頂層節點)
- for(int i =0;i<tbCategories.size();i++){
- // 優點1:整個方法,只查詢了一次數據庫
- // 優點2:不用知道頂層節點的id
- if(!treeMap.containsKey(tbCategories.get(i).getParentId())){
- // 我們在存儲的時候就是將元素的id為鍵,元素本身為值存入的
- // 以元素的父id為鍵,在map里取值,若取不到則,對應的元素不存在,即沒有父節點,為頂層節點或游離節點
- // 將頂層節點放入list集合
- resultList.add(tbCategories.get(i));
- }
- }
-
- // 循環數據,將數據放到該節點的父節點的children屬性中
- for(int i =0 ;i<tbCategories.size()&& !tbCategories.isEmpty();i++){
- // 數據庫中,若一個元素有子節點,那么,該元素的id為子節點的父id
- //treeMap.get(tbCategories.get(i).getParentId()); // 從map集合中找到父節點
- TbCategory category = (TbCategory)treeMap.get(tbCategories.get(i).getParentId());
- if(category!=null ){ // 不等于null,也就意味著有父節點
- // 有了父節點,要判斷父節點下存貯字節點的集合是否存在,然后將子節點放入
- if(category.getChildList() == null){
- // 判斷一個集合是否被創建用null:表示結合還沒有被分配內存空間(即還沒有被創建),內存大小自然為null
- // 用集合的size判斷集合中是否有元素,為0,沒有元素(集合已經被創建),
- category.setChildList(new ArrayList<TbCategory>());
- }
- category.getChildList().add(tbCategories.get(i)); // 添加到父節點的ChildList集合下
-
- // 這一步其實可以不要,因為我們修改了數據(添加了子節點,然后在將元素放入到map中,
- // 若鍵相同,map會自動覆蓋掉相同的鍵值對,達到更新map集合中的數據的目的),但是我們
- // 這里只是從map中取值,而并不關心值的子節點(子節點是對象本身自己封裝的。這里我們知道
- // 元素從查詢后放入map,父節點放入list,然后通過鍵來在map中取得對象,之后再將修改過的對象重新放入map當中
- // ,我們并沒有直接操作list,但是在list中對象的值卻是已經修改過了,這就是對象的引用傳遞,同一個引用對象是通過
- // 地址值來操作對象的,即有不同的引用,但是對象中的屬性是已經通過引用的操作而改變的,所以這里一旦修改過后,無論是map中還是list中,再次取值時都已經是更改過后的值了)
- treeMap.put(tbCategories.get(i).getParentId(),category); // 把放好的數據放回到map中
- }
-
- }
-
-
- return resultList;
- }
實體類:
- private Long nodeId;
- private String categoryName;
- private Long parentId;
- private Long childId;
- private List<T> childList;
以上數據都在后臺封裝好了,前臺直接獲取數據顯示即可
- <el-tree :data="treeList"
- :props="defaultProps"
- @node-click="handleNodeClick"
- node-key="nodeId"
- show-checkbox=true>
- </el-tree>
js:
- defaultProps:{
- children: 'childList',
- label: 'categoryName' // 這里的名字要和你封裝的數據中的節點的名字一樣
- }
- // 點擊事件
- handleNodeClick: function (data) {
- console.log("沒做處理");
- }
方法抽取
上面的方法雖然也能用,但是想把這個方法抽取成一個通用的方法,以后再寫的時候就可以直接調取該方法了。抽取的過程中還是遇到了很多的問題的。
例如實體類A是對應數據庫中存儲節點的表的實體類,但是,實體類中是不存在setChildList、getChildList集合這些方法的。我就把這些存貯信息的字段寫在了一個工具類里面,然后方法也在該工具類里。這樣返回的時候就要返回一個裝有該工具類的一個集合了。還有一個問題就是該工具類中都需要那些字段?因為是一棵樹,所以我們需要節點id,幾點的父id,節點的名稱,以及存儲子節點的集合,如果想要更多的數據,可以添加一個 T data泛型,該泛型直接將原本存儲節點的實體類對象存儲進來。這樣所有的數據就都整齊了,數據結構也就完整了。
contrell代碼:
因為我們想抽取一個公用的方法,那么參數的類型就是不確定的,即傳入的list中元素的類型是不固定的,所以要用到泛型。上面說過了,我們要拿到節點id,父id,以及節點的名稱賦值給工具類中對應的字段。但是既然是用泛型,所以就不知道對象類型,所以我們在工具類中是點不出相應的方法來取到值的,我們就要用到反射,反射的知道類中具體的字段或者方法的名字來取值,所以我們在controller來調用工具類的時候就要,將節點id、父id和節點名稱傳入。當然了還要傳入從后臺查詢到了裝有數據的list集合。
contreller代碼如下所示:
- @RequestMapping("/cateList")
- @ResponseBody
- public List<TreeUtils> cateList() throws Exception{
- List<TbCategory> tbCategories = categoryService.cateList();
- List<TreeUtils> treeList = TreeUtils.getTreeList(tbCategories,"nodeId", "parentId","categoryName");
-
- return treeList;
- }
工具類:
- // 抽取方法的時候要考慮一個問題,即,返回一個集合,集合中有父節點和字節點,父節點和字節點的類型一定要統一,
- // 即這里返回的是一個裝有TreeUtils類型的集合,那么集合里的父節點和子節點一定都得是TreeUtils類型的
-
- public class TreeUtils<T> {
-
- private Integer id; // 節點id
- private Integer parentId; // 父節點
- private String name; // 節點名稱 ,返回給前臺的是一個裝有TreeUtils的集合的數據,所以在前臺顯示數據的時候,el-tree的lable的名字的和這個一樣
- private List<TreeUtils> childList; // 父節點中存放子節點的集合
- private T data; // 節點數據
方法
- /**
- * @param listData // 從數據庫中查詢的數據
- * @return
- */
- public static List<TreeUtils> getTreeList(List<?> listData ,String id,String parentId,StringcategoryName) throws Exception{
-
- List<TreeUtils> resultList = new ArrayList<TreeUtils>(); // 最終返回的結果
- Map<Integer ,Object> map = new HashMap<Integer,Object>();
-
- for(int i =0;i<listData.size() && !listData.isEmpty();i++){
-
- // 寫一個與該方法差不多的方法,將得到TreeUtils的代碼抽取出來
- // 也可以將listData集合整個轉換成裝有TreeUtils的集合x,然后再循環x
- TreeUtils treeUtils = new TreeUtils();
- treeUtils.setId(Integer.parseInt(TreeUtils.getFileValue(listData.get(i),id).toString())); // id // 返回值為Object無法直接轉換成Integer,先toString,再轉換成Integer。這里的返回值寫成Object是因為多種類型字段的值都可以用該方法
- treeUtils.setParentId(Integer.parseInt(TreeUtils.getFileValue(listData.get(i),parentId).toString()));// 父id
- treeUtils.setName(TreeUtils.getFileValue(listData.get(i),categoryName).toString()); // 節點名
- //System.out.println("節點名為+"+TreeUtils.getFileValue(listData.get(i),categoryName).toString());
- treeUtils.setData(listData.get(i)); // data:原對象中的所有屬性,無children
-
- // 通過反射得到每條數據的id將數據封裝的map集合中,id為鍵,元素本身為值
- map.put(treeUtils.getId(),treeUtils);
-
-
- // 將所有頂層元素添加到resultList集合中
- //if( 0 == treeUtils.getParentId()){
- // resultList.add(treeUtils);
- // }
- }
- // 得到所有的頂層節點,游離節點也算作頂層節點
- // 優點一,不用知道等級節點的id
- // 優點而,只查詢了一次數據庫
- for(int i =0;i<listData.size();i++){
- if(!map.containsKey(Integer.parseInt(TreeUtils.getFileValue(listData.get(i),parentId).toString()))){
- resultList.add((TreeUtils)map.get(Integer.parseInt(TreeUtils.getFileValue(listData.get(i),id).toString())));
- }
- }
-
-
-
- for(int i =0;i<listData.size() && !listData.isEmpty();i++){
- TreeUtils obj = (TreeUtils)map.get(Integer.parseInt(TreeUtils.getFileValue(listData.get(i),parentId).toString()));
- if(obj != null){
- if(obj.getChildList() == null){
- obj.setChildList(new ArrayList());
- }
- obj.getChildList().add(map.get(Integer.parseInt(TreeUtils.getFileValue(listData.get(i),id).toString())));
- }
- }
- return resultList;
- }
反射的方法
- /**
- * 通過反射得到的數據類型的也是不一定的,所以這里我們返回值為Object
- * Object是無法直接轉為Integer,現將Object轉為String,然后再將String轉為Integer
- * @param item
- * @param fileName
- * @return
- */
- public static Object getFileValue(Object item,String fileName) throws Exception {
- Class<?> aClass = item.getClass();
- Field file = aClass.getDeclaredField(fileName); // 得到所有字段包括私有字段
- file.setAccessible(true); // 取消訪問限制
- return file.get(item); // 這里就體現出反射的意思了,我們通常都是通過對象拿到字段,這里是通過字段,將類的字節碼對象為參數傳入,來得到值
- }
ps:抽取方法遇到了很多的問題,其中的T,?等泛型還只是會簡單的用,并不熟練,以后要多加學習。
到此這篇關于Element的el-tree控件后臺數據結構的生成以及方法的抽取的文章就介紹到這了,更多相關Element el-tree生成及方法抽取內容請搜索我們以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持我們!
相關信息