|
@@ -13,6 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import javax.annotation.PostConstruct;
|
|
|
import java.util.*;
|
|
|
+import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
import java.util.concurrent.locks.ReadWriteLock;
|
|
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|
|
import java.util.stream.Collectors;
|
|
@@ -32,7 +33,6 @@ public class AuthOrgTreeServiceImpl implements IAuthOrgTreeService {
|
|
|
|
|
|
/**
|
|
|
* holder不能对外暴露
|
|
|
- * 通过holder获取的树节点不允许调用set方法修改树节点的属性值
|
|
|
* 接口给出去的对象使用拷贝后的对象,不要破坏树节点的内部结构
|
|
|
* 在使用holder时尽量只获取一次,然后都使用获取到的引用。可以避免在一个方法中多次获取树结构,而树结构又被重新构建导致数据不一致的情况
|
|
|
*/
|
|
@@ -47,175 +47,119 @@ public class AuthOrgTreeServiceImpl implements IAuthOrgTreeService {
|
|
|
|
|
|
@Override
|
|
|
public List<OrgTreeNodeDTO> getChildById(String id, Integer level) {
|
|
|
- if(StringUtils.isBlank(id)) {
|
|
|
- return deepCopy(holder.getTopNodesList());
|
|
|
- } else {
|
|
|
- Map<String, OrgTreeNodeDTO> treeNodeMap = holder.getTreeNodeMap();
|
|
|
- OrgTreeNodeDTO dto = treeNodeMap.get(id);
|
|
|
- if(null == dto) {
|
|
|
- return new ArrayList<>();
|
|
|
- }
|
|
|
- Set<String> childIds = getAllChildIds(id, treeNodeMap, level);
|
|
|
- if(CollectionUtils.isEmpty(childIds)) {
|
|
|
- return new ArrayList<>();
|
|
|
- }
|
|
|
- List<OrgTreeNodeDTO> collect = childIds
|
|
|
- .stream()
|
|
|
- .map(treeNodeMap::get)
|
|
|
- .collect(Collectors.toList());
|
|
|
- return deepCopy(collect);
|
|
|
- }
|
|
|
+ return holder.getChildById(id, level);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public List<OrgTreeNodeDTO> getSelfAndChildByIds(List<String> orgIds) {
|
|
|
- if(CollectionUtils.isEmpty(orgIds)) {
|
|
|
- return new ArrayList<>();
|
|
|
- }
|
|
|
- Map<String, OrgTreeNodeDTO> treeNodeMap = holder.getTreeNodeMap();
|
|
|
- List<OrgTreeNodeDTO> selfNodes = orgIds.stream().map(treeNodeMap::get).collect(Collectors.toList());
|
|
|
- List<OrgTreeNodeDTO> collect = selfNodes
|
|
|
- .stream()
|
|
|
- .map(OrgTreeNodeDTO::getChildIds)
|
|
|
- .flatMap(List::stream)
|
|
|
- .distinct()
|
|
|
- .map(treeNodeMap::get)
|
|
|
- .collect(Collectors.toList());
|
|
|
- selfNodes.addAll(collect);
|
|
|
- return deepCopy(selfNodes);
|
|
|
+ return holder.getSelfAndChildByIds(orgIds);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public List<OrgTreeNodeDTO> getAllChildNodes(String orgId) {
|
|
|
- if(StringUtils.isBlank(orgId)) {
|
|
|
- return new ArrayList<>();
|
|
|
- }
|
|
|
- Map<String, OrgTreeNodeDTO> treeNodeMap = holder.getTreeNodeMap();
|
|
|
- Set<String> allChildIds = getAllChildIds(orgId, treeNodeMap, null);
|
|
|
- return getOrgTreeNodeByIds(allChildIds);
|
|
|
+ return holder.getAllChildNodes(orgId);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public OrgTreeNodeDTO getOrgTreeNode(String id) {
|
|
|
- if(StringUtils.isBlank(id)) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- Map<String, OrgTreeNodeDTO> treeNodeMap = holder.getTreeNodeMap();
|
|
|
- OrgTreeNodeDTO orgTreeNodeDTO = treeNodeMap.get(id);
|
|
|
- if(null == orgTreeNodeDTO) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- return deepCopy(orgTreeNodeDTO);
|
|
|
+ return holder.getOrgTreeNode(id);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public List<OrgTreeNodeDTO> getOrgTreeNodeByIds(Collection<String> ids) {
|
|
|
- if(CollectionUtils.isEmpty(ids)) {
|
|
|
- return new ArrayList<>();
|
|
|
- }
|
|
|
- Map<String, OrgTreeNodeDTO> treeNodeMap = holder.getTreeNodeMap();
|
|
|
- List<OrgTreeNodeDTO> collect = ids
|
|
|
- .stream()
|
|
|
- .map(treeNodeMap::get)
|
|
|
- .collect(Collectors.toList());
|
|
|
-
|
|
|
- return deepCopy(collect);
|
|
|
+ return holder.getOrgTreeNodeByIds(ids);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Set<String> getAllMtOrgIds(String mtIds) {
|
|
|
- Set<String> resultSet = new HashSet<>();
|
|
|
- String[] mtIdStrs = mtIds.split(",");
|
|
|
- Map<String, OrgTreeNodeDTO> treeNodeMap = holder.getTreeNodeMap();
|
|
|
- for (String mtIdStr : mtIdStrs) {
|
|
|
- if (mtIdStr.contains(":")) {
|
|
|
- String[] split = mtIdStr.split(":");
|
|
|
- String orgId = split[0];
|
|
|
- resultSet.add(orgId);
|
|
|
- int rang = Integer.parseInt(split[1]);
|
|
|
- //1 半选 2 全选
|
|
|
- if (rang == 2) {
|
|
|
- Set<String> allChildIds = getAllChildIds(orgId, treeNodeMap, null);
|
|
|
- resultSet.addAll(allChildIds);
|
|
|
- }
|
|
|
- } else {
|
|
|
- resultSet.add(mtIdStr);
|
|
|
- }
|
|
|
- }
|
|
|
- return resultSet;
|
|
|
+ return holder.getAllMtOrgIds(mtIds);
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 获取机构下的子机构节点id
|
|
|
- * @param orgId 机构id
|
|
|
- * @param treeNodeMap 机构树map
|
|
|
- * @param level 深度(从该机构节点算起)。需要所有子节点id,传入null
|
|
|
- * @return
|
|
|
- */
|
|
|
- private Set<String> getAllChildIds(String orgId, Map<String, OrgTreeNodeDTO> treeNodeMap, Integer level) {
|
|
|
- Set<String> childIds = new HashSet<>();
|
|
|
- OrgTreeNodeDTO orgTreeNodeDTO = treeNodeMap.get(orgId);
|
|
|
- if(null == orgTreeNodeDTO) {
|
|
|
- return childIds;
|
|
|
- }
|
|
|
- if(CollectionUtils.isEmpty(orgTreeNodeDTO.getChildIds())) {
|
|
|
- return childIds;
|
|
|
- }
|
|
|
- //初始化双端队列
|
|
|
- Deque<OrgTreeNodeDTO> deque = new LinkedList<>();
|
|
|
- deque.add(orgTreeNodeDTO);
|
|
|
-
|
|
|
- //初始化深度计算指针
|
|
|
- int currentLevelIndex = deque.size();
|
|
|
- int currentNodeIndex = 0;
|
|
|
-
|
|
|
- while (!deque.isEmpty()) {
|
|
|
- //往双端队列中添加下一层的子节点
|
|
|
- OrgTreeNodeDTO node = deque.pollFirst();
|
|
|
- List<String> nodeChildIds = node.getChildIds();
|
|
|
- if(CollectionUtils.isNotEmpty(nodeChildIds)) {
|
|
|
- childIds.addAll(nodeChildIds);
|
|
|
- List<OrgTreeNodeDTO> childNodes = nodeChildIds
|
|
|
- .stream()
|
|
|
- .map(treeNodeMap::get)
|
|
|
- .collect(Collectors.toList());
|
|
|
- deque.addAll(childNodes);
|
|
|
- }
|
|
|
- //判断是否达到深度
|
|
|
- if(null != level && ++currentNodeIndex == currentLevelIndex) {
|
|
|
- --level;
|
|
|
- if(level == 0) {
|
|
|
- break;
|
|
|
- }
|
|
|
- //重置index
|
|
|
- currentNodeIndex = 0;
|
|
|
- currentLevelIndex = deque.size();
|
|
|
- }
|
|
|
+ @Override
|
|
|
+ public void reInitTrees(boolean async) {
|
|
|
+ Runnable runnable = ()-> holder.init();
|
|
|
+ if(async) {
|
|
|
+ Thread thread = new Thread(runnable);
|
|
|
+ thread.start();
|
|
|
+ } else {
|
|
|
+ runnable.run();
|
|
|
}
|
|
|
- return childIds;
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public void reInitTrees() {
|
|
|
- holder.init();
|
|
|
+ public void updateTreeByCode(List<String> updateOrgCodes, boolean async) {
|
|
|
+ Runnable runnable = ()-> updateTask(updateOrgCodes);
|
|
|
+ if(async) {
|
|
|
+ Thread thread = new Thread(runnable);
|
|
|
+ thread.start();
|
|
|
+ } else {
|
|
|
+ runnable.run();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- private OrgTreeNodeDTO deepCopy(OrgTreeNodeDTO orgTreeNodeDTO) {
|
|
|
- OrgTreeNodeDTO dto = new OrgTreeNodeDTO();
|
|
|
- BeanUtils.copyProperties(orgTreeNodeDTO, dto);
|
|
|
- dto.setChildIds(new ArrayList<>(orgTreeNodeDTO.getChildIds()));
|
|
|
- return dto;
|
|
|
- }
|
|
|
+ private void updateTask(List<String> updateOrgCodes) {
|
|
|
+ List<AuthOrgInfo> updateOrgInfos = authOrgInfoService.getOrgByCodes(updateOrgCodes);
|
|
|
+ Set<String> existOrgCodes = updateOrgInfos.stream().map(AuthOrgInfo::getCode).collect(Collectors.toSet());
|
|
|
+ //构建需要更新的树节点
|
|
|
+ List<OrgTreeNodeDTO> treeNods = getTreeNods(updateOrgInfos);
|
|
|
|
|
|
- private List<OrgTreeNodeDTO> deepCopy(List<OrgTreeNodeDTO> list) {
|
|
|
- return Optional.ofNullable(list)
|
|
|
- .orElse(new ArrayList<>())
|
|
|
+ List<AuthOrgInfo> childInfos = authOrgInfoService.getChildByCodes(updateOrgCodes);
|
|
|
+ Map<String, List<AuthOrgInfo>> childIdGroup = childInfos
|
|
|
.stream()
|
|
|
- .map(this::deepCopy).collect(Collectors.toList());
|
|
|
+ .collect(Collectors.groupingBy(AuthOrgInfo::getUpGovId));
|
|
|
+
|
|
|
+ treeNods.forEach(e->{
|
|
|
+ List<AuthOrgInfo> list = childIdGroup.get(e.getId());
|
|
|
+ List<String> collect = list.stream()
|
|
|
+ .sorted(Comparator.comparing(AuthOrgInfo::getSort,
|
|
|
+ Comparator.nullsLast(Integer::compareTo)))
|
|
|
+ .map(AuthOrgInfo::getId).collect(Collectors.toList());
|
|
|
+ if(CollectionUtils.isEmpty(collect)) {
|
|
|
+ e.setIsParent(false);
|
|
|
+ e.setChildIds(Collections.emptyList());
|
|
|
+ } else {
|
|
|
+ e.setIsParent(true);
|
|
|
+ e.setChildIds(collect);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ //过滤删除的机构
|
|
|
+ List<String> delCodes = updateOrgCodes.stream()
|
|
|
+ .filter(e -> !existOrgCodes.contains(e))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ holder.updateTreeNodes(treeNods, delCodes);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将机构数据转为树节点对象
|
|
|
+ * @param orgInfos 机构信息
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private List<OrgTreeNodeDTO> getTreeNods(List<AuthOrgInfo> orgInfos) {
|
|
|
+ return orgInfos.stream().map(e -> {
|
|
|
+ OrgTreeNodeDTO nodeDTO = new OrgTreeNodeDTO();
|
|
|
+ nodeDTO.setId(e.getId());
|
|
|
+ nodeDTO.setName(e.getFullName());
|
|
|
+ nodeDTO.setCode(e.getCode());
|
|
|
+ nodeDTO.setPid(e.getUpGovId());
|
|
|
+ nodeDTO.setPath(e.getPath());
|
|
|
+ nodeDTO.setOrgLevel(e.getOrgLevel());
|
|
|
+ nodeDTO.setOrgType(e.getOrgType());
|
|
|
+ nodeDTO.setOrgKind(e.getOrgKind());
|
|
|
+ nodeDTO.setOrgRank(e.getOrgRank());
|
|
|
+ nodeDTO.setUnitClass(e.getUnitClass());
|
|
|
+ nodeDTO.setSort(e.getSort());
|
|
|
+ return nodeDTO;
|
|
|
+ }).collect(Collectors.toList());
|
|
|
}
|
|
|
|
|
|
private class AuthOrgTreeHolder {
|
|
|
|
|
|
+ /**
|
|
|
+ * 全量构建树标识
|
|
|
+ * true 正在构建中 false 未在构建中
|
|
|
+ */
|
|
|
+ private volatile AtomicBoolean initIng = new AtomicBoolean(false);
|
|
|
+
|
|
|
/**
|
|
|
* 深度为1的树节点map
|
|
|
* childIds字段只存子节点id
|
|
@@ -223,6 +167,13 @@ public class AuthOrgTreeServiceImpl implements IAuthOrgTreeService {
|
|
|
*/
|
|
|
private volatile Map<String, OrgTreeNodeDTO> treeNodeMap;
|
|
|
|
|
|
+ /**
|
|
|
+ * 树节点id和code对应值Map
|
|
|
+ * 便于根据code值操作树节点
|
|
|
+ * key:orgCode value:orgId
|
|
|
+ */
|
|
|
+ private volatile Map<String, OrgTreeNodeDTO> codeIdMap;
|
|
|
+
|
|
|
/**
|
|
|
* 所有顶级节点
|
|
|
*/
|
|
@@ -234,6 +185,20 @@ public class AuthOrgTreeServiceImpl implements IAuthOrgTreeService {
|
|
|
*/
|
|
|
private ReadWriteLock lock = new ReentrantReadWriteLock();
|
|
|
|
|
|
+ private OrgTreeNodeDTO deepCopy(OrgTreeNodeDTO orgTreeNodeDTO) {
|
|
|
+ OrgTreeNodeDTO dto = new OrgTreeNodeDTO();
|
|
|
+ BeanUtils.copyProperties(orgTreeNodeDTO, dto);
|
|
|
+ dto.setChildIds(new ArrayList<>(orgTreeNodeDTO.getChildIds()));
|
|
|
+ return dto;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<OrgTreeNodeDTO> deepCopy(List<OrgTreeNodeDTO> list) {
|
|
|
+ return Optional.ofNullable(list)
|
|
|
+ .orElse(new ArrayList<>())
|
|
|
+ .stream()
|
|
|
+ .map(this::deepCopy).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 构建树结构
|
|
|
* @param treeNodeMap
|
|
@@ -259,28 +224,6 @@ public class AuthOrgTreeServiceImpl implements IAuthOrgTreeService {
|
|
|
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 将机构数据转为树节点对象
|
|
|
- * @param orgInfos 机构信息
|
|
|
- * @return
|
|
|
- */
|
|
|
- private List<OrgTreeNodeDTO> getTreeNods(List<AuthOrgInfo> orgInfos) {
|
|
|
- return orgInfos.stream().map(e -> {
|
|
|
- OrgTreeNodeDTO nodeDTO = new OrgTreeNodeDTO();
|
|
|
- nodeDTO.setId(e.getId());
|
|
|
- nodeDTO.setName(e.getFullName());
|
|
|
- nodeDTO.setCode(e.getCode());
|
|
|
- nodeDTO.setPid(e.getUpGovId());
|
|
|
- nodeDTO.setPath(e.getPath());
|
|
|
- nodeDTO.setOrgLevel(e.getOrgLevel());
|
|
|
- nodeDTO.setOrgType(e.getOrgType());
|
|
|
- nodeDTO.setOrgKind(e.getOrgKind());
|
|
|
- nodeDTO.setOrgRank(e.getOrgRank());
|
|
|
- nodeDTO.setUnitClass(e.getUnitClass());
|
|
|
- return nodeDTO;
|
|
|
- }).collect(Collectors.toList());
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* 将树节点组装成深度为1的树结构
|
|
|
* 子节点只保留id集合
|
|
@@ -301,11 +244,13 @@ public class AuthOrgTreeServiceImpl implements IAuthOrgTreeService {
|
|
|
List<OrgTreeNodeDTO> childNodes = upIdGroupMap.get(headNode.getId());
|
|
|
if(CollectionUtils.isEmpty(childNodes)) {
|
|
|
headNode.setIsParent(false);
|
|
|
- headNode.setChildIds(ListUtils.EMPTY_LIST);
|
|
|
+ headNode.setChildIds(Collections.emptyList());
|
|
|
} else {
|
|
|
headNode.setIsParent(true);
|
|
|
List<String> childIds = childNodes
|
|
|
.stream()
|
|
|
+ .sorted(Comparator.comparing(OrgTreeNodeDTO::getSort,
|
|
|
+ Comparator.nullsLast(Integer::compareTo)))
|
|
|
.map(OrgTreeNodeDTO::getId)
|
|
|
.distinct()
|
|
|
.collect(Collectors.toList());
|
|
@@ -316,46 +261,246 @@ public class AuthOrgTreeServiceImpl implements IAuthOrgTreeService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- Map<String, OrgTreeNodeDTO> getTreeNodeMap() {
|
|
|
+ /**
|
|
|
+ * 初始化
|
|
|
+ */
|
|
|
+ void init() {
|
|
|
+ try {
|
|
|
+ //cas减少并发量
|
|
|
+ boolean init = initIng.compareAndSet(false, true);
|
|
|
+ if (!init) {
|
|
|
+ log.info("cas set fail");
|
|
|
+ return ;
|
|
|
+ }
|
|
|
+ Map<String, OrgTreeNodeDTO> orgMap = new HashMap<>();
|
|
|
+ List<OrgTreeNodeDTO> orgList = new ArrayList<>();
|
|
|
+ initIng.getAndSet(false);
|
|
|
+
|
|
|
+ //锁控制数据一致
|
|
|
+ lock.writeLock().lock();
|
|
|
+ constructTrees(orgMap, orgList);
|
|
|
+ treeNodeMap = orgMap;
|
|
|
+ topNodesList = orgList;
|
|
|
+ codeIdMap = orgList
|
|
|
+ .stream()
|
|
|
+ .collect(Collectors.toMap(OrgTreeNodeDTO::getCode, e->e, (old, last)-> last));
|
|
|
+ }catch (Exception e) {
|
|
|
+ log.error("reInitTree error.", e);
|
|
|
+ } finally {
|
|
|
+ lock.writeLock().unlock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void updateTreeNodes(List<OrgTreeNodeDTO> treeNods, List<String> delCodes) {
|
|
|
+ try {
|
|
|
+ lock.writeLock().lock();
|
|
|
+ treeNods.forEach(e->{
|
|
|
+ treeNodeMap.put(e.getId(), e);
|
|
|
+ codeIdMap.put(e.getCode(), e);
|
|
|
+ });
|
|
|
+ delCodes.forEach(e->{
|
|
|
+ OrgTreeNodeDTO node = codeIdMap.remove(e);
|
|
|
+ if(null != node) {
|
|
|
+ treeNodeMap.remove(node.getId());
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }catch (Exception e) {
|
|
|
+ log.error("updateTreeNodes error.", e);
|
|
|
+ } finally {
|
|
|
+ lock.writeLock().unlock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<OrgTreeNodeDTO> getChildById(String id, Integer level) {
|
|
|
+ try {
|
|
|
+ lock.readLock().lock();
|
|
|
+ if(StringUtils.isBlank(id)) {
|
|
|
+ return deepCopy(this.topNodesList);
|
|
|
+ } else {
|
|
|
+ Map<String, OrgTreeNodeDTO> treeNodeMap = this.treeNodeMap;
|
|
|
+ OrgTreeNodeDTO dto = treeNodeMap.get(id);
|
|
|
+ if(null == dto) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+ Set<String> childIds = getAllChildIds(id, treeNodeMap, level);
|
|
|
+ if(CollectionUtils.isEmpty(childIds)) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+ List<OrgTreeNodeDTO> collect = childIds
|
|
|
+ .stream()
|
|
|
+ .map(treeNodeMap::get)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ return deepCopy(collect);
|
|
|
+ }
|
|
|
+ }catch (Exception e) {
|
|
|
+ log.error("updateTreeNodes error.", e);
|
|
|
+ return Collections.emptyList();
|
|
|
+ } finally {
|
|
|
+ lock.readLock().unlock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<OrgTreeNodeDTO> getAllChildNodes(String orgId) {
|
|
|
+ try {
|
|
|
+ lock.readLock().lock();
|
|
|
+ if(StringUtils.isBlank(orgId)) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ Map<String, OrgTreeNodeDTO> treeNodeMap = this.treeNodeMap;
|
|
|
+ Set<String> allChildIds = getAllChildIds(orgId, treeNodeMap, null);
|
|
|
+ return getOrgTreeNodeByIds(allChildIds);
|
|
|
+ }catch (Exception e) {
|
|
|
+ log.error("getAllChildNodes error.", e);
|
|
|
+ return Collections.emptyList();
|
|
|
+ }finally {
|
|
|
+ lock.readLock().unlock();
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<OrgTreeNodeDTO> getSelfAndChildByIds(List<String> orgIds) {
|
|
|
try {
|
|
|
lock.readLock().lock();
|
|
|
- return treeNodeMap;
|
|
|
+ if(CollectionUtils.isEmpty(orgIds)) {
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ Map<String, OrgTreeNodeDTO> treeNodeMap = this.treeNodeMap;
|
|
|
+ List<OrgTreeNodeDTO> selfNodes = orgIds.stream().map(treeNodeMap::get).collect(Collectors.toList());
|
|
|
+ List<OrgTreeNodeDTO> collect = selfNodes
|
|
|
+ .stream()
|
|
|
+ .map(OrgTreeNodeDTO::getChildIds)
|
|
|
+ .flatMap(List::stream)
|
|
|
+ .distinct()
|
|
|
+ .map(treeNodeMap::get)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ selfNodes.addAll(collect);
|
|
|
+ return deepCopy(selfNodes);
|
|
|
} catch (Exception e) {
|
|
|
- log.error("getTreeNodeMap error.", e);
|
|
|
- return null;
|
|
|
+ log.error("getSelfAndChildByIds error.", e);
|
|
|
+ return Collections.emptyList();
|
|
|
} finally {
|
|
|
lock.readLock().unlock();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- List<OrgTreeNodeDTO> getTopNodesList() {
|
|
|
+ private OrgTreeNodeDTO getOrgTreeNode(String id) {
|
|
|
try {
|
|
|
lock.readLock().lock();
|
|
|
- return topNodesList;
|
|
|
+ if(StringUtils.isBlank(id)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ Map<String, OrgTreeNodeDTO> treeNodeMap = this.treeNodeMap;
|
|
|
+ OrgTreeNodeDTO orgTreeNodeDTO = treeNodeMap.get(id);
|
|
|
+ if(null == orgTreeNodeDTO) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return deepCopy(orgTreeNodeDTO);
|
|
|
}catch (Exception e) {
|
|
|
- log.error("getTreeNodeMap error.", e);
|
|
|
+ log.error("getOrgTreeNode error.", e);
|
|
|
return null;
|
|
|
}finally {
|
|
|
lock.readLock().unlock();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 初始化
|
|
|
- */
|
|
|
- void init() {
|
|
|
- Map<String, OrgTreeNodeDTO> orgMap = new HashMap<>();
|
|
|
- List<OrgTreeNodeDTO> orgList = new ArrayList<>();
|
|
|
- constructTrees(orgMap, orgList);
|
|
|
+ private List<OrgTreeNodeDTO> getOrgTreeNodeByIds(Collection<String> ids) {
|
|
|
try {
|
|
|
- lock.writeLock().lock();
|
|
|
- treeNodeMap = orgMap;
|
|
|
- topNodesList = orgList;
|
|
|
+ lock.readLock().lock();
|
|
|
+ if(CollectionUtils.isEmpty(ids)) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+ Map<String, OrgTreeNodeDTO> treeNodeMap = this.treeNodeMap;
|
|
|
+ List<OrgTreeNodeDTO> collect = ids
|
|
|
+ .stream()
|
|
|
+ .map(treeNodeMap::get)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ return deepCopy(collect);
|
|
|
}catch (Exception e) {
|
|
|
- log.error("reInitTree error.", e);
|
|
|
- } finally {
|
|
|
- lock.writeLock().unlock();
|
|
|
+ log.error("getOrgTreeNode error.", e);
|
|
|
+ return Collections.emptyList();
|
|
|
+ }finally {
|
|
|
+ lock.readLock().unlock();
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private Set<String> getAllMtOrgIds(String mtIds) {
|
|
|
+ try {
|
|
|
+ lock.readLock().lock();
|
|
|
+ Set<String> resultSet = new HashSet<>();
|
|
|
+ String[] mtIdStrs = mtIds.split(",");
|
|
|
+ Map<String, OrgTreeNodeDTO> treeNodeMap = this.treeNodeMap;
|
|
|
+ for (String mtIdStr : mtIdStrs) {
|
|
|
+ if (mtIdStr.contains(":")) {
|
|
|
+ String[] split = mtIdStr.split(":");
|
|
|
+ String orgId = split[0];
|
|
|
+ resultSet.add(orgId);
|
|
|
+ int rang = Integer.parseInt(split[1]);
|
|
|
+ //1 半选 2 全选
|
|
|
+ if (rang == 2) {
|
|
|
+ Set<String> allChildIds = getAllChildIds(orgId, treeNodeMap, null);
|
|
|
+ resultSet.addAll(allChildIds);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ resultSet.add(mtIdStr);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return resultSet;
|
|
|
+ }catch (Exception e) {
|
|
|
+ return Collections.emptySet();
|
|
|
+ }finally {
|
|
|
+ lock.readLock().unlock();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取机构下的子机构节点id
|
|
|
+ * @param orgId 机构id
|
|
|
+ * @param treeNodeMap 机构树map
|
|
|
+ * @param level 深度(从该机构节点算起)。需要所有子节点id,传入null
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Set<String> getAllChildIds(String orgId, Map<String, OrgTreeNodeDTO> treeNodeMap, Integer level) {
|
|
|
+ Set<String> childIds = new HashSet<>();
|
|
|
+ OrgTreeNodeDTO orgTreeNodeDTO = treeNodeMap.get(orgId);
|
|
|
+ if(null == orgTreeNodeDTO) {
|
|
|
+ return childIds;
|
|
|
+ }
|
|
|
+ if(CollectionUtils.isEmpty(orgTreeNodeDTO.getChildIds())) {
|
|
|
+ return childIds;
|
|
|
+ }
|
|
|
+ //初始化双端队列
|
|
|
+ Deque<OrgTreeNodeDTO> deque = new LinkedList<>();
|
|
|
+ deque.add(orgTreeNodeDTO);
|
|
|
+
|
|
|
+ //初始化深度计算指针
|
|
|
+ int currentLevelIndex = deque.size();
|
|
|
+ int currentNodeIndex = 0;
|
|
|
+
|
|
|
+ while (!deque.isEmpty()) {
|
|
|
+ //往双端队列中添加下一层的子节点
|
|
|
+ OrgTreeNodeDTO node = deque.pollFirst();
|
|
|
+ List<String> nodeChildIds = node.getChildIds();
|
|
|
+ if(CollectionUtils.isNotEmpty(nodeChildIds)) {
|
|
|
+ childIds.addAll(nodeChildIds);
|
|
|
+ List<OrgTreeNodeDTO> childNodes = nodeChildIds
|
|
|
+ .stream()
|
|
|
+ .map(treeNodeMap::get)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ deque.addAll(childNodes);
|
|
|
+ }
|
|
|
+ //判断是否达到深度
|
|
|
+ if(null != level && ++currentNodeIndex == currentLevelIndex) {
|
|
|
+ --level;
|
|
|
+ if(level == 0) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ //重置index
|
|
|
+ currentNodeIndex = 0;
|
|
|
+ currentLevelIndex = deque.size();
|
|
|
+ }
|
|
|
}
|
|
|
+ return childIds;
|
|
|
}
|
|
|
}
|
|
|
}
|