项目描述
最近使用SSM做后台系统,已经使用递归的形式动态获取到多级菜单,现写一个多级菜单的管理程序,用于直接遍历出所有菜单,并实现创建菜单以及对菜单的管理与删除。
具体实现效果如下
实现方案
在后台以深度先序递归的方式将数据以JSON的形式遍历出来,在菜单数据表中,主要使用了两个,一个是id,一个是pid,其他数据字段再此不描述。具体流程图
1、先创建多叉树主节点主节点的pid=null,id=0。2、通过查找下一节点节点pid=主节点id值,进行创建子节点
3、遍历使用深度优先遍历的先序搜索进行遍历输出
实现代码
多叉树的节点结构为一个实体MenuTree.class
package com.song.model;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.song.model.AdminMenu;
public class MenuTree{
//AdminMenu 为菜单实体
private AdminMenu nodeEntity;
private MenuTree parentNode;
private List<MenuTree> childNodes;
public MenuTree(AdminMenu nodeEntity) {
this.getParentNode();
initChildList();
}
public MenuTree () {
initChildList();
}
/* 插入一个child节点到当前节点中 */
public void addChildNode(MenuTree childNode){
initChildList();
this.childNodes.add(childNode);
}
public MenuTree getParentNode() {
return parentNode;
}
public void setParentNode(MenuTree parentNode) {
this.parentNode = parentNode;
}
public AdminMenu getNodeEntity() {
return nodeEntity;
}
public void setNodeEntity(AdminMenu nodeEntity) {
this.nodeEntity = nodeEntity;
}
public List<MenuTree> getChildNodes() {
return childNodes;
}
public void setChildNodes(List<MenuTree> childNodes) {
this.childNodes = childNodes;
}
}
//返回前端JSON数组
@ResponseBody
@RequestMapping(value="/menupower",produces = "application/json;charset=UTF-8")
public String menupower() {
List<AdminMenu> menuall = adminmenuservice.superapimenuall();
List<AdminMenu> menuallapi =new ArrayList<AdminMenu>();
//创建一个AdminMenu的对象作为多叉树的根的值
AdminMenu root=new AdminMenu();
root.setId(0);
//创建跟节点
MenuTree roottree =new MenuTree();
roottree.setNodeEntity(root);
//开始创建多叉树
CreateTree(roottree,menuall);
//遍历多叉树,roottree 为多叉树的根节点,这个函数将根节点遍历给全局变量allmenu对象数组中
DFStraverse(roottree,menuallapi);
if(menuallapi.size()==0) {
return SuperCommon.SuperJson(menuallapi,"超级权限中的菜单管理出错!");
}
return JSON.toJSONString(menuallapi);
}
//创建多叉树
public boolean CreateTree(MenuTree menutree,List<AdminMenu> menuall) {
if(menutree==null)
return false;
//先获取同等级节点
List<AdminMenu> rootMenu = new ArrayList<AdminMenu>();
for (AdminMenu res : menuall) {
if (menutree.getNodeEntity().getId().equals(res.getPid())) {// 父节点是0的,为根节点。
rootMenu.add(res);
}
}
// 根据Menu类的order排序 ,对同等级节点进行排序
Collections.sort(rootMenu, order());
//对rootmenu继续创建节点
for(AdminMenu res :rootMenu) {
System.out.println("menutree.getNodeEntity().getId()---------"+menutree.getNodeEntity().getId()+"--------res.getPid()------"+res.getPid());
if(menutree.getNodeEntity().getId().equals(res.getPid())) {
System.out.println(JSON.toJSONString(res));
//使用正则表达式判断获取的id属于第几级菜单,赋予不通的cname值
if(Pattern.matches("^[1-9]{1}00",Integer.toString(res.getId()))) {
res.setCname(" "+res.getName());
}else if(Pattern.matches("^[1-9]{2}0$",Integer.toString(res.getId()))) {
res.setCname(" ├"+res.getName());
}else {
res.setCname(" |└"+res.getName());
}
MenuTree leaf=new MenuTree();
leaf.setNodeEntity(res);
menutree.addChildNode(leaf);
CreateTree(leaf,menuall);
}
}
return true;
}
/* 遍历一棵树,层次遍历 */
public void DFStraverse(MenuTree tree,List<AdminMenu> menuapi) {
if (tree.getChildNodes() == null || tree.getChildNodes().isEmpty())
return;
int childNumber = tree.getChildNodes().size();
for (int i = 0; i < childNumber; i++) {
MenuTree child = tree.getChildNodes().get(i);
menuapi.add(child.getNodeEntity());
DFStraverse(child,menuapi);
}
}
/*
* 排序,根据order排序
*/
public Comparator<AdminMenu> order() {
Comparator<AdminMenu> comparator = new Comparator<AdminMenu>() {
@Override
public int compare(AdminMenu o1, AdminMenu o2) {
if (o1.getSort() != o2.getSort()) {
return o1.getSort() - o2.getSort();
}
return 0;
}
};
return comparator;
}
返回前端的数据格式
总结
在采用多叉树遍历所有菜单时,有点笨,使用了两天时间,到现在才明白过来具体具体算法思路,再创建多叉树的时候时由于遇到的一些问题,比如以后创建菜单时会不会发生id冲突,或者创建菜单的级别不同等问题,在创建菜单数据表时对菜单的id与pid做了以下情况,同时菜单只能建立三级,同级只能有九列。