Java生成菜单树(目录树)的几种方式
本文介绍两种不同生成多级目录树的方式: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生成菜单树(目录树)的几种方式的更多相关文章
- java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明)
转载地址:http://www.devba.com/index.php/archives/4581.html java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明); ...
- JAVA发送http GET/POST请求的两种方式+JAVA http 请求手动配置代理
java发送http get请求,有两种方式. 第一种用URLConnection: public static String get(String url) throws IOException { ...
- (转)java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明)
java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明);部分资料参考网络资源 1. java向MySQL插入当前时间的四种方式 第一种:将java.util.Date ...
- Java 数组元素逆序Reverse的三种方式
Java 数组元素逆序Reverse的三种方式 本文链接:https://blog.csdn.net/xHibiki/article/details/82930521 题目 代码实现 说明 int ...
- 用java代码实现构造目录树
怎么用java代码实现上面这样的目录树? 首先创建数据表 每条数据记录自己的id以及父节点的id 然后进入java代码部分: public String directory(String author ...
- Java身份证归属地目录树
数据库结构: web管理界面: 目录树: 视频: 应用场景:
- 第十二节:WebApi自动生成在线Api文档的两种方式
一. WebApi自带生成api文档 1. 说明 通过观察,发现WebApi项目中Area文件夹下有一个HelpPage文件夹,如下图,该文件夹就是WebApi自带的生成Api的方式,如果该文件夹没了 ...
- JAVA SparkSQL初始和创建DataFrame的几种方式
建议参考SparkSQL官方文档:http://spark.apache.org/docs/latest/sql-programming-guide.html 一.前述 1.SparkSQ ...
- 0036 Java学习笔记-多线程-创建线程的三种方式
创建线程 创建线程的三种方式: 继承java.lang.Thread 实现java.lang.Runnable接口 实现java.util.concurrent.Callable接口 所有的线程对象都 ...
随机推荐
- 用于未处理异常错误的.NET框架清理工具
当你启动某些程序时,会收到与此错误类似的未处理异常错误:Unhandled e0434f4dh exception at 7c81eb33h.此问题是由于.NET框架未正确安装或.NET框架系统中的另 ...
- WinDbg常用命令系列---!analyze
!analyze命令简介 这个!analyze扩展显示有关当前异常或错误检查的信息. 用户模式: !analyze [-v] [-f | -hang] [-D BucketID] !analyze - ...
- 洛谷P1577 切绳子题解
洛谷P1577 切绳子题解 题目描述 有N条绳子,它们的长度分别为Li.如果从它们中切割出K条长度相同的 绳子,这K条绳子每条最长能有多长?答案保留到小数点后2位(直接舍掉2为后的小数). 输入输出格 ...
- Vue.set 向响应式对象中添加响应式属性,及设置数组元素触发视图更新
一.为什么需要使用Vue.set? vue中不能检测到数组和对象的两种变化: 1.数组长度的变化 vm.arr.length = 4 2.数组通过索引值修改内容 vm.arr[1] = ‘aa’ Vu ...
- Git基本介绍(三大分区及核心内部构造)
1. Git三大工作区(工作区.暂存区和版本库) 工作区(WORKING DIRECTORY): 直接编辑文件的地方,肉眼可见直接操作: 暂存区(STAGIN AREA):数据(快照)暂时存放的地方: ...
- 如果要对img里面的值做特殊处理,可以直接写方法
html <img :src="getMore('up')" alt=""> data里面定义的 one: 'http://p1.fishqc.ne ...
- devops 运维平台相关知识
1.https://choerodon.io/zh/community/ (代码 https://github.com/choerodon/choerodon) 猪齿鱼 2.https://www.o ...
- rust 函数的使用
fn main() { println!("Hello, world!"); another_function(2,3); let y ={ let x =3; //表达式的结尾没 ...
- 数据仓库DW、ODS、DM概念及其区别
整体结构 在具体分析数据仓库之前先看下一下数据中心的整体架构以及数据流向 数据中心整体架构.png DB 是现有的数据来源,可以为mysql.SQLserver.文件日志等,为数据仓库提供数据来源 ...
- Dependency Parsing
句子的依赖结构表现在哪些单词依赖哪些单词.单词之间的这种关系及可以表示为优先级之间的关系等. Dependency Parsing 通常情况下,对于一个输入句子:\(S=w_{0} w_{1} \do ...