java获取树行结构菜单

项目中免不了会遇到树形结构的查询,今天分享一下我写的一个查询方法。 先看数据库的数据,主要有id,parentId,name三个字段(可能还有其他本次无用的很多字段),根节点的父id设置为0
在这里插入图片描述
实现的效果

[{
	"children": [{
		"children": [{
			"children": [{
				"children": [],
				"id": 11,
				"name": "四级目录1111",
				"parentId": 5
			}],
			"id": 5,
			"name": "三级目录111",
			"parentId": 3
		}, {
			"children": [],
			"id": 6,
			"name": "三级目录112",
			"parentId": 3
		}, {
			"children": [],
			"id": 7,
			"name": "三级目录113",
			"parentId": 3
		}],
		"id": 3,
		"name": "二级目录11",
		"parentId": 1
	}],
	"id": 1,
	"name": "一级目录1",
	"parentId": 0
}, {
	"children": [{
		"children": [{
			"children": [{
				"children": [],
				"id": 12,
				"name": "四级目录2111",
				"parentId": 8
			}],
			"id": 8,
			"name": "三级目录211",
			"parentId": 4
		}, {
			"children": [],
			"id": 9,
			"name": "三级目录212",
			"parentId": 4
		}, {
			"children": [],
			"id": 10,
			"name": "三级目录213",
			"parentId": 4
		}],
		"id": 4,
		"name": "二级目录21",
		"parentId": 2
	}],
	"id": 2,
	"name": "一级目录2",
	"parentId": 0
}]

下面是业务层的实现代码,主要是递归的思想

package yulisao.test;

import com.alibaba.fastjson.JSON;
import yulisao.bean.Menu;
import yulisao.bean.MenuTree;

import java.util.ArrayList;
import java.util.List;

/**
 * @author yulisao
 * @createDate 2022/7/9 0009 下午 3:54
 */
public class MenuTreeTest {

    public static void main(String[] args) {
        List<MenuTree> resp = getMenuTreeList(0L); // c从根节点开始查找。根节点的id是0
        System.out.println(JSON.toJSONString(resp));
    }

    public static List<MenuTree> getMenuTreeList(Long parentId) {
        List<MenuTree> menuTrees = new ArrayList<>();
        //List<Menu> menuList = xxxxxMapper.findByParentId(parentId); // 去数据库根据父id查询
        List<Menu> menuList = findByParentId(parentId);
        for (Menu menu : menuList) {
            MenuTree nodeTree = new MenuTree();
            nodeTree.setId(menu.getId());
            nodeTree.setParentId(menu.getParentId());
            nodeTree.setName(menu.getName());
            nodeTree.setChildren(getMenuTreeList(menu.getId()));//递归
            menuTrees.add(nodeTree);
        }
        return menuTrees;
    }

    /**
     * 模拟 根据父id从数据库查询数据
     * @param parentId
     * @return
     */
    public static List<Menu> findByParentId (Long parentId) {
        List<Menu> menus = new ArrayList<>();

        if (parentId==0) {
            Menu menu = new Menu();
            menu.setId(1L);
            menu.setParentId(0L);
            menu.setName("一级目录1");
            menus.add(menu);
            Menu menu1 = new Menu();
            menu1.setId(2L);
            menu1.setParentId(0L);
            menu1.setName("一级目录2");
            menus.add(menu1);
        }

        if (parentId==1) {
            Menu menu = new Menu();
            menu.setId(3L);
            menu.setParentId(1L);
            menu.setName("二级目录11");
            menus.add(menu);
        }

        if (parentId==2) {
            Menu menu = new Menu();
            menu.setId(4L);
            menu.setParentId(2L);
            menu.setName("二级目录21");
            menus.add(menu);
        }

        if (parentId==3) {
            Menu menu = new Menu();
            menu.setId(5L);
            menu.setParentId(3L);
            menu.setName("三级目录111");
            menus.add(menu);
            Menu menu1 = new Menu();
            menu1.setId(6L);
            menu1.setParentId(3L);
            menu1.setName("三级目录112");
            menus.add(menu1);
            Menu menu2 = new Menu();
            menu2.setId(7L);
            menu2.setParentId(3L);
            menu2.setName("三级目录113");
            menus.add(menu2);
        }

        if (parentId==4) {
            Menu menu = new Menu();
            menu.setId(8L);
            menu.setParentId(4L);
            menu.setName("三级目录211");
            menus.add(menu);
            Menu menu1 = new Menu();
            menu1.setId(9L);
            menu1.setParentId(4L);
            menu1.setName("三级目录212");
            menus.add(menu1);
            Menu menu2 = new Menu();
            menu2.setId(10L);
            menu2.setParentId(4L);
            menu2.setName("三级目录213");
            menus.add(menu2);
        }

        if (parentId==5) {
            Menu menu = new Menu();
            menu.setId(11L);
            menu.setParentId(5L);
            menu.setName("四级目录1111");
            menus.add(menu);
        }

        if (parentId==8) {
            Menu menu = new Menu();
            menu.setId(12L);
            menu.setParentId(8L);
            menu.setName("四级目录2111");
            menus.add(menu);
        }

        return menus;
    }
}


