多级分类的实现方式

一:

字段里有一个parentId,0代表顶级,1是二级,2是三级

查一级分类,在实体类(对标数据库的表)添加一个对象,添加注解,因为这个对象在数据库不存在这个字段。

树形递归查询

java 复制代码
 public List<CategoryEntity> listWithTree() {
        //查出所有分类
        List<CategoryEntity>entities=baseMapper.selectList(null);
        //组装成父子树形结构
        //2.1)、找到所有一级分类
        List<CategoryEntity> levelMenus = entities.stream()
                .filter(e -> e.getParentCid() == 0)
                .map((menu) -> {
                    menu.setChildren(getChildrens(menu, entities));
                    return menu;
                })
                .sorted((menu, menu2) -> {
                    return (menu.getSort() == null ? 0 : menu.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
                })
                .collect(Collectors.toList());

        return levelMenus;
    }
    //递归查找所有菜单的子菜单
    private List<CategoryEntity> getChildrens(CategoryEntity root, List<CategoryEntity> all) {

        List<CategoryEntity> children = all.stream().filter(categoryEntity -> {
            return categoryEntity.getParentCid().equals(root.getCatId());
        }).map(categoryEntity -> {
            //1、找到子菜单(递归)
            categoryEntity.setChildren(getChildrens(categoryEntity, all));
            return categoryEntity;
        }).sorted((menu, menu2) -> {
            //2、菜单的排序
            return (menu.getSort() == null ? 0 : menu.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
        }).collect(Collectors.toList());

        return children;

    }

setchildren是往新增属性list里添加,所以才会有一级嵌套二级嵌套三级

二:

部门有多级部门,比如父部门,子部门

表中parent_dept_no和dept_no是用于构建树形结构的基础,通过这2个字段定义资源的上下级关系,通常添加部门,我们通过程序自动生成编号,生成的编号满足以下规则:

  • 1级:100000000000000

  • 2级:100001000000000

  • 3级:100001001000000

  • 4级:100001001001000

  • 5级:100001001001001

当我们在需要查询当前1级节点以下所有节点时,就不用再递归查询,使用like "dept_no%"即可。

举个例子:

想要查询100001001000000下所有的部门,我们的查询方式为:

复制代码
select * from sys_dept where dept_no like '100001001%'

这样就可以查询到100001001000000部门下所有的部门了

我的疑问:同级的不同部门怎么区分?

//构建部门编号,有两种情况,当前父部门编号,有子部门:在已有的子部门的基础上累加 | 没有子部门:新增子部门编号

DeptDto deptDto = DeptDto.builder().parentDeptNo(parentDeptNo).build();

List<DeptVo> deptVoList = deptMapper.selectList(deptDto);

//无下属节点则创建下属节点

if(EmptyUtil.isNullOrEmpty(deptVoList)){

return NoProcessing.createNo(parentDeptNo,false);

}else {

//有下属节点则累加下属节点

Long deptNo = deptVoList.stream().map(dept -> {

return Long.valueOf(dept.getDeptNo());

}).max(Comparator.comparing(i -> i)).get();

return NoProcessing.createNo(String.valueOf(deptNo),true);

}

即当前要创建节点的父节点经过我们查询有别的子节点,我们就累加,即找到子节点的最大一个序号,然后在下面创建序列号的逻辑里累加

比如:100001002000000,累加以后变成100001003000000

java 复制代码
    /***
     *  生产层级编号
     * @param input 输入编号
     * @param peerNode 是否下属节点
     * @return
     * @return: java.lang.String
     */
    public static String createNo(String input,boolean peerNode) {
        int step = input.length() / 3;
        int supplement = 0;
        for (int i =0;i<step;i++ ){
            String targetString = input.substring(input.length()-3,input.length());
            if ("000".equals(targetString)){
                input = input.substring(0,input.length()-3);
                supplement++;
            }else {
                break;
            }
        }
        if (peerNode){
            input = String.valueOf(Long.valueOf(input) + 1L);
            for (int i =0;i<supplement;i++ ){
                input = input+"000";
            }
        }else {
            input = String.valueOf(Long.valueOf(input+"001"));
            for (int i =0;i<supplement-1;i++ ){
                input = input+"000";
            }
        }
        return input;
    }
第一部分:处理尾部连续的"000"
  1. 计算步长step = input.length() / 3 计算出可以检查多少个三字符子串。
  2. 循环检查尾部 :从输入字符串的末尾开始,每次取最后三个字符进行检查。
    • 如果这三个字符是 "000",则将它们移除,并增加 supplement 计数器。
    • 如果不是 "000",则停止检查。
第二部分:根据 peerNode 标志调整编号
  • 如果 peerNodetrue

    • 将剩余的 input 转换为长整型并加 1。
    • 然后根据之前记录的 supplement 数量,向结果中追加相应数量的 "000"
  • 如果 peerNodefalse

    • 首先在 input 后面追加 "001",然后转换为长整型。
    • 接着根据 supplement - 1 的值,向结果中追加相应数量的 "000"

这样可以跟方便的查某一部门的子部门列表

还有一种需求就是查整个部门的树形结构

也是先查所有的,再通过所有的·慢慢拼出树形

java 复制代码
/**
     * 组织部门树形
     * @return
     */
@Override
public TreeVo deptTreeVo() {
    //获取根节点树形
    String parentDeptNo = SuperConstant.ROOT_DEPT_PARENT_ID;

    //构建查询条件
    DeptDto param = DeptDto.builder()
        .dataState(SuperConstant.DATA_STATE_0)
        .parentDeptNo(NoProcessing.processString(parentDeptNo))
        .build();
    //查询部门列表数据
    List<DeptVo> deptList =  deptMapper.selectList(param);

    if(EmptyUtil.isNullOrEmpty(deptList)){
        throw new BaseException("部门数据没有定义");
    }

    //找根节点
    DeptVo rootDept = deptList.stream().filter(d -> SuperConstant.ROOT_DEPT_PARENT_ID.equals(d.getParentDeptNo())).collect(Collectors.toList()).get(0);

    //返回的部门数据
    List<TreeItemVo> treeItemVoList = new ArrayList<>();

    //递归调用
    recursionTreeItem(treeItemVoList,rootDept,deptList);

    return TreeVo.builder().items(treeItemVoList).build();
}

/**
     * 递归调用拼装数据
     * @param treeItemVoList  封装返回的数据
     * @param rootDept  当前部门
     * @param deptList  部门列表(全部数据)
     */
private void recursionTreeItem(List<TreeItemVo> treeItemVoList, DeptVo rootDept, List<DeptVo> deptList) {
    //构建item对象
    TreeItemVo treeItemVo = TreeItemVo.builder().id(rootDept.getDeptNo()).label(rootDept.getDeptName()).build();
    //获得当前部门下的子部门
    List<DeptVo> childrenDept = deptList.stream()
        .filter(n -> n.getParentDeptNo().equals(rootDept.getDeptNo()))
        .collect(Collectors.toList());
    //如果子部门不为空,则继续递归调用
    if(!EmptyUtil.isNullOrEmpty(childrenDept)){

        ArrayList<TreeItemVo> listChildren = Lists.newArrayList();
        //子部门列表
        childrenDept.forEach(dept -> {
            this.recursionTreeItem(listChildren,dept,deptList);
        });
        treeItemVo.setChildren(listChildren);
    }

    treeItemVoList.add(treeItemVo);
}
相关推荐
王有品2 小时前
Java 集合框架对比全解析:单列集合 vs 双列集合
java·windows·python
感谢地心引力7 小时前
【Matlab】最新版2025a发布,深色模式、Copilot编程助手上线!
开发语言·windows·matlab·copilot
qq_653644469 小时前
如何查看打开的 git bash 窗口是否是管理员权限打开
开发语言·windows·git·bash
云途行者13 小时前
windows、Ubuntu、Debian 添加静态路由
linux·windows·ubuntu
敲代码的瓦龙16 小时前
STL?list!!!
c语言·开发语言·数据结构·c++·windows·list
一枚小菜程序员16 小时前
记录: Windows下远程Liunx 系统xrdp 用到的一些小问题(免费踩坑 记录)
windows
tyn1881 天前
记录一次conda虚拟环境pip安装报错[WinError 32] 另一个程序正在使用此文件,进程无法访问
windows·conda·pip·虚拟环境·虚环境
陈苏同学1 天前
[已解决] VS Code / Cursor / Trae 的 PowerShell 终端 conda activate 进不去环境的常见问题
linux·windows·conda
辰%1 天前
如何重启pycharm中的项目?
windows·python·pycharm