🐛 fix 组织机构移动时层级和深度更新错误的问题 & 使用 sharding-jdbc 时无法正确处理 sql 的问题

 新增组织机构层级和深度校正接口
This commit is contained in:
b2baccline
2021-06-22 23:57:28 +08:00
parent 2579e7cf8c
commit 0b872abdff
7 changed files with 169 additions and 37 deletions

View File

@@ -1,7 +1,9 @@
package com.hccake.ballcat.system.mapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hccake.ballcat.system.model.dto.OrganizationMoveChildParam;
import com.hccake.ballcat.system.model.entity.SysOrganization;
import com.hccake.ballcat.system.model.qo.SysOrganizationQO;
import com.hccake.extend.mybatis.plus.conditions.query.LambdaQueryWrapperX;
@@ -37,12 +39,9 @@ public interface SysOrganizationMapper extends ExtendMapper<SysOrganization> {
/**
* 跟随父节点移动子节点
* @param originHierarchy 原始父级层级
* @param targetHierarchy 移动后的父级层级
* @param depthDiff 移动的深度差
* @param param OrganizationMoveChildParam 跟随移动子节点的参数对象
*/
void followMoveChildNode(@Param("originHierarchy") String originHierarchy,
@Param("targetHierarchy") String targetHierarchy, @Param("depthDiff") int depthDiff);
void followMoveChildNode(@Param("param") OrganizationMoveChildParam param);
/**
* 根据组织机构Id查询该组织下的所有子部门
@@ -51,4 +50,18 @@ public interface SysOrganizationMapper extends ExtendMapper<SysOrganization> {
*/
List<SysOrganization> listChildOrganization(@Param("organizationId") Integer organizationId);
/**
* 批量更新节点层级和深度
* @param depth 深度
* @param hierarchy 层级
* @param organizationIds 组织id集合
*/
default void updateHierarchyAndPathBatch(int depth, String hierarchy, List<Integer> organizationIds) {
LambdaUpdateWrapper<SysOrganization> wrapper = Wrappers.lambdaUpdate(SysOrganization.class)
.set(SysOrganization::getDepth, depth).set(SysOrganization::getHierarchy, hierarchy)
.in(SysOrganization::getId, organizationIds);
this.update(null, wrapper);
}
}

View File

@@ -50,4 +50,10 @@ public interface SysOrganizationService extends ExtendService<SysOrganization> {
*/
List<SysOrganization> listChildOrganization(Integer organizationId);
/**
* 校正组织机构层级和深度
* @return 校正是否成功
*/
boolean revisedHierarchyAndPath();
}

View File

