之前项目中是使用的最多两级菜单,所以当时写的是两个for 循环,一旦多层菜单,维护起来就麻烦,所以今天使用递归实现导航栏动态生成。在这里主要java 后台代码,以及简单js 递归后台json 数据。数据库就没有在这里设计。
1、Menu实体类
package com.dairuijie.pojo;
import java.util.List;
/**
* 菜单类
*
* @Title: Menu.java
* @Package com.dairuijie.pojo
* @author Drj
* @date 2018年3月2日 下午6:15:00
* @version V1.0
*/
public class Menu {
private String id;
// 菜单名称
private String menuName;
// 父菜单id
private String parentId;
// 菜单url
private String url;
// 菜单图标
private String icon;
// 菜单顺序
private int order;
// 子菜单
private List<Menu> childMenus;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public List<Menu> getChildMenus() {
return childMenus;
}
public void setChildMenus(List<Menu> childMenus) {
this.childMenus = childMenus;
}
}
2、测试递归类
package com.dairuijie.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import com.dairuijie.pojo.Menu;
import com.google.gson.Gson;
/**
*
* @Title: MenuTest.java
* @Package com.dairuijie.controller
* @author Drj
* @date 2018年3月2日 下午7:00:56
* @version V1.0
*/
public class MenuTest {
private static List<Menu> getChild(String id, List<Menu> rootMenu) {
List<Menu> childList = new ArrayList<>();//存放直接子菜单
/**
*开始遍历二级菜单以及它的直接子菜单
*/
for (Menu menu : rootMenu) {
// 遍历所有节点,将父菜单id与传过来的id比较
if (StringUtils.isNotBlank(menu.getParentId())) {//导入org.apache.commons.lang3.StringUtils;
if (id.equals(menu.getParentId())) {//尽量让id 在前面,因为他不会为空(数据库设计为主键),parentId 不一定都有值。
childList.add(menu);//相等的话说明这些使它(id)的直接子节点,加入childList
}
}
}//这时候已经将一级菜单以及一级的直接子孩子遍历出来了。
/**
* 把子菜单的直接子菜单再循环一遍
* 这时候就是从Menu的直接子菜单中获得需要遍历的菜单也就是childList
*/
for (Menu menu : childList) {
if (StringUtils.isBlank(menu.getUrl())) {//这个判断的意思是 如果url 不为空说明是最后一个节点,为空说明他不是最后一个子节点,这时候就需要去遍历
menu.setChildMenus(getChild(menu.getId(), rootMenu));//递归
}
}
if (childList.size() == 0) {// 递归退出条件(走到这里childList 大小等于0 说明该节点就是最后一个)
return null;
}
return childList;
}
public static void main(String[] args) {
List<Menu> rootMenus = new ArrayList<Menu>();//假设是从数据库查出来的
List<Menu> menuList = new ArrayList<Menu>();
/**
* 先找到所有的一级菜单
*/
for (int i = 0; i < rootMenus.size(); i++) {
if (StringUtils.isBlank(rootMenus.get(i).getParentId()) || "0".equals(rootMenus.get(i).getParentId())) {// 一级菜单没有parentId (或是等于0,看怎么数据库怎么设置)
menuList.add(rootMenus.get(i));
}
}
/**
* 一级菜单之后,开始递归子菜单
*/
for (Menu menu : menuList) {
menu.setChildMenus(getChild(menu.getId(), rootMenus));
}
Map<String,Object> jsonMap = new HashMap<>();
jsonMap.put("menu", menuList);
System.out.println(new Gson().toJson(jsonMap));//json 字符串 前端遍历
}
}
3、前端递归解析json 数据。
$(function () {
var showlist = $("<ul></ul>");
showall(menulist.menulist, showlist);
$("#div_menu").append(showlist);
});
/**
* parent为要组合成html的容器
* menu_list为后台json数据
*/
function showall(menu_list, parent) {
for (var menu in menu_list) {
//如果有子节点,则遍历该子节点
if (menu_list[menu].menulist.length > 0) {
//创建一个子节点li
var li = $("<li></li>");
//将li的文本设置好,并马上添加一个空白的ul子节点,并且将这个li添加到父亲节点中
$(li).append(menu_list[menu].MName).append("<ul></ul>").appendTo(parent);
//将空白的ul作为下一个递归遍历的父亲节点传入
showall(menu_list[menu].menulist, $(li).children().eq(0));
}
//如果该节点没有子节点,则直接将该节点li以及文本创建好直接添加到父亲节点中
else {
$("<li></li>").append(menu_list[menu].MName).appendTo(parent);
}
}
}