本文介绍两种不同生成多级目录树的方式:1. 递归生成,2.  map+list 集合生成。最下方会附上完整代码。

生成树的基本规则:子节点的par_id等于父节点的id。

1. 实体类

import java.util.ArrayList;

public class Menu {

  private int id;
private String menuName;//名称
private int parId;//上级ID
private int type;//0:目录;1:菜单
private String url;
public ArrayList<Menu> children; public Menu() {
super();
this.children = new ArrayList<>();
} private Menu(Builder builder) {
setId(builder.id);
setMenuName(builder.menuName);
setParId(builder.parId);
setType(builder.type);
setUrl(builder.url);
setChildren(builder.children);
} public void addChildren(Menu menu) { this.children.add(menu);
} public ArrayList<Menu> getChildren() {
return children;
} public void setChildren(ArrayList<Menu> children) {
if (children==null){//防止添加子节点出现空引用
children=new ArrayList<>();
}
this.children = children;
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getMenuName() {
return menuName;
} public void setMenuName(String menuName) {
this.menuName = menuName;
} public int getParId() {
return parId;
} public void setParId(int parId) {
this.parId = parId;
} public int getType() {
return type;
} public void setType(int type) {
this.type = type;
} public String getUrl() {
return url;
} public void setUrl(String url) {
this.url = url;
} @Override
public String toString() {
return "Menu{" +
"id=" + id +
", menuName='" + menuName + '\'' +
", parId=" + parId +
", type=" + type +
", url='" + url + '\'' +
", children=" + children +
'}';
} public static final class Builder {
private int id;
private String menuName;
private int parId;
private int type;
private String url;
private ArrayList<Menu> children; public Builder() {
} public Builder id(int id) {
this.id = id;
return this;
} public Builder menuName(String menuName) {
this.menuName = menuName;
return this;
} public Builder parId(int parId) {
this.parId = parId;
return this;
} public Builder type(int type) {
this.type = type;
return this;
} public Builder url(String url) {
this.url = url;
return this;
} public Builder children(ArrayList<Menu> children) {
this.children = children;
return this;
} public Menu build() {
return new Menu(this);
}
}
}

注意使用build()插入数据时setChildren注意要判空处理,不然添加子节点时出现空引用

public void setChildren(ArrayList<Menu> children) {
    if (children==null){//防止添加子节点出现空引用
      children=new ArrayList<>();
    }
    this.children = children;
  }

2. 创建测试数据

public static void main(String[] args) {
createData();
dataList.forEach(e-> System.out.println(e.toString())); }
//保存数据
public static List<Menu> dataList=new ArrayList();
//创建数据
public static void createData(){
dataList.add(new Menu.Builder().id(0).menuName("根节点").parId(-2).type(0).url("").build());
for (int i = 1; i <50 ; i++) {
if (i<11) {
dataList.add(new Menu.Builder().id(i).menuName("1级节点"+i).parId(0).type(0).url("").build());
}else {
dataList.add(new Menu.Builder().id(i).menuName(((i/10)+1)+"级节点"+i).parId(i-10).type(0).url("").build());
}
}
}

生成如下数据:

Menu{id=0, menuName='根节点', parId=-2, type=0, url='', children=[]}
Menu{id=1, menuName='1级节点1', parId=0, type=0, url='', children=[]}
Menu{id=2, menuName='1级节点2', parId=0, type=0, url='', children=[]}
Menu{id=3, menuName='1级节点3', parId=0, type=0, url='', children=[]}
Menu{id=4, menuName='1级节点4', parId=0, type=0, url='', children=[]}
Menu{id=5, menuName='1级节点5', parId=0, type=0, url='', children=[]}
Menu{id=6, menuName='1级节点6', parId=0, type=0, url='', children=[]}
Menu{id=7, menuName='1级节点7', parId=0, type=0, url='', children=[]}
Menu{id=8, menuName='1级节点8', parId=0, type=0, url='', children=[]}
Menu{id=9, menuName='1级节点9', parId=0, type=0, url='', children=[]}
Menu{id=10, menuName='1级节点10', parId=0, type=0, url='', children=[]}
Menu{id=11, menuName='2级节点11', parId=1, type=0, url='', children=[]}
Menu{id=12, menuName='2级节点12', parId=2, type=0, url='', children=[]}
Menu{id=13, menuName='2级节点13', parId=3, type=0, url='', children=[]}
Menu{id=14, menuName='2级节点14', parId=4, type=0, url='', children=[]}
Menu{id=15, menuName='2级节点15', parId=5, type=0, url='', children=[]}
Menu{id=16, menuName='2级节点16', parId=6, type=0, url='', children=[]}
Menu{id=17, menuName='2级节点17', parId=7, type=0, url='', children=[]}
Menu{id=18, menuName='2级节点18', parId=8, type=0, url='', children=[]}
Menu{id=19, menuName='2级节点19', parId=9, type=0, url='', children=[]}
Menu{id=20, menuName='3级节点20', parId=10, type=0, url='', children=[]}
Menu{id=21, menuName='3级节点21', parId=11, type=0, url='', children=[]}
Menu{id=22, menuName='3级节点22', parId=12, type=0, url='', children=[]}
Menu{id=23, menuName='3级节点23', parId=13, type=0, url='', children=[]}
Menu{id=24, menuName='3级节点24', parId=14, type=0, url='', children=[]}
Menu{id=25, menuName='3级节点25', parId=15, type=0, url='', children=[]}
Menu{id=26, menuName='3级节点26', parId=16, type=0, url='', children=[]}
Menu{id=27, menuName='3级节点27', parId=17, type=0, url='', children=[]}
Menu{id=28, menuName='3级节点28', parId=18, type=0, url='', children=[]}
Menu{id=29, menuName='3级节点29', parId=19, type=0, url='', children=[]}
Menu{id=30, menuName='4级节点30', parId=20, type=0, url='', children=[]}
Menu{id=31, menuName='4级节点31', parId=21, type=0, url='', children=[]}
Menu{id=32, menuName='4级节点32', parId=22, type=0, url='', children=[]}
Menu{id=33, menuName='4级节点33', parId=23, type=0, url='', children=[]}
Menu{id=34, menuName='4级节点34', parId=24, type=0, url='', children=[]}
Menu{id=35, menuName='4级节点35', parId=25, type=0, url='', children=[]}
Menu{id=36, menuName='4级节点36', parId=26, type=0, url='', children=[]}
Menu{id=37, menuName='4级节点37', parId=27, type=0, url='', children=[]}
Menu{id=38, menuName='4级节点38', parId=28, type=0, url='', children=[]}
Menu{id=39, menuName='4级节点39', parId=29, type=0, url='', children=[]}
Menu{id=40, menuName='5级节点40', parId=30, type=0, url='', children=[]}
Menu{id=41, menuName='5级节点41', parId=31, type=0, url='', children=[]}
Menu{id=42, menuName='5级节点42', parId=32, type=0, url='', children=[]}
Menu{id=43, menuName='5级节点43', parId=33, type=0, url='', children=[]}
Menu{id=44, menuName='5级节点44', parId=34, type=0, url='', children=[]}
Menu{id=45, menuName='5级节点45', parId=35, type=0, url='', children=[]}
Menu{id=46, menuName='5级节点46', parId=36, type=0, url='', children=[]}
Menu{id=47, menuName='5级节点47', parId=37, type=0, url='', children=[]}
Menu{id=48, menuName='5级节点48', parId=38, type=0, url='', children=[]}
Menu{id=49, menuName='5级节点49', parId=39, type=0, url='', children=[]}

3. 生成树(集合方式)

public static Map<String, Object> getTreeByColl(List<Menu> list) {
Map<String, Object> resmap=new HashMap<>();
Map<Integer, Menu> map;
List<Menu> treelist= new ArrayList<>(); if (null==list||list.isEmpty()){
return null;
}
map = list.stream().collect(Collectors.toMap(Menu::getId, a -> a,(k1, k2)->k1));
// 将list集合对象转换为json的字符串
// 如果id是父级的话就放入tree中treelist
for (Menu menu : list) {
if (null==map.get(menu.getParId())) {
treelist.add(menu);
} else {
// 子级通过父id获取到父级的类型
Menu parent = map.get(menu.getParId());
// 父级获得子级,再将子级放到对应的父级中
parent.addChildren(menu);
}
}
resmap.put("data",treelist);
return resmap;
}

打印json如下:打印json时可以通过@JSONField(ordinal=1) 在实体类属性设置顺序

{
"data": [
{
"id": 0,
"menuName": "根节点",
"parId": -2,
"type": 0,
"url": "",
"children": [
{
"id": 1,
"menuName": "1级节点1",
"parId": 0,
"type": 0,
"url": "",
"children": [
{
"id": 11,
"menuName": "2级节点11",
"parId": 1,
"type": 0,
"url": "",
"children": [
{
"id": 21,
"menuName": "3级节点21",
"parId": 11,
"type": 0,
"url": "",
"children": [
{
"id": 31,
"menuName": "4级节点31",
"parId": 21,
"type": 0,
"url": "",
"children": [
{
"id": 41,
"menuName": "5级节点41",
"parId": 31,
"type": 0,
"url": "",
"children": [ ]
}
]
}
]
}
]
}
]
},
{
"id": 2,
"menuName": "1级节点2",
"parId": 0,
"type": 0,
"url": "",
"children": [
{
"id": 12,
"menuName": "2级节点12",
"parId": 2,
"type": 0,
"url": "",
"children": [
{
"id": 22,
"menuName": "3级节点22",
"parId": 12,
"type": 0,
"url": "",
"children": [
{
"id": 32,
"menuName": "4级节点32",
"parId": 22,
"type": 0,
"url": "",
"children": [
{
"id": 42,
"menuName": "5级节点42",
"parId": 32,
"type": 0,
"url": "",
"children": [ ]
}
]
}
]
}
]
}
]
},
{
"id": 3,
"menuName": "1级节点3",
"parId": 0,
"type": 0,
"url": "",
"children": [
{
"id": 13,
"menuName": "2级节点13",
"parId": 3,
"type": 0,
"url": "",
"children": [
{
"id": 23,
"menuName": "3级节点23",
"parId": 13,
"type": 0,
"url": "",
"children": [
{
"id": 33,
"menuName": "4级节点33",
"parId": 23,
"type": 0,
"url": "",
"children": [
{
"id": 43,
"menuName": "5级节点43",
"parId": 33,
"type": 0,
"url": "",
"children": [ ]
}
]
}
]
}
]
}
]
},
{
"id": 4,
"menuName": "1级节点4",
"parId": 0,
"type": 0,
"url": "",
"children": [
{
"id": 14,
"menuName": "2级节点14",
"parId": 4,
"type": 0,
"url": "",
"children": [
{
"id": 24,
"menuName": "3级节点24",
"parId": 14,
"type": 0,
"url": "",
"children": [
{
"id": 34,
"menuName": "4级节点34",
"parId": 24,
"type": 0,
"url": "",
"children": [
{
"id": 44,
"menuName": "5级节点44",
"parId": 34,
"type": 0,
"url": "",
"children": [ ]
}
]
}
]
}
]
}
]
},
{
"id": 5,
"menuName": "1级节点5",
"parId": 0,
"type": 0,
"url": "",
"children": [
{
"id": 15,
"menuName": "2级节点15",
"parId": 5,
"type": 0,
"url": "",
"children": [
{
"id": 25,
"menuName": "3级节点25",
"parId": 15,
"type": 0,
"url": "",
"children": [
{
"id": 35,
"menuName": "4级节点35",
"parId": 25,
"type": 0,
"url": "",
"children": [
{
"id": 45,
"menuName": "5级节点45",
"parId": 35,
"type": 0,
"url": "",
"children": [ ]
}
]
}
]
}
]
}
]
},
{
"id": 6,
"menuName": "1级节点6",
"parId": 0,
"type": 0,
"url": "",
"children": [
{
"id": 16,
"menuName": "2级节点16",
"parId": 6,
"type": 0,
"url": "",
"children": [
{
"id": 26,
"menuName": "3级节点26",
"parId": 16,
"type": 0,
"url": "",
"children": [
{
"id": 36,
"menuName": "4级节点36",
"parId": 26,
"type": 0,
"url": "",
"children": [
{
"id": 46,
"menuName": "5级节点46",
"parId": 36,
"type": 0,
"url": "",
"children": [ ]
}
]
}
]
}
]
}
]
},
{
"id": 7,
"menuName": "1级节点7",
"parId": 0,
"type": 0,
"url": "",
"children": [
{
"id": 17,
"menuName": "2级节点17",
"parId": 7,
"type": 0,
"url": "",
"children": [
{
"id": 27,
"menuName": "3级节点27",
"parId": 17,
"type": 0,
"url": "",
"children": [
{
"id": 37,
"menuName": "4级节点37",
"parId": 27,
"type": 0,
"url": "",
"children": [
{
"id": 47,
"menuName": "5级节点47",
"parId": 37,
"type": 0,
"url": "",
"children": [ ]
}
]
}
]
}
]
}
]
},
{
"id": 8,
"menuName": "1级节点8",
"parId": 0,
"type": 0,
"url": "",
"children": [
{
"id": 18,
"menuName": "2级节点18",
"parId": 8,
"type": 0,
"url": "",
"children": [
{
"id": 28,
"menuName": "3级节点28",
"parId": 18,
"type": 0,
"url": "",
"children": [
{
"id": 38,
"menuName": "4级节点38",
"parId": 28,
"type": 0,
"url": "",
"children": [
{
"id": 48,
"menuName": "5级节点48",
"parId": 38,
"type": 0,
"url": "",
"children": [ ]
}
]
}
]
}
]
}
]
},
{
"id": 9,
"menuName": "1级节点9",
"parId": 0,
"type": 0,
"url": "",
"children": [
{
"id": 19,
"menuName": "2级节点19",
"parId": 9,
"type": 0,
"url": "",
"children": [
{
"id": 29,
"menuName": "3级节点29",
"parId": 19,
"type": 0,
"url": "",
"children": [
{
"id": 39,
"menuName": "4级节点39",
"parId": 29,
"type": 0,
"url": "",
"children": [
{
"id": 49,
"menuName": "5级节点49",
"parId": 39,
"type": 0,
"url": "",
"children": [ ]
}
]
}
]
}
]
}
]
},
{
"id": 10,
"menuName": "1级节点10",
"parId": 0,
"type": 0,
"url": "",
"children": [
{
"id": 20,
"menuName": "3级节点20",
"parId": 10,
"type": 0,
"url": "",
"children": [
{
"id": 30,
"menuName": "4级节点30",
"parId": 20,
"type": 0,
"url": "",
"children": [
{
"id": 40,
"menuName": "5级节点40",
"parId": 30,
"type": 0,
"url": "",
"children": [ ]
}
]
}
]
}
]
}
]
}
]
}

4. 生成树(递归方式)

待续。。。。。

/*********************************************************************************************************************/

最后完整代码如下:

实体类:

import com.alibaba.fastjson.annotation.JSONField;

import java.util.ArrayList;

public class Menu {
@JSONField(ordinal=1)
private int id;
@JSONField(ordinal=2)
private String menuName;//名称
@JSONField(ordinal=3)
private int parId;//上级ID
@JSONField(ordinal=4)
private int type;//0:目录;1:菜单
@JSONField(ordinal=5)
private String url;
@JSONField(ordinal=6)
public ArrayList<Menu> children; public Menu() {
super();
this.children = new ArrayList<>();
} private Menu(Builder builder) {
setId(builder.id);
setMenuName(builder.menuName);
setParId(builder.parId);
setType(builder.type);
setUrl(builder.url);
setChildren(builder.children);
} public void addChildren(Menu menu) { this.children.add(menu);
} public ArrayList<Menu> getChildren() {
return children;
} public void setChildren(ArrayList<Menu> children) {
if (children==null){
children=new ArrayList<>();
}
this.children = children;
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getMenuName() {
return menuName;
} public void setMenuName(String menuName) {
this.menuName = menuName;
} public int getParId() {
return parId;
} public void setParId(int parId) {
this.parId = parId;
} public int getType() {
return type;
} public void setType(int type) {
this.type = type;
} public String getUrl() {
return url;
} public void setUrl(String url) {
this.url = url;
} @Override
public String toString() {
return "Menu{" +
"id=" + id +
", menuName='" + menuName + '\'' +
", parId=" + parId +
", type=" + type +
", url='" + url + '\'' +
", children=" + children +
'}';
} public static final class Builder {
private int id;
private String menuName;
private int parId;
private int type;
private String url;
private ArrayList<Menu> children; public Builder() {
} public Builder id(int id) {
this.id = id;
return this;
} public Builder menuName(String menuName) {
this.menuName = menuName;
return this;
} public Builder parId(int parId) {
this.parId = parId;
return this;
} public Builder type(int type) {
this.type = type;
return this;
} public Builder url(String url) {
this.url = url;
return this;
} public Builder children(ArrayList<Menu> children) {
this.children = children;
return this;
} public Menu build() {
return new Menu(this);
}
}
}

树生成类:

import com.alibaba.fastjson.JSONObject;

import java.util.*;
import java.util.stream.Collectors; public class TreeUtil {
public static void main(String[] args) {
createData();
//dataList.forEach(e-> System.out.println(e.toString()));
System.out.println(JSONObject.toJSONString(getTreeByColl(dataList)));
}
//保存数据
public static List<Menu> dataList=new ArrayList();
//创建数据
public static void createData(){
dataList.add(new Menu.Builder().id(0).menuName("根节点").parId(-2).type(0).url("").build());
for (int i = 1; i <50 ; i++) {
if (i<11) {
dataList.add(new Menu.Builder().id(i).menuName("1级节点"+i).parId(0).type(0).url("").build());
}else {
dataList.add(new Menu.Builder().id(i).menuName(((i/10)+1)+"级节点"+i).parId(i-10).type(0).url("").build());
}
}
}
//System.out.println(getTreeByColl(dataList));
/**
* 通过集合方式生成树
* @param list
* @return
*/
public static Map<String, Object> getTreeByColl(List<Menu> list) {
Map<String, Object> resmap=new HashMap<>();
Map<Integer, Menu> map;
List<Menu> treelist= new ArrayList<>(); if (null==list||list.isEmpty()){
return null;
}
map = list.stream().collect(Collectors.toMap(Menu::getId, a -> a,(k1, k2)->k1));
/*List<Map.Entry<Integer, Menu>> listMap = new ArrayList<Map.Entry<Integer, Menu>>(map.entrySet());
Collections.sort(listMap, new Comparator<Map.Entry<Integer, Menu>>() {
public int compare(Map.Entry<Integer, Menu> o1, Map.Entry<Integer, Menu> o2) {
return o2.getKey().compareTo(o1.getKey());
}
});*/
// 将list集合对象转换为json的字符串
// 如果id是父级的话就放入tree中treelist
for (Menu menu : list) {
if (null==map.get(menu.getParId())) {
treelist.add(menu);
} else {
// 子级通过父id获取到父级的类型
Menu parent = map.get(menu.getParId());
// 父级获得子级,再将子级放到对应的父级中
parent.addChildren(menu);
}
} resmap.put("data",treelist);
return resmap;
} }

Java生成菜单树(目录树)的几种方式的更多相关文章