实体和返回对象

package yulisao.bean;

/**
 * 菜单实体对象
 * @author yulisao
 * @createDate 2022/7/9 0009 下午 5:16
 */
public class Menu {

    private Long id;
    private Long parentId;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getParentId() {
        return parentId;
    }

    public void setParentId(Long parentId) {
        this.parentId = parentId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

package yulisao.bean;

import java.util.List;

/**
 * 返回的菜单树对象 相比菜单实体对象这里只取了我们需要返回给前端的部分字段,并且多了一个list成员来存放子节点菜单
 * @author yulisao
 * @createDate 2022/7/9 0009 下午 3:55
 */
public class MenuTree {

    private Long id;
    private Long parentId;
    private String name;
    List<MenuTree> children;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getParentId() {
        return parentId;
    }

    public void setParentId(Long parentId) {
        this.parentId = parentId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<MenuTree> getChildren() {
        return children;
    }

    public void setChildren(List<MenuTree> children) {
        this.children = children;
    }
}

创建表语句

 CREATE TABLE `t_menu` (
  `id` INT(11) NOT NULL,
  `parentId` INT(11) NOT NULL,
  `url` VARCHAR(50) NOT NULL,
  `menuname` VARCHAR(50) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=gbk COMMENT '菜单表';
INSERT INTO `t_menu` (`id`, `parentId`, `url`, `menuname`) VALUES('1','0','yourUrl','一级目录1');
INSERT INTO `t_menu` (`id`, `parentId`, `url`, `menuname`) VALUES('2','0','yourUrl','一级目录2');
INSERT INTO `t_menu` (`id`, `parentId`, `url`, `menuname`) VALUES('3','1','yourUrl','二级目录11');
INSERT INTO `t_menu` (`id`, `parentId`, `url`, `menuname`) VALUES('4','2','yourUrl','二级目录21');
INSERT INTO `t_menu` (`id`, `parentId`, `url`, `menuname`) VALUES('5','3','yourUrl','三级目录111');
INSERT INTO `t_menu` (`id`, `parentId`, `url`, `menuname`) VALUES('6','3','yourUrl','三级目录112');
INSERT INTO `t_menu` (`id`, `parentId`, `url`, `menuname`) VALUES('7','3','yourUrl','三级目录113');
INSERT INTO `t_menu` (`id`, `parentId`, `url`, `menuname`) VALUES('8','4','yourUrl','三级目录211');
INSERT INTO `t_menu` (`id`, `parentId`, `url`, `menuname`) VALUES('9','4','yourUrl','三级目录212');
INSERT INTO `t_menu` (`id`, `parentId`, `url`, `menuname`) VALUES('10','4','yourUrl','三级目录213');
INSERT INTO `t_menu` (`id`, `parentId`, `url`, `menuname`) VALUES('11','5','yourUrl','四级目录1111');
INSERT INTO `t_menu` (`id`, `parentId`, `url`, `menuname`) VALUES('12','8','yourUrl','四级目录2111');

分析一下getMenuTreeList方法,先查出父id为0的全部数据(即一级菜单),遍历一级菜单得到一级菜单的id后,在根据这个id去查二级菜单的数据,一层一层往下查。查不到的时候menuList为空也就不会进入for循环了自然不会无限循环。另外一种写法和这个类似,就是不带任何条件先查询出所有的数据,然后从所有数据中去判断他们的父id是不是我要找的,若是则添加。

public static List<MenuTree> getMenuTreeList2(Long parentId,List<Menu> allMenuList) {
        List<MenuTree> menuTrees = new ArrayList<>();
        for (Menu menu : allMenuList) {
            //遍历所有数据,如果该数据的父id等于当前要找的id就添加
            if (parentId.equals(menu.getParentId())) {
                MenuTree nodeTree = new MenuTree();
                nodeTree.setId(menu.getId());
                nodeTree.setParentId(menu.getParentId());
                nodeTree.setName(menu.getName());
                nodeTree.setChildren(getMenuTreeList2(menu.getId(), allMenuList)); // 递归
                menuTrees.add(nodeTree);
            }
        }
        return menuTrees;
    }

二者的区别就是只查一次数据库和多次的区别,具体选哪个视菜单表的数据量有多少以及他的层级有多深。数据量不大层级不深,推荐用后者,一次查询把数据全部加载到内存中来,减少数据库连接的开销。

猜你喜欢

转载自blog.csdn.net/qq_29539827/article/details/125697208
今日推荐