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接口 所有的线程对象都 ...
随机推荐
- 我的ImageIO.write ByteArrayOutputStream为什么这么慢?
File.createTempFile(prefix, suffix),创建一个临时文件,再使用完之后清理即可.但是遇到如下两个坑: String prefix = "temp"; ...
- 查全率(Recall),查准率(Precision),灵敏性(Sensitivity),特异性(Specificity),F1,PR曲线,ROC,AUC的应用场景
之前介绍了这么多分类模型的性能评价指标(<分类模型的性能评价指标(Classification Model Performance Evaluation Metric)>),那么到底应该选 ...
- mysql 修改字段名称以及长度
//修改字段长度 alter table table1 modify name ); //修改字段名称以及长度 alter table table1 change name name_new ); a ...
- manjaro arm在rock pi4b中的配置记录:
首先说明下我的硬件情况,网上买了: 主要有emmc的转接板,主要是写入emmc镜像使用,32G的emmc,打算安装个android用来看电子书够了.需要自备读卡器,资料太少了,么有说明,考虑了1个多小 ...
- Fluent也弹窗
具体步骤见<fluent加载第三方(C++,Fortran等)动态链接库> 我们对导入的动态链接库进行改动 打开VS2013 源代码: #include #ifdef __cplusplu ...
- ArgumentException: The Assembly Mono.WebBrowser is referenced by System.Windows.Forms ('Assets/Plugins/System.Windows.Forms.dll'). But the dll is not allowed to be included or could not be found.
最近有个项目要用到System.Windows.Forms.dll,在Unity编辑器里用着还好好的,但是一导出就给我报错,让我十分不爽. 于是请教百度,搜出了五花八门的答案,没一个能解决我的问题的, ...
- idea乱码问题
## 1. 文件中内容中文乱码 这个原因是文件的编码和项目的编码不一致导致,将项目工程和文件的编码设置成一致的(如,文件编码是GBK,那就都设置为GBK,若为UTF-8就都设置为UTF-8) ## 2 ...
- TCP连接关闭总结
由于涉及面太广,只作简单整理,有兴趣的可参考<UNIX Networking Programming>volum 1, Section 5.7, 5.12, 5.14, 5.15, 6.6 ...
- m4a 转MP3
import os for filename in os.listdir(r'.'): print filename os.rename(filename,filename.replace(' ',' ...
- 升级ruby的版本 https://gems.ruby-china.com/
升级ruby版本,有时候安装ruby的版本过低,需要进行升级,例如安装在centos6.7安装fpm需要ruby版本在1.9以上. 1.主机环境如下: 1 [root@test ~]# cat /et ...