  1. java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明)

    转载地址:http://www.devba.com/index.php/archives/4581.html java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明); ...

  2. JAVA发送http GET/POST请求的两种方式+JAVA http 请求手动配置代理

    java发送http get请求,有两种方式. 第一种用URLConnection: public static String get(String url) throws IOException { ...

  3. (转)java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明)

    java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明);部分资料参考网络资源 1. java向MySQL插入当前时间的四种方式 第一种:将java.util.Date ...

  4. Java 数组元素逆序Reverse的三种方式

    Java 数组元素逆序Reverse的三种方式   本文链接:https://blog.csdn.net/xHibiki/article/details/82930521 题目 代码实现 说明 int ...

  5. 用java代码实现构造目录树

    怎么用java代码实现上面这样的目录树? 首先创建数据表 每条数据记录自己的id以及父节点的id 然后进入java代码部分: public String directory(String author ...

  6. Java身份证归属地目录树

    数据库结构: web管理界面: 目录树: 视频: 应用场景:

  7. 第十二节:WebApi自动生成在线Api文档的两种方式

    一. WebApi自带生成api文档 1. 说明 通过观察,发现WebApi项目中Area文件夹下有一个HelpPage文件夹,如下图,该文件夹就是WebApi自带的生成Api的方式,如果该文件夹没了 ...

  8. JAVA SparkSQL初始和创建DataFrame的几种方式

    建议参考SparkSQL官方文档:http://spark.apache.org/docs/latest/sql-programming-guide.html 一.前述       1.SparkSQ ...

  9. 0036 Java学习笔记-多线程-创建线程的三种方式

    创建线程 创建线程的三种方式: 继承java.lang.Thread 实现java.lang.Runnable接口 实现java.util.concurrent.Callable接口 所有的线程对象都 ...

随机推荐

  1. python - django 实现文件下载功能

    使用 Django 搭建的网站中添加一个可以从服务器中下载文件的功能 (此处演示一个从网站中下载API文档的例子供参考) # 一.url  urlpatterns = [ # 下载 API 接口文档 ...

  2. SQL Server 父子迭代查询语句,树状查询

    这个也有用: -- Get childs by parent idWITH TreeAS( SELECT Id,ParentId FROM dbo.Node P WHERE P.Id = 21 -- ...

  3. LOJ P10013 曲线 题解

    每日一题 day38 打卡 Analysis 这道题运用的是三分,就是说具有一定的单调性,找最大最小值,然后和二分基本类似,就是说特性就是说当前两个点比较,较优的点和最优点在相对了较差点的同侧,就是说 ...

  4. Vue之路由

    1. SPA是什么 单页Web应用(single page application,SPA),就是只有一个Web页面的应用, 是加载单个HTML页面,并在用户与应用程序交互时动态更新该页面的Web应用 ...

  5. Hibernate对象持久化的三种状态

    1.三种状态: public static void testSel() { Session session = HibernateUtils.openSession(); Transaction t ...

  6. vuex基础入门

    Vuex简介 vuex的安装和组成介绍 [外链图片转存失败(img-nWQUUuyh-1565273314232)(https://upload-images.jianshu.io/upload_im ...

  7. Python各种扩展名(py, pyc, pyw, pyo, pyd)区别

    扩展名 在写Python程序时我们常见的扩展名是py, pyc,其实还有其他几种扩展名.下面是几种扩展名的用法. py py就是最基本的源码扩展名 pyw pyw是另一种源码扩展名,跟py唯一的区别是 ...

  8. js MD5加密与 java MD5加密不一致

    因为该项目会部署到多台机器,所以需要用字符生成唯一的MD5,但是js生成的MD5和java生成的MD5不一致.经过博主查阅资料发现java生成MD5用的是utf-8的编码,而且js用的是2进制.那我就 ...

  9. mysql 组合聚集函数

    mysql> select * from table1; +----------+------------+-----+---------------------+ | name_new | t ...

  10. AOP注解方式ApsectJ开发

    AOP注解方式ApsectJ开发 引入配置文件 编写切面类配置 使用注解的AOP对象目标类进行增强 在配置文件中开启以注解形式进行AOP开发 在切面类上添加注解 注解AOP通知类型 @Before前置 ...