@@ -3,24 +3,29 @@ package com.hccake.ballcat.system.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.hccake.ballcat.common.core.constant.GlobalConstants;
import com.hccake.ballcat.common.core.exception.BusinessException;
import com.hccake.ballcat.common.model.result.BaseResultCode;
import com.hccake.ballcat.common.util.TreeUtils;
import com.hccake.ballcat.system.converter.SysOrganizationConverter;
import com.hccake.ballcat.system.mapper.SysOrganizationMapper;
import com.hccake.ballcat.system.model.dto.OrganizationMoveChildParam;
import com.hccake.ballcat.system.model.dto.SysOrganizationDTO;
import com.hccake.ballcat.system.model.entity.SysOrganization;
import com.hccake.ballcat.system.model.qo.SysOrganizationQO;
import com.hccake.ballcat.system.model.vo.SysOrganizationTree;
import com.hccake.ballcat.system.service.SysOrganizationService;
import com.hccake.ballcat.common.core.constant.GlobalConstants;
import com.hccake.ballcat.common.core.exception.BusinessException;
import com.hccake.ballcat.common.model.result.BaseResultCode;
import com.hccake.ballcat.common.util.TreeUtils;
import com.hccake.extend.mybatis.plus.service.impl.ExtendServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 组织架构
@@ -69,14 +74,14 @@ public class SysOrganizationServiceImpl extends ExtendServiceImpl<SysOrganizatio
@Transactional(rollbackFor = Exception.class)
public boolean update(SysOrganizationDTO sysOrganizationDTO) {
// TODO 防止并发问题
SysOrganization sysOrganization = SysOrganizationConverter.INSTANCE.dtoToPo(sysOrganizationDTO);
Integer organizationId = sysOrganization.getId();
SysOrganization newSysOrganization = SysOrganizationConverter.INSTANCE.dtoToPo(sysOrganizationDTO);
Integer organizationId = newSysOrganization.getId();
SysOrganization originSysOrganization = baseMapper.selectById(organizationId);
// 如果没有移动父节点,则直接更新
Integer targetParentId = sysOrganizationDTO.getParentId();
if (originSysOrganization.getParentId().equals(targetParentId)) {
return SqlHelper.retBool(baseMapper.updateById(sysOrganization));
return SqlHelper.retBool(baseMapper.updateById(newSysOrganization));
}
// 移动了父节点,先判断不是选择自己作为父节点
@@ -91,16 +96,33 @@ public class SysOrganizationServiceImpl extends ExtendServiceImpl<SysOrganizatio
}
// 填充目标层级和深度
fillDepthAndHierarchy(sysOrganization, targetParentId);
// 原来的层级和深度
String originHierarchy = originSysOrganization.getHierarchy();
int originDepth = originSysOrganization.getDepth();
// 计算出更换父节点后的层级和深度
int depthDiff = originDepth - sysOrganization.getDepth();
fillDepthAndHierarchy(newSysOrganization, targetParentId);
// 更新其子节点的数据
baseMapper.followMoveChildNode(originHierarchy, sysOrganization.getHierarchy(), depthDiff);
OrganizationMoveChildParam param = getOrganizationMoveChildParam(newSysOrganization, originSysOrganization);
baseMapper.followMoveChildNode(param);
// 更新组织节点信息
return SqlHelper.retBool(baseMapper.updateById(newSysOrganization));
}
return SqlHelper.retBool(baseMapper.updateById(sysOrganization));
private OrganizationMoveChildParam getOrganizationMoveChildParam(SysOrganization newSysOrganization,
SysOrganization originSysOrganization) {
// 父组织 id
Integer parentId = newSysOrganization.getId();
// 父节点原来的层级
String originParentHierarchy = originSysOrganization.getHierarchy();
// 修改后的父节点层级
String targetParentHierarchy = newSysOrganization.getHierarchy();
// 父节点移动后的深度差
int depthDiff = originSysOrganization.getDepth() - newSysOrganization.getDepth();
OrganizationMoveChildParam param = new OrganizationMoveChildParam();
param.setParentId(parentId);
param.setOriginParentHierarchy(originParentHierarchy);
param.setOriginParentHierarchyLengthPlusOne(originParentHierarchy.length() + 1);
param.setTargetParentHierarchy(targetParentHierarchy);
param.setDepthDiff(depthDiff);
param.setGrandsonConditionalStatement(originParentHierarchy + "-" + parentId + "-%");
return param;
}
/**
@@ -123,6 +145,43 @@ public class SysOrganizationServiceImpl extends ExtendServiceImpl<SysOrganizatio
return baseMapper.listChildOrganization(organizationId);
}
/**
* 校正组织机构层级和深度
* @return 校正是否成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean revisedHierarchyAndPath() {
// 组织机构一般数据量不多,一次性查询出来缓存到内存中,减少查询开销
List<SysOrganization> sysOrganizations = baseMapper.selectList(Wrappers.emptyWrapper());
Map<Integer, List<SysOrganization>> map = sysOrganizations.stream()
.collect(Collectors.groupingBy(SysOrganization::getParentId));
// 默认的父节点为根节点,
Integer parentId = GlobalConstants.TREE_ROOT_ID;
int depth = 1;
String hierarchy = "0";
updateChildHierarchyAndPath(map, parentId, depth, hierarchy);
return true;
}
private void updateChildHierarchyAndPath(Map<Integer, List<SysOrganization>> map, Integer parentId, int depth,
String hierarchy) {
// 获取对应 parentId 下的所有子节点
List<SysOrganization> sysOrganizations = map.get(parentId);
if (CollectionUtil.isEmpty(sysOrganizations)) {
return;
}
// 递归更新子节点数据
List<Integer> childrenIds = new ArrayList<>();
for (SysOrganization sysOrganization : sysOrganizations) {
Integer organizationId = sysOrganization.getId();
updateChildHierarchyAndPath(map, organizationId, depth + 1, hierarchy + "-" + organizationId);
childrenIds.add(organizationId);
}
baseMapper.updateHierarchyAndPathBatch(depth, hierarchy, childrenIds);
}
/**
* 根据组织ID 删除组织机构
* @param organizationId 组织机构ID

View File

@@ -16,14 +16,16 @@
update_time
</sql>
<!-- 这里为了兼容 shardingsphare 4.x 暂时使用 ${} 传参-->
<update id="followMoveChildNode">
UPDATE
sys_organization
SET hierarchy =
CONCAT(#{targetHierarchy}, SUBSTR(hierarchy, LENGTH(#{originHierarchy}) + 1)),
depth = depth - #{depthDiff}
SET hierarchy = CONCAT(#{param.targetParentHierarchy}, SUBSTR(hierarchy, ${param.originParentHierarchyLengthPlusOne})),
depth = depth - #{param.depthDiff}
WHERE
hierarchy like CONCAT(#{originHierarchy}, "-%")
parent_id = #{param.parentId} -- 儿子节点
or
hierarchy like #{param.grandsonConditionalStatement} -- 孙子节点
</update>
<select id="listChildOrganization" resultType="com.hccake.ballcat.system.model.entity.SysOrganization">

View File

@@ -13,14 +13,7 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@@ -42,7 +35,7 @@ public class SysOrganizationController {
* @param qo 组织机构查询条件
* @return R 通用返回体
*/
@ApiOperation(value = "组织架构树查询", notes = "组织架构树查询")
@ApiOperation(value = "组织架构树查询")
@GetMapping("/tree")
@PreAuthorize("@per.hasPermission('system:organization:read')")
public R<List<SysOrganizationTree>> getOrganizationTree(SysOrganizationQO qo) {
@@ -54,7 +47,7 @@ public class SysOrganizationController {
* @param sysOrganizationDTO 组织机构DTO
* @return R 通用返回体
*/
@ApiOperation(value = "新增组织架构", notes = "新增组织架构")
@ApiOperation(value = "新增组织架构")
@CreateOperationLogging(msg = "新增组织架构")
@PostMapping
@PreAuthorize("@per.hasPermission('system:organization:add')")
@@ -68,7 +61,7 @@ public class SysOrganizationController {
* @param sysOrganizationDTO 组织机构DTO
* @return R 通用返回体
*/
@ApiOperation(value = "修改组织架构", notes = "修改组织架构")
@ApiOperation(value = "修改组织架构")
@UpdateOperationLogging(msg = "修改组织架构")
@PutMapping
@PreAuthorize("@per.hasPermission('system:organization:edit')")
@@ -82,7 +75,7 @@ public class SysOrganizationController {
* @param id id
* @return R 通用返回体
*/
@ApiOperation(value = "通过id删除组织架构", notes = "通过id删除组织架构")
@ApiOperation(value = "通过id删除组织架构")
@DeleteOperationLogging(msg = "通过id删除组织架构")
@DeleteMapping("/{id}")
@PreAuthorize("@per.hasPermission('system:organization:del')")
@@ -91,4 +84,17 @@ public class SysOrganizationController {
: R.failed(BaseResultCode.UPDATE_DATABASE_ERROR, "通过id删除组织架构失败");
}
/**
* 校正组织机构层级和深度
* @return R 通用返回体
*/
@ApiOperation(value = "校正组织机构层级和深度")
@UpdateOperationLogging(msg = "校正组织机构层级和深度")
@PatchMapping("/revised")
@PreAuthorize("@per.hasPermission('system:organization:revised')")
public R<?> revisedHierarchyAndPath() {
return sysOrganizationService.revisedHierarchyAndPath() ? R.ok()
: R.failed(BaseResultCode.UPDATE_DATABASE_ERROR, "校正组织机构层级和深度失败");
}
}

View File

@@ -0,0 +1,43 @@
package com.hccake.ballcat.system.model.dto;
import lombok.Data;
/**
* 组织机构移动子节点时的参数封装对象
*
* @author hccake
*/
@Data
public class OrganizationMoveChildParam {
/**
* 父级id
*/
private Integer parentId;
/**
* 父级节点原始的层级信息
*/
private String originParentHierarchy;
/**
* 父级节点原始的层级信息长度 + 1
*/
private int originParentHierarchyLengthPlusOne;
/**
* 父级节点移动后的层级信息
*/
private String targetParentHierarchy;
/**
* 移动前后的节点深度差
*/
private Integer depthDiff;
/**
* 查询孙子节点的条件语句
*/
private String grandsonConditionalStatement;
}

View File

@@ -169,4 +169,7 @@ UPDATE `sys_menu` SET `title` = '访问日志查询' WHERE `id` = 110301;
RENAME TABLE `admin_access_log` TO `log_access_log`;
RENAME TABLE `admin_operation_log` TO `log_operation_log`;
RENAME TABLE `admin_login_log` TO `log_login_log`;
RENAME TABLE `admin_login_log` TO `log_login_log`;
-- 添加组织机构校正功能
INSERT INTO `sys_menu` (`id`, `parent_id`, `title`, `icon`, `permission`, `path`, `target_type`, `uri`, `sort`, `keep_alive`, `hidden`, `type`, `remarks`, `deleted`, `create_time`, `update_time`) VALUES (100705, 100700, '组织机构校正', NULL, 'system:organization:revised', NULL, 1, '', 5, 0, 0, 2, '校正组织机构层级和深度', 0, '2021-06-22 21:54:19', NULL);