跟着开源项目学java6-从优化部门查询逻辑的提交看树形数据处理的设计
若依 树
·
本来打算对一些比较复杂的功能做些解析的,但发现还是挺有难度的,那还是两方面吧,一个难一点的,一个简单一点的搭配着写,其实一些写法上的优化也是有很多可以学习的地方,自己写代码很多都是直接一个for循环
这次看一个在列表中排除某些元素的写法优化,用
removeIf 函数,传入一个 Predicate 用来过滤,跟我们平时用的 stream().filter() 挺像的,但确实之前我只知道用 stream() 但是又会显得很繁琐
这里再简单看下 sys_dept 的 存储
可以看到这个字段存储了这个节点的所有祖先,二叉树到根节点的所有父节点,不难推测,保存和修改节点的时候肯定会动态 set 这个属性
下面思考,加上这个字段以后,对部门树的操作service应该如何设计(crud)
首先看新增,新增只会增加子节点,查询到这个节点到根节点路径上的父节点就好了
/**
* 新增保存部门信息
*
* @param dept 部门信息
* @return 结果
*/
@Override
public int insertDept(SysDept dept)
{
SysDept info = deptMapper.selectDeptById(dept.getParentId());
// 如果父节点不为正常状态,则不允许新增子节点
if (!UserConstants.DEPT_NORMAL.equals(info.getStatus()))
{
throw new ServiceException("部门停用,不允许新增");
}
dept.setAncestors(info.getAncestors() + "," + dept.getParentId());
return deptMapper.insertDept(dept);
}
这里其实有点递归的意思,父节点中已经存放了他的所有父节点,所以只用找出离他最近的一个父节点 parent.ancestor + parent.id,字符串拼接上即可
再看修改
/**
* 修改部门
*/
@PreAuthorize("@ss.hasPermi('system:dept:edit')")
@Log(title = "部门管理", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody SysDept dept)
{
Long deptId = dept.getDeptId();
deptService.checkDeptDataScope(deptId);
if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
{
return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
}
else if (dept.getParentId().equals(deptId))
{
return AjaxResult.error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
}
else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
{
return AjaxResult.error("该部门包含未停用的子部门!");
}
dept.setUpdateBy(getUsername());
return toAjax(deptService.updateDept(dept));
}
/**
* 修改保存部门信息
*
* @param dept 部门信息
* @return 结果
*/
@Override
public int updateDept(SysDept dept)
{
SysDept newParentDept = deptMapper.selectDeptById(dept.getParentId());
SysDept oldDept = deptMapper.selectDeptById(dept.getDeptId());
if (StringUtils.isNotNull(newParentDept) && StringUtils.isNotNull(oldDept))
{
String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId();
String oldAncestors = oldDept.getAncestors();
dept.setAncestors(newAncestors);
updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
}
int result = deptMapper.updateDept(dept);
if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())
&& !StringUtils.equals("0", dept.getAncestors()))
{
// 如果该部门是启用状态,则启用该部门的所有上级部门
updateParentDeptStatusNormal(dept);
}
return result;
}
controller 层确保
- 部门名称唯一
- 上级部门不能是自己
- 不能包含未停用的子部门
service 层处理具体逻辑
- 首先处理自己的 ancestor 字段,找到修改后的父节点,拼接得到自己的 ancestor
- 递归处理所有子节点的 ancestor
/**
* 修改子元素关系
*
* @param deptId 被修改的部门ID
* @param newAncestors 新的父ID集合
* @param oldAncestors 旧的父ID集合
*/
public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors)
{
List<SysDept> children = deptMapper.selectChildrenDeptById(deptId);
for (SysDept child : children)
{
child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
}
if (children.size() > 0)
{
deptMapper.updateDeptChildren(children);
}
}
<select id="selectChildrenDeptById" parameterType="Long" resultMap="SysDeptResult">
select * from sys_dept where find_in_set(#{deptId}, ancestors)
</select>
<update id="updateDeptChildren" parameterType="java.util.List">
update sys_dept set ancestors =
<foreach collection="depts" item="item" index="index"
separator=" " open="case dept_id" close="end">
when #{item.deptId} then #{item.ancestors}
</foreach>
where dept_id in
<foreach collection="depts" item="item" index="index"
separator="," open="(" close=")">
#{item.deptId}
</foreach>
</update>
这个 sql 会找出 ancestors 中包含这个 id 的,也就是这个节点所有的子节点,然后更新这个 set
更多推荐
已为社区贡献18条内容
所有评论(0)