樹形菜單應該是很常見的了,類似下面這種,通常我們的做法是后端從數據庫中查詢出來數據,然后將其轉為樹的結構,丟給前端,前端就渲染到樹組件中;
那么返給前端的數據是什么樣的呢?如下所示
[ { id: 1, label: '一級 1', children: [{ id: 4, label: '二級 1-1', children: [{ id: 9, label: '三級 1-1-1' }, { id: 10, label: '三級 1-1-2' }] }] }, {xxx} ]
那么對應在數據庫中的表示什么樣子的呢?Subject表下圖所示,如果parent_id為0的,表示是一級菜單,其他多個二級菜單的parent_id等於某個一級菜單的id,依次類推,可有有很多級別菜單
下面用java代碼實現
1.工具類:
package com.protagonist.edu.utils; import com.protagonist.edu.bo.SubjectTreeNodeBO; import com.protagonist.edu.entity.Subject; import com.protagonist.responseVO.StatusCode; import com.protagonist.servicebase.exception.ProtagonistException; import org.springframework.beans.BeanUtils; import org.springframework.util.CollectionUtils; import java.util.*; /** * 用於構建樹形結構 */ public class TreeUtil { /** * 默認樹形菜單最頂層的pid是"0" * @param list 所有數據 * @return 樹形的數據 */ public static List<SubjectTreeNodeBO> buildTree(List<Subject> list) { if (CollectionUtils.isEmpty(list)){ throw new ProtagonistException(StatusCode.ERROR,"查詢的菜單數據為空,不能轉為樹形"); } return buildTree(list, "0"); } /** * 獲取樹形菜單結構 * 思路:首先遍歷一次將所有的數據轉化為前端需要的數據類型,然后放入到map中,以id->T對應關系 * 然后再遍歷一次,這次的話判斷parentId是否為0(這里暫時可以特使pid為0時表示一級菜單),是的話就是一級菜單,就放到rootTree中; * 不為0的話,說明不是一級菜單,我們就需要獲取它的父菜單 * 根據pid去map中獲取,然后將當前菜單放入其父菜單的子菜單中,等遍歷完之后樹形菜單就ok了,這種做法可以完成多級子菜單變成樹形 * @param list 所有的數據 * @param pid 父id * @return 樹形數據 */ public static List<SubjectTreeNodeBO> buildTree(List<Subject> list, String pid) { if (CollectionUtils.isEmpty(list)){ throw new ProtagonistException(StatusCode.ERROR,"查詢的菜單數據為空,不能轉為樹形"); } List<SubjectTreeNodeBO> allTreeNode = new ArrayList<>(); List<SubjectTreeNodeBO> rootTree = new ArrayList<>(); Map<String, SubjectTreeNodeBO> nodeMap = new HashMap<>(); //將所有的數據都放入到map中一份 for (Subject item : list) { SubjectTreeNodeBO nodeBO = new SubjectTreeNodeBO(); BeanUtils.copyProperties(item,nodeBO); allTreeNode.add(nodeBO); nodeMap.put(item.getId(),nodeBO); } for (SubjectTreeNodeBO t : allTreeNode) { //如果父id等於傳進來的pid,那么該菜單是最頂級的菜單,放入到rootTree中 if (Objects.equals(t.getParentId(), pid)){ rootTree.add(t); //如果不是頂級菜單,那就獲取父菜單,然后嫁給你本BO設置到父菜單的children中 }else { SubjectTreeNodeBO parentNode = nodeMap.get(t.getParentId()); parentNode.getChildren().add(t); } } return rootTree; } }
2.subject類:
@Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) @TableName("subject") @ApiModel(value="Subject對象", description="課程科目") public class Subject implements Serializable { private static final long serialVersionUID = 1L; @ApiModelProperty(value = "課程類別ID") @TableId(value = "id", type = IdType.ID_WORKER_STR) private String id; @ApiModelProperty(value = "類別名稱") private String title; @ApiModelProperty(value = "父ID") private String parentId; }
3.SubjectTreeNodeBO類:
package com.protagonist.edu.bo; import lombok.Data; import java.util.ArrayList; import java.util.List; @Data public class SubjectTreeNodeBO { private String id; private String title; private String parentId; private List<SubjectTreeNodeBO> children = new ArrayList<>(); }
4. 測試,成功,然后配合element的Tree 樹形控件一起使用,就行了