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

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 '' COMMENT '菜单顺序',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='菜单表'; -- ----------------------------
-- Records of jrbac_menu
-- ----------------------------
INSERT INTO `jrbac_menu` VALUES ('', 'Forms', null, 'forms.html', 'fa fa-edit', '');
INSERT INTO `jrbac_menu` VALUES ('', 'UI Elements', null, '', 'fa fa-wrench', '');
INSERT INTO `jrbac_menu` VALUES ('', 'Buttons', '', 'buttons.html', '', '');
INSERT INTO `jrbac_menu` VALUES ('', 'Icons', '', 'icons.html', null, '');
INSERT INTO `jrbac_menu` VALUES ('', 'Multi-Level Dropdown', '', '', 'fa fa-sitemap', '');
INSERT INTO `jrbac_menu` VALUES ('', 'Second Level Item', '', 'second.html', null, '');
INSERT INTO `jrbac_menu` VALUES ('', 'Third Level', '', null, '', '');
INSERT INTO `jrbac_menu` VALUES ('', 'Third Level Item', '', 'third.html', null, '');

第二步:引入相应pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.payease</groupId>
<artifactId>sell</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging> <name>sell</name>
<description>Demo project for Spring Boot</description> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency> <!-- ===================== mysql驱动 ======================== -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- ===================== jpa ======================== -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency> <!-- ===================== @Getter @Setter @Slf4j @Data ======================== -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency> <!-- ===================== google: gson ======================== -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.36</version>
</dependency> <!-- https://mvnrepository.com/artifact/com.github.binarywang/weixin-java-mp -->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>2.7.0</version>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency> <dependency>
<groupId>cn.springboot</groupId>
<artifactId>best-pay-sdk</artifactId>
<version>1.1.0</version>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

第三步:相应数据库的实体类(把数据库的那张表jrbac_menu 改为 menu)

package com.payease.dataobject;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.Id; /**
* 菜单循环递归类
* @Created By liuxiaoming
* @CreateTime 2017/12/7 下午12:46
**/
@Entity
@Data
public class Menu {
// 菜单id
@Id
private String id;
// 菜单名称
private String name;
// 父菜单id
private String parentId;
// 菜单url
private String url;
// 菜单图标
private String icon;
// 菜单顺序
private int order; // ... 省去getter和setter方法以及toString方法
}

第四步:树形数据实体接口

package com.payease.utils;

import java.util.List;

/**
* 树形数据实体接口
* @param <E>
* @Created By liuxiaoming
* @CreateTime 2017/12/7 下午3:39
**/
public interface TreeEntity<E> {
// 菜单id
public String getId();
// 菜单名称
public String getName();
// 父菜单id
public String getParentId();
// 菜单url
public String getUrl();
// 菜单图标
public String getIcon();
// 菜单顺序
public int getOrder(); public void setChildList(List<E> childList); }

第五步:封装类menuVO

package com.payease.VO;

import com.payease.utils.TreeEntity;
import lombok.Data; import java.util.List; /**
* @Created By liuxiaoming
* @CreateTime 2017/12/7 下午12:58
**/
@Data
public class MenuVO implements TreeEntity<MenuVO> {
// 菜单id
public String id;
// 菜单名称
public String name;
// 父菜单id
public String parentId;
// 菜单url
public String url;
// 菜单图标
public String icon;
// 菜单顺序
public int order;
// 子菜单
public List<MenuVO> childList; }

第六步:编写 解析树形数据工具类

package com.payease.utils;

