当前位置: 首页 > news >正文

多级分类的实现方式

一:

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

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

树形递归查询

 

 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

    /****  生产层级编号* @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"

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

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

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

/*** 组织部门树形* @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);
}

相关文章:

  • 双系统重装ubuntu
  • 缺乏对新技术的评估和引入机制,如何建立
  • Cursor安全漏洞事件深度解析:当AI编程工具成为供应链攻击的新战场
  • Secs/Gem第五讲(基于secs4net项目的ChatGpt介绍)
  • C++核心编程--2 引用
  • 小结: js 在浏览器执行原理
  • 解密企业级大模型智能体Agentic AI 关键技术:MCP、A2A、Reasoning LLMs- Manus技术解密
  • 关于词向量的思考
  • 【数据结构】栈与队列
  • ExecutorService详解:Java 17线程池管理从零到一
  • nestjs[一文学懂TypeORM在nestjs中的日常使用]
  • C++核心编程--3 函数提高
  • 小白学编程之——数据库如何性能优化
  • 【RAP】RAP动作与流行舞蹈/街舞
  • unity terrain 在生成草,树,石头等地形障碍的时候,无法触发碰撞导致人物穿过模型
  • 图深度学习、EMD和VMD详解
  • 【日撸 Java 三百行】Day 16(递归)
  • 数据结构之图的应用场景及其代码
  • 修复“ImportError: DLL load failed while importing lib: 找不到指定的程序”笔记
  • Cocos Creator 3.8.5 构建依赖环境配置文档
  • 国家防汛抗旱总指挥部对15个重点省份开展汛前实地督导检查
  • A股三大股指低收:汽车股领涨,大金融走弱,两市成交近1.1万亿元
  • “多规合一”改革7年成效如何?自然资源部总规划师亮成绩单
  • 农行回应“病重老人被要求亲自取钱在银行去世”:全力配合公安机关调查
  • 李家超:明日起香港特区护照持有人可免签入境阿联酋
  • 马上评|让查重回归促进学术规范的本意