有做过网站菜单的童鞋,都知道树级结构,因为展开的形式就是一棵树一样,有父节点、子节点。实现树级结构菜单的形式有很多,例如主从表的形式,一张表存父节点,一张表存子节点,这种方式可能存在一种问题,就是只能支持两级,并且不容易进行扩展。在这里,我想讲的是另一种形式,单表存储的方式。即一张表里面既有子节点,又有父节点,然后实现树级结构,具体介绍请往下看:
一、表结构
如上图可以看到,每一条记录都有一个pid,代表的是父节点的ID,这里我们的菜单根节点,也就是最大的父节点的ID为-1,其他的都是他的子孙们。
二、递归算法
要想对这种数据进行组织形成最后的树级结构,需要才要递归算法,递归怎么理解?你就想它自己在不断调用自己就行了,当然,你需要注意的是它有一个特点,就是肯定有一个跳出递归的条件,否则岂不是会进入死循环吗?
public Map queryMenus(Map prams){
List<Map> menus = ToLowerCaseForList(iSysUserDao.queryMenus(prams));
Map retMap = new HashMap();
retMap.put("menus",recursionMenu(menus));
return retMap;
}
public List recursionMenu(List<Map> list){
List treeList = new ArrayList();
// 循环查出的list,找到根节点(最大的父节点)的子节点
for(Map map : list){
// 我们这里最大的根节点ID是-1,所以首先找pid为-1的子,然后调用我们的递归算法
if("-1".equals(map.get("pid").toString())){
treeList.add(addChildMenu(map,list));
}
}
return treeList;
}
public List addChildMenu(Map parentMap, List<Map> list){
List<Map> childList = new ArrayList<>();
// 为每一个父节点增加子树(List形式,没有则为空的list)
parentMap.put("children",childList);
for (Map childMap : list){
//如果子节点的pid等于父节点的ID,则说明是父子关系
if(childMap.get("pid").toString().equals(parentMap.get("id").toString())){
// 是父子关系,则将其放入子list字面
childList.add(childMap);
// 继续调用递归算法,将当前作为父节点,继续找他的子节点,反复执行。
addChildMenu(childMap,list);
}
}
// 当遍历完成,返回调用的父节点的所有子节点
return childList;
}
如代码所示,每次将一个子节点作为父节点,递归调用查找子节点方法,直到所有的子节点都找完,返回主方法,递归结束。
三、结果展示
{
"menus": [
[
{
"code": "P2300",
"i18nid": 361,
"useflag": 1,
"icon": "icon-blank",
"pid": -3,
"functionurl": "",
"functionid": "",
"padimg": "",
"children": [],
"i18ntype": "",
"name": "VUE",
"id": 656,
"seq": 0
}
],
[
{
"code": "Report",
"i18nid": 8,
"useflag": 1,
"icon": "icon-report",
"pid": -2,
"functionurl": "",
"functionid": "",
"padimg": "",
"children": [],
"i18ntype": "zh_CN",
"name": "统计报表",
"id": 137,
"seq": 40
},
{
"code": "BoardMgr",
"i18nid": 331,
"useflag": 1,
"icon": "icon-setting",
"pid": -2,
"functionurl": "./Board/BoardUrlIndex",
"functionid": "",
"padimg": "",
"children": [],
"i18ntype": "",
"name": "看板管理",
"id": 376,
"seq": 50
},
{
"code": "DeviceMgr",
"i18nid": 6,
"useflag": 1,
"icon": "icon-devicemgr",
"pid": -2,
"functionurl": "",
"functionid": "",
"padimg": "",
"children": [
{
"code": "MonitorDevAlarm",
"i18nid": 273,
"useflag": 1,
"icon": "icon-blank",
"pid": 66,
"functionurl": "./Technics/MonitorDevAlarm",
"functionid": "",
"padimg": "",
"children": [],
"i18ntype": "",
"name": "设备告警",
"id": 599,
"seq": 15
},
{
"code": "DeviceRecord",
"i18nid": 278,
"useflag": 1,
"icon": "icon-blank",
"pid": 66,
"functionurl": "",
"functionid": "",
"padimg": "",
"children": [
{
"code": "MaintainOperate",
"i18nid": 285,
"useflag": 2,
"icon": "icon-blank",
"pid": 616,
"functionurl": "./Device/MaintainOperate",
"functionid": "",
"padimg": "",
"children": [],
"i18ntype": "",
"name": "保养次数",
"id": 621,
"seq": 3
},
{
"code": "SpotCheckOperate",
"i18nid": 286,
"useflag": 2,
"icon": "icon-blank",
"pid": 616,
"functionurl": "./Device/SpotCheckOperate",
"functionid": "",
"padimg": "",
"children": [],
"i18ntype": "",
"name": "点检次数",
"id": 622,
"seq": 6
}
],
"i18ntype": "",
"name": "设备履历",
"id": 616,
"seq": 3
}
],
"i18ntype": "zh_CN",
"name": "设备管理",
"id": 66,
"seq": 10
},
{
"code": "systool",
"i18nid": 12,
"useflag": 1,
"icon": "icon-systool",
"pid": -2,
"functionurl": "",
"functionid": "",
"padimg": "",
"children": [],
"i18ntype": "zh_CN",
"name": "开发关联",
"id": 1,
"seq": 99
},
{
"code": "系统管理",
"i18nid": 11,
"useflag": 1,
"icon": "icon-sysmgr",
"pid": -2,
"functionurl": "",
"functionid": "",
"padimg": "",
"children": [],
"i18ntype": "zh_CN",
"name": "系统管理",
"id": 5,
"seq": 98
},
{
"code": "OrderMgr",
"i18nid": 4,
"useflag": 1,
"icon": "icon-order",
"pid": -2,
"functionurl": "",
"functionid": "",
"padimg": "",
"children": [],
"i18ntype": "zh_CN",
"name": "工单管理",
"id": 11,
"seq": 0
},
{
"code": "ProduceMonit",
"i18nid": 333,
"useflag": 1,
"icon": "icon-producemonit",
"pid": -2,
"functionurl": "",
"functionid": "",
"padimg": "",
"children": [],
"i18ntype": "",
"name": "生产管理",
"id": 22,
"seq": 5
},
{
"code": "Technics",
"i18nid": 5,
"useflag": 1,
"icon": "icon-technics",
"pid": -2,
"functionurl": "",
"functionid": "",
"padimg": "",
"children": [],
"i18ntype": "zh_CN",
"name": "工艺管理",
"id": 575,
"seq": 20
},
{
"code": "NotifyMgr",
"i18nid": 9,
"useflag": 1,
"icon": "icon-board",
"pid": -2,
"functionurl": "",
"functionid": "",
"padimg": "",
"children": [],
"i18ntype": "",
"name": "预警管理",
"id": 578,
"seq": 49
},
{
"code": "BasicData",
"i18nid": 10,
"useflag": 1,
"icon": "icon-basicdata",
"pid": -2,
"functionurl": "",
"functionid": "",
"padimg": "",
"children": [],
"i18ntype": "",
"name": "基础数据",
"id": 157,
"seq": 60
}
]
]
}
这里的递归方法有一个不好的地方,就是每次调用的时候,都会传进最大的list,这就导致了,可能同一个节点被循环很多遍。
你有更好的办法解决吗?欢迎留言~~~ 我的另一种方法下回揭晓。