import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List; /**
* 解析树形数据工具类
* @Created By liuxiaoming
* @CreateTime 2017/12/7 下午3:41
**/
public class TreeParser{
/**
* 解析树形数据
* @param topId
* @param entityList
* @return
* @Created By liuxiaoming
* @CreateTime 2017/12/7 下午3:41
*/
public static <E extends TreeEntity<E>> List<E> getTreeList(String topId, List<E> entityList) {
List<E> resultList=new ArrayList<>(); //获取顶层元素集合
String parentId;
if(StringUtils.isBlank(topId)){
//全查
for (E entity : entityList) {
parentId=entity.getParentId();
if(StringUtils.isBlank(parentId))
resultList.add(entity);
}
}else{
//根据传入的ID进行向下递归
for (E entity : entityList) {
parentId=entity.getParentId();
if(parentId!=null && topId.equals(parentId)){
resultList.add(entity);
}
}
} //获取每个顶层元素的子数据集合
for (E entity : resultList) {
entity.setChildList(getSubList(entity.getId(),entityList));
} return resultList;
} /**
* 获取子数据集合
* @param id
* @param entityList
* @return
* @Created By liuxiaoming
* @CreateTime 2017/12/7 下午3:41
*/
private static <E extends TreeEntity<E>> List<E> getSubList(String id, List<E> entityList) {
List<E> childList=new ArrayList<>();
String parentId; //子集的直接子对象
for (E entity : entityList) {
parentId=entity.getParentId();
if(id.equals(parentId)){
childList.add(entity);
}else{ }
} //子集的间接子对象
for (E entity : childList) {
entity.setChildList(getSubList(entity.getId(), entityList));
} //递归退出条件
if(childList.size()==0){
return null;
} return childList;
} }

第七步:编写对应的dao层

package com.payease.repository;

import com.payease.dataobject.Menu;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository; import java.util.List; /**
* Created by liuxiaoming on 2017/11/13.
*/
@Repository
public interface MenuRepository extends JpaRepository<Menu, String> { List<Menu> findById(String orderId);
}

第八步:编写测试类

package com.payease.repository;

import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import com.payease.VO.MenuVO;
import com.payease.dataobject.Menu;
import com.payease.utils.TreeParser;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import java.util.ArrayList;
import java.util.List; /**
* @Created By liuxiaoming
* @CreateTime 2017/12/7 下午12:51
**/
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class MenuRepositoryTest { @Autowired
private MenuRepository repository;
@Test
public void findById() throws Exception {
// 原始的数据
List<Menu> rootMenu = repository.findAll();
// 查看结果
List<MenuVO> rootMenuVO = new ArrayList<>();
for (Menu menu : rootMenu) {
MenuVO menuVO = new MenuVO();
BeanUtils.copyProperties(menu,menuVO);
rootMenuVO.add(menuVO);
// System.out.println("rootMenu:" + menuVO.toString());
} List<MenuVO> child = TreeParser.getTreeList("2",rootMenuVO); List<MenuVO> menus = TreeParser.getTreeList("2",rootMenuVO);
System.out.println(menus); Gson gson = new Gson();
String gJson = gson.toJson(menus);
System.out.println("gjson:"+gJson); String fastJson = JSON.toJSONString(child); System.out.println("fastJson:"+fastJson); } }

