java 从数据库读取菜单,递归生成菜单树

本贴最后更新于 2774 天前,其中的信息可能已经渤澥桑田

首先看一下菜单的样子

根据这个样子我们定义菜单类

public class Menu { // 菜单id private String id; // 菜单名称 private String name; // 父菜单id private String parentId; // 菜单url private String url; // 菜单图标 private String icon; // 菜单顺序 private int order; // 子菜单 private List<Menu> childMenus; // ... 省去getter和setter方法以及toString方法 }

我们根据这个类定义数据库,并插入菜单数据

DROP TABLE IF EXISTS `jrbac_menu`; CREATE TABLE `jrbac_menu` ( `id` varchar(32) NOT NULL COMMENT '主键id,uuid32位', `name` varchar(64) NOT NULL COMMENT '登录用户名', `parent_id` varchar(32) DEFAULT NULL COMMENT '父菜单id', `url` varchar(64) DEFAULT NULL COMMENT '访问地址', `icon` varchar(32) DEFAULT NULL COMMENT '菜单图标', `order` tinyint(4) DEFAULT '0' COMMENT '菜单顺序', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='菜单表'; -- ---------------------------- -- Records of jrbac_menu -- ---------------------------- INSERT INTO `jrbac_menu` VALUES ('1', 'Forms', null, 'forms.html', 'fa fa-edit', '0'); INSERT INTO `jrbac_menu` VALUES ('2', 'UI Elements', null, '', 'fa fa-wrench', '1'); INSERT INTO `jrbac_menu` VALUES ('3', 'Buttons', '2', 'buttons.html', '', '0'); INSERT INTO `jrbac_menu` VALUES ('4', 'Icons', '2', 'icons.html', null, '1'); INSERT INTO `jrbac_menu` VALUES ('5', 'Multi-Level Dropdown', '', '', 'fa fa-sitemap', '2'); INSERT INTO `jrbac_menu` VALUES ('6', 'Second Level Item', '5', 'second.html', null, '0'); INSERT INTO `jrbac_menu` VALUES ('7', 'Third Level', '5', null, '', '1'); INSERT INTO `jrbac_menu` VALUES ('8', 'Third Level Item', '7', 'third.html', null, '0');

为了演示,我们把可展开的没有做完,仅仅插入几条数据能出效果就可以了。

测试方法与递归方法

private final Gson gson = new GsonBuilder().disableHtmlEscaping().create(); @Test public void testQueryMenuList() { // 原始的数据 List<Menu> rootMenu = menuDao.queryMenuList(null); // 查看结果 for (Menu menu : rootMenu) { System.out.println(menu); } // 最后的结果 List<Menu> menuList = new ArrayList<Menu>(); // 先找到所有的一级菜单 for (int i = 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 = new HashMap<>(); jsonMap.put("menu", menuList); System.out.println(gson.toJson(jsonMap)); } /** * 递归查找子菜单 * * @param id * 当前菜单id * @param rootMenu * 要查找的列表 * @return */ private List<Menu> getChild(String id, List<Menu> rootMenu) { // 子菜单 List<Menu> childList = new ArrayList<>(); 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) { return null; } return childList; }

menuDao.queryMenuList(null);查找的结果是一条一条的数据

meuDao

package com.jrbac.dao; import java.util.List; import com.jrbac.entity.LoginUser; import com.jrbac.entity.Menu; public interface MenuDao { /** * 查找用户的菜单 * @param loginUser * @return */ public List<Menu> queryMenuList(LoginUser loginUser); }

mybatis

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//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>

测试程序的运行结果,对输出的 json 进行个格式化后的对比

最终效果

如果你也使用 sbadmin 后台模版的话,它只做到了二级菜单,三级的没有做展开控制。

要做到三级将 sb-admin-2.js 的最后一个替换成下面的。

if (element.is('li')) { element.addClass('active'); element.parent().addClass('in'); }

再奉上前端 jsp 页面输出菜单的代码

<c:forEach items="${userMenuList }" var="menu" varStatus="status"> <!-- 一级子菜单没有parentId,有url --> <c:if test="${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:if test="${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:if test="${not empty secondChild.url }"> <li> <a href="<c:url value='${secondChild.url }'/>">${secondChild.name }</a> </li> </c:if> <!-- 二级菜单url为空,表示还有三级菜单 --> <c:if test="${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> 转载自:http://blog.csdn.net/frankcheng5143/article/details/52958486
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3203 引用 • 8217 回帖 • 1 关注
  • 递归
    15 引用 • 9 回帖
  • 菜单
    3 引用 • 5 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • someone

    😄

  • leap

    我也做了个类似的。不过前端是 vue。哈哈😂

  • someone

    😄 😄 😄

推荐标签 标签

  • IPFS

    IPFS(InterPlanetary File System,星际文件系统)是永久的、去中心化保存和共享文件的方法,这是一种内容可寻址、版本化、点对点超媒体的分布式协议。请浏览 IPFS 入门笔记了解更多细节。

    20 引用 • 245 回帖 • 237 关注
  • 黑曜石

    黑曜石是一款强大的知识库工具,支持本地 Markdown 文件编辑,支持双向链接和关系图。

    A second brain, for you, forever.

    26 引用 • 264 回帖 • 1 关注
  • 区块链

    区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。所谓共识机制是区块链系统中实现不同节点之间建立信任、获取权益的数学算法 。

    92 引用 • 752 回帖
  • CSDN

    CSDN (Chinese Software Developer Network) 创立于 1999 年,是中国的 IT 社区和服务平台,为中国的软件开发者和 IT 从业者提供知识传播、职业发展、软件开发等全生命周期服务,满足他们在职业发展中学习及共享知识和信息、建立职业发展社交圈、通过软件开发实现技术商业化等刚性需求。

    14 引用 • 155 回帖 • 1 关注
  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖 • 1 关注
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    337 引用 • 324 回帖
  • flomo

    flomo 是新一代 「卡片笔记」 ,专注在碎片化时代,促进你的记录,帮你积累更多知识资产。

    6 引用 • 143 回帖 • 1 关注
  • H2

    H2 是一个开源的嵌入式数据库引擎,采用 Java 语言编写,不受平台的限制,同时 H2 提供了一个十分方便的 web 控制台用于操作和管理数据库内容。H2 还提供兼容模式,可以兼容一些主流的数据库,因此采用 H2 作为开发期的数据库非常方便。

    11 引用 • 54 回帖 • 673 关注
  • danl
    185 关注
  • PHP

    PHP(Hypertext Preprocessor)是一种开源脚本语言。语法吸收了 C 语言、 Java 和 Perl 的特点,主要适用于 Web 开发领域,据说是世界上最好的编程语言。

    167 引用 • 408 回帖 • 482 关注
  • C

    C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

    86 引用 • 165 回帖 • 1 关注
  • Follow
    4 引用 • 12 回帖 • 10 关注
  • V2EX

    V2EX 是创意工作者们的社区。这里目前汇聚了超过 400,000 名主要来自互联网行业、游戏行业和媒体行业的创意工作者。V2EX 希望能够成为创意工作者们的生活和事业的一部分。

    16 引用 • 236 回帖 • 236 关注
  • 宕机

    宕机,多指一些网站、游戏、网络应用等服务器一种区别于正常运行的状态,也叫“Down 机”、“当机”或“死机”。宕机状态不仅仅是指服务器“挂掉了”、“死机了”状态,也包括服务器假死、停用、关闭等一些原因而导致出现的不能够正常运行的状态。

    13 引用 • 82 回帖 • 73 关注
  • 程序员

    程序员是从事程序开发、程序维护的专业人员。

    593 引用 • 3533 回帖
  • OnlyOffice
    4 引用 • 18 关注
  • Scala

    Scala 是一门多范式的编程语言,集成面向对象编程和函数式编程的各种特性。

    13 引用 • 11 回帖 • 160 关注
  • 一些有用的避坑指南。

    69 引用 • 93 回帖 • 1 关注
  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 91 关注
  • 安全

    安全永远都不是一个小问题。

    199 引用 • 818 回帖
  • Wide

    Wide 是一款基于 Web 的 Go 语言 IDE。通过浏览器就可以进行 Go 开发,并有代码自动完成、查看表达式、编译反馈、Lint、实时结果输出等功能。

    欢迎访问我们运维的实例: https://wide.b3log.org

    30 引用 • 218 回帖 • 642 关注
  • 职场

    找到自己的位置,萌新烦恼少。

    127 引用 • 1708 回帖
  • FlowUs

    FlowUs.息流 个人及团队的新一代生产力工具。

    让复杂的信息管理更轻松、自由、充满创意。

    1 引用 • 4 关注
  • abitmean

    有点意思就行了

    32 关注
  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    89 引用 • 113 回帖 • 1 关注
  • BND

    BND(Baidu Netdisk Downloader)是一款图形界面的百度网盘不限速下载器,支持 Windows、Linux 和 Mac,详细介绍请看这里

    107 引用 • 1281 回帖 • 40 关注
  • CentOS

    CentOS(Community Enterprise Operating System)是 Linux 发行版之一,它是来自于 Red Hat Enterprise Linux 依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定的服务器以 CentOS 替代商业版的 Red Hat Enterprise Linux 使用。两者的不同在于 CentOS 并不包含封闭源代码软件。

    240 引用 • 224 回帖