首先看一下菜单的样子
根据这个样子我们定义菜单类
publicclassMenu{ // 菜单id privateString id; // 菜单名称 privateString name; // 父菜单id privateString parentId; // 菜单url privateString url; // 菜单图标 privateString icon; // 菜单顺序 privateintorder; // 子菜单 privateList<Menu>childMenus; // ... 省去getter和setter方法以及toString方法}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
我们根据这个类定义数据库,并插入菜单数据
DROPTABLEIFEXISTS`jrbac_menu`;CREATETABLE`jrbac_menu`( `id`varchar(32)NOTNULLCOMMENT'主键id,uuid32位', `name`varchar(64)NOTNULLCOMMENT'菜单名称', `parent_id`varchar(32)DEFAULTNULLCOMMENT'父菜单id', `url`varchar(64)DEFAULTNULLCOMMENT'访问地址', `icon`varchar(32)DEFAULTNULLCOMMENT'菜单图标', `order`tinyint(4)DEFAULT'0'COMMENT'菜单顺序', PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8 COMMENT='菜单表';-- ------------------------------ Records of jrbac_menu-- ----------------------------INSERTINTO`jrbac_menu`VALUES('1','Forms',null,'forms.html','fa fa-edit','0');INSERTINTO`jrbac_menu`VALUES('2','UI Elements',null,'','fa fa-wrench','1');INSERTINTO`jrbac_menu`VALUES('3','Buttons','2','buttons.html','','0');INSERTINTO`jrbac_menu`VALUES('4','Icons','2','icons.html',null,'1');INSERTINTO`jrbac_menu`VALUES('5','Multi-Level Dropdown','','','fa fa-sitemap','2');INSERTINTO`jrbac_menu`VALUES('6','Second Level Item','5','second.html',null,'0');INSERTINTO`jrbac_menu`VALUES('7','Third Level','5',null,'','1');INSERTINTO`jrbac_menu`VALUES('8','Third Level Item','7','third.html',null,'0');
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
为了演示,我们把可展开的没有做完,仅仅插入几条数据能出效果就可以了。
测试方法与递归方法
privatefinalGson gson =newGsonBuilder().disableHtmlEscaping().create();@TestpublicvoidtestQueryMenuList(){ // 原始的数据 List<Menu>rootMenu =menuDao.queryMenuList(null); // 查看结果 for(Menu menu :rootMenu){ System.out.println(menu); } // 最后的结果 List<Menu>menuList =newArrayList<Menu>(); // 先找到所有的一级菜单 for(inti =0;i <rootMenu.size();i++){ // 一级菜单没有parentId if(StringUtils.isBlank(rootMenu.get(i).getParentId())){ menuList.add(rootMenu.get(i)); } } // 为一级菜单设置子菜单,getChild是递归调用的 for(Menu menu :menuList){ menu.setChildMenus(getChild(menu.getId(),rootMenu)); } Map<String,Object>jsonMap =newHashMap<>(); jsonMap.put("menu",menuList); System.out.println(gson.toJson(jsonMap));}/** * 递归查找子菜单 * * @param id * 当前菜单id * @param rootMenu * 要查找的列表 * @return */privateList<Menu>getChild(String id,List<Menu>rootMenu){ // 子菜单 List<Menu>childList =newArrayList<>(); for(Menu menu :rootMenu){ // 遍历所有节点,将父菜单id与传过来的id比较 if(StringUtils.isNotBlank(menu.getParentId())){ if(menu.getParentId().equals(id)){ childList.add(menu); } } } // 把子菜单的子菜单再循环一遍 for(Menu menu :childList){// 没有url子菜单还有子菜单 if(StringUtils.isBlank(menu.getUrl())){ // 递归 menu.setChildMenus(getChild(menu.getId(),rootMenu)); } }// 递归退出条件 if(childList.size()==0){ returnnull; } returnchildList;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
menuDao.queryMenuList(null);查找的结果是一条一条的数据
meuDao
packagecom.jrbac.dao;importjava.util.List;importcom.jrbac.entity.LoginUser;importcom.jrbac.entity.Menu;publicinterfaceMenuDao{ /** * 查找用户的菜单 * @param loginUser * @return */ publicList<Menu>queryMenuList(LoginUser loginUser);}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
mybatis
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.jrbac.dao.MenuDao"> <select id="queryMenuList" resultType="Menu"> SELECT id,`name`,parent_id,url,icon,`order` FROM jrbac_menu ORDER BY `order` ASC </select></mapper>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
测试程序的运行结果,对输出的json进行个格式化后的对比
最终效果
如果你也使用sbadmin后台模版的话,它只做到了二级菜单,三级的没有做展开控制。
要做到三级将sb-admin-2.js的最后一个替换成下面的。
if(element.is('li')){ element.addClass('active'); element.parent().addClass('in');}
- 1
- 2
- 3
- 4
再奉上前端jsp页面输出菜单的代码
<c:forEach items="${userMenuList }"var="menu"varStatus="status"> <!--一级子菜单没有parentId,有url --> <c:iftest="${empty menu.parentId and not empty menu.url}"> <li> <a href="<c:url value='${menu.url }'/>"> <i class="${menu.icon } fa-fw"></i>${menu.name } </a> </li> </c:if> <!--可展开的一级菜单,没有parentId,有url --> <c:iftest="${empty menu.parentId and empty menu.url}"> <li> <a href="#"> <i class="${menu.icon } fa-fw"></i>${menu.name }<span class="fa arrow"></span> </a> <ul class="nav nav-second-level"> <!--没有url的是三级菜单,有url的直接输出到li中 --> <c:forEach items="${menu.childMenus}"var="secondChild"varStatus="status"> <c:iftest="${not empty secondChild.url }"> <li> <a href="<c:url value='${secondChild.url }'/>">${secondChild.name }</a> </li> </c:if> <!--二级菜单url为空,表示还有三级菜单 --> <c:iftest="${empty secondChild.url }"> <li> <a href="#">${secondChild.name }<span class="fa arrow"></span></a> <ul class="nav nav-third-level"> <c:forEach items="${secondChild.childMenus}"var="thirdChild"varStatus="status"> <li> <a href="<c:url value='${thirdChild.url }'/>">${thirdChild.name }</a> </li> </c:forEach> </ul> </li> </c:if> </c:forEach> </ul> </li> </c:if></c:forEach>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41