菜单根据菜单ID向下递归的更多相关文章

  1. PHP递归获得树形菜单和遍历文件夹下的所有文件以及子文件夹

    PHP递归获得树形菜单和遍历文件夹下的所有文件以及子文件夹 一.使用递归获取树形菜单 数据表category(id,name,parent_id) <?php class category{ / ...

  2. #AOS应用基础平台# 添加了用户自己定义快捷菜单在平铺布局下的用户自己定义排序管理

    #AOS开发平台# 添加了用户自己定义快捷菜单在平铺布局下的用户自己定义排序管理.

  3. jq自定义下拉菜单,在点击非当前下拉菜单区域时,关闭下拉菜单(点击事件的对象不是目标元素本身)

    jq自定义下拉菜单,在点击非当前下拉菜单区域时,关闭下拉菜单(点击事件的对象不是目标元素本身) //点击非当前下拉菜单区域时,关闭下拉菜单 $(document).mousedown(function ...

  4. jq自定义下拉菜单,当用户点击非自身元素(下拉菜单)本身时关闭下拉菜单

    jq自定义下拉菜单,当用户点击非自身元素(下拉菜单)本身时关闭下拉菜单 截图: 代码如下: //关闭用户菜单 $(document).mousedown(function(e){ var _con = ...

  5. 自定义右键菜单,禁用浏览器自带的右键菜单[右键菜单实现--Demo]

    许多从事Web开发的会发现有些事,我们需要禁用浏览器本事自带的右键菜单,而实现自定义的右键菜单下面我们也来实现一个自定义的右键菜单 首先来创建JSP页面 <%@ page language=&q ...

  6. 微信公众号开发C#系列-8、自定义菜单及菜单响应事件的处理

    1.概述 自定义菜单能够帮助公众号丰富界面,让用户更好更快地理解公众号的功能.菜单分为默认菜单与个性化菜单.个性化菜单接口是为了帮助公众号实现灵活的业务运营,开发者可以通过该接口,让公众号的不同用户群 ...

  7. VS2010/MFC编程入门之三十五(菜单:菜单及CMenu类的使用)

    鸡啄米在上一节中讲的是VS2010的菜单资源,本节主要讲菜单及CMenu类的使用. CMenu类的主要成员函数 MFC为菜单的操作提供了CMenu类,下面鸡啄米就常用的几个成员函数进行简单的介绍. B ...

  8. Android_(菜单)选项菜单

    Android系统中菜单分为Options Menu.Context Menu.Sub Men三种 Options Menu和Context Menu属于一级菜单 Sub Menu属于Options ...

  9. VS2010-MFC(菜单:菜单及CMenu类的使用)

    转自:http://www.jizhuomi.com/software/212.html 上一节讲的是VS2010的菜单资源,本节主要讲菜单及CMenu类的使用. CMenu类的主要成员函数 MFC为 ...

随机推荐

  1. 20155335俞昆《java程序设计》第6周总结

    20155335    <Java程序设计>第6周学习总结 ##  教材学习内容总结 首先,我们需要了解输入和输出的关系,我想,这不同于c语言中的输入和输出,我们首先明白,Java中以串流 ...

  2. delphi跨平台SOCKET--System.Net.Socket

    delphi跨平台SOCKET--System.Net.Socket 不知始于DELPHI哪一个版本,姑且始于柏林版吧. 基于此单元的TSocket类,大家可以很方便地封装出自己的服务端和客户端的SO ...

  3. Head First iOS Programming

    内部分享: Head First iOS Programming http://www.slideshare.net/tedzhaoxa/head-first-ios-programming-4606 ...

  4. PG数据库错误: 检测到OA幸运飞艇源码ShareLock死锁处理

    PostgreSQL 是一个免费数据库,OA幸运飞艇源码下载,详情咨询[企娥166848365]对于处理分析型+交易型混合型系统来说确实很不错,特别是版本的升级到11.2后性能提升很多,很多运行机制跟 ...

  5. [Elixir005] 查看指定数据的详细信息 i helper

    elixir在1.2后增加了一个新的特性i helper. 在iex shell中使用i可以查看任意数据的数据类型和详细描述 #查看变量描述 iex(1)> i {:test, "Th ...

  6. WP8.1StoreApp(WP8.1RT)---发送邮件和短信

    在WP7/8中,发送短信是利用了EmailComposeTask和SmsComposeTask来实现的. 在WP8.1 Store App中,原来的方式已经失效,采用了新的方法:ChatMessage ...

  7. 在VC++中执行VBS代码

    此代码来自https://blog.csdn.net/zhu2695/article/details/13770671 作者: zhu2695   时间:2013年10月31日 13:08:41 #i ...

  8. C#中实现对象的深拷贝

    深度拷贝指的是将一个引用类型(包含该类型里的引用类型)拷贝一份(在内存中完完全全是两个对象,没有任何引用关系).......... 直接上代码: /// <summary> /// 对象的 ...

  9. 使用sn.exe为程序集签名

    前言 在写上一篇随笔时,为理解EF事务底层的原理,我去Github上把EF的源码下载放到自己项目调试,不过在编译时遇到了下面这个报错信息.经过一番查阅,了解到了程序集签名(也称强名称签名)的概念.报错 ...

  10. mysql--对行(表中数据)的增删改查

    一.插入数据(增加)insert 1.插入数据(顺序插入) 语法一: INSERT INTO 表名(字段1,字段2,字段3…字段n) VALUES(值1,值2,值3…值n); #指定字段来插入数据,插 ...