多级分类的实现方式
一:
字段里有一个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”
- 计算步长:
step = input.length() / 3
计算出可以检查多少个三字符子串。 - 循环检查尾部:从输入字符串的末尾开始,每次取最后三个字符进行检查。
- 如果这三个字符是
"000"
,则将它们移除,并增加supplement
计数器。 - 如果不是
"000"
,则停止检查。
- 如果这三个字符是
第二部分:根据 peerNode
标志调整编号
-
如果
peerNode
为true
:- 将剩余的
input
转换为长整型并加 1。 - 然后根据之前记录的
supplement
数量,向结果中追加相应数量的"000"
。
- 将剩余的
-
如果
peerNode
为false
:- 首先在
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);
}