feat:(REQ-2393) 修改菜单的根节点到菜单表,修改path的生成和同步的逻辑

This commit is contained in:
lilong 2024-05-08 15:14:58 +08:00
parent db0a266e5f
commit eadc8d9f9f
5 changed files with 98 additions and 95 deletions

View File

@ -3,11 +3,15 @@ package cn.axzo.tyr.server.controller;
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
import cn.axzo.tyr.client.model.req.CommonDictQueryReq;
import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq;
import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq;
import cn.axzo.tyr.client.model.req.QuerySaasRoleGroupReq;
import cn.axzo.tyr.client.model.res.CommonDictResp;
import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode;
import cn.axzo.tyr.client.model.res.SaasRoleRes;
import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO;
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
import cn.axzo.tyr.server.repository.dao.SaasRoleGroupRelationDao;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import cn.axzo.tyr.server.repository.entity.SaasRole;
import cn.axzo.tyr.server.repository.entity.SaasRoleGroup;
import cn.axzo.tyr.server.repository.entity.SaasRoleGroupRelation;
@ -15,19 +19,23 @@ import cn.axzo.tyr.server.service.RoleService;
import cn.axzo.tyr.server.service.SaasCommonDictService;
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
import cn.axzo.tyr.server.service.SaasRoleGroupService;
import cn.axzo.tyr.server.service.impl.SaasFeatureResourceCacheService;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
@ -37,6 +45,7 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@Slf4j
@RestController
@RequiredArgsConstructor
public class PrivateController {
@ -51,6 +60,11 @@ public class PrivateController {
private RoleService roleService;
@Autowired
private SaasFeatureResourceService saasFeatureResourceService;
@Autowired
private SaasFeatureResourceDao saasFeatureResourceDao;
@Autowired
private SaasFeatureResourceCacheService saasFeatureResourceCacheService;
/**
* 统一层级的roleGroup按照id升序sort从1递增
@ -160,18 +174,73 @@ public class PrivateController {
return "ok";
}
// @PostMapping("/api/private/saasFeatureResourceRoot/create")
// public Object createFeatureResourceRoot(@RequestBody ) {
// FeatureResourceTreeSaveReq featureResourceTreeSaveReq = FeatureResourceTreeSaveReq.builder()
// .parentId(0L)
// .featureName(e.getDictValue())
// .featureType(FeatureResourceType.ROOT.getCode())
// .featureCode(e.getDictCode() + ":" + FeatureResourceType.ROOT.getDesc())
// .terminal(e.getDictCode())
// .operatorId()
// .build();
// saasFeatureResourceService.saveOrUpdateMenu(featureResourceTreeSaveReq);
// return "ok";
// }
@PostMapping("/api/private/saasFeatureResource/path/refresh")
public Object createFeatureResourceRoot(@Validated @RequestBody RefreshFeatureResourcePathParam request) {
GetFeatureResourceTreeReq getFeatureResourceTreeReq = GetFeatureResourceTreeReq.builder()
.terminals(Lists.newArrayList(request.getTerminal()))
.build();
List<FeatureResourceTreeNode> tree = saasFeatureResourceService.getTree(getFeatureResourceTreeReq);
if (CollectionUtils.isEmpty(tree)) {
log.info("not found featureResource,{}", request.getTerminal());
return "error";
}
FeatureResourceTreeNode root = tree.stream()
.filter(e -> Objects.equals(e.getId(), request.getRootId()))
.findFirst()
.orElse(null);
if (root == null) {
log.info("not found root,{}", request.getTerminal());
return "error";
}
SaasFeatureResource saasFeatureResource = new SaasFeatureResource();
saasFeatureResource.setId(root.getId());
saasFeatureResource.setParentId(0L);
saasFeatureResource.setPath(root.getId() + ",");
saasFeatureResourceDao.updateById(saasFeatureResource);
updateChildrenPath(root, tree);
saasFeatureResourceCacheService.clearCache();
return "ok";
}
private void updateChildrenPath(FeatureResourceTreeNode parent,
List<FeatureResourceTreeNode> featureResources) {
if (CollectionUtils.isEmpty(featureResources)) {
return;
}
List<FeatureResourceTreeNode> children = featureResources.stream()
.filter(e -> !Objects.equals(e.getId(), parent.getId()))
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(children)) {
return;
}
SaasFeatureResource parentFeatureResource = saasFeatureResourceDao.getById(parent.getId());
children.forEach(e -> {
SaasFeatureResource saasFeatureResource = new SaasFeatureResource();
saasFeatureResource.setId(e.getId());
saasFeatureResource.setParentId(parentFeatureResource.getId());
saasFeatureResource.setPath(parentFeatureResource.getPath() + e.getId() + ",");
saasFeatureResourceDao.updateById(saasFeatureResource);
updateChildrenPath(e, e.getChildren());
});
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class RefreshFeatureResourcePathParam {
@NotBlank(message = "terminal不能为空")
private String terminal;
@NotNull(message = "rootId不能为空")
private Long rootId;
}
}

View File

@ -4,7 +4,6 @@ import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum;
import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import cn.axzo.tyr.server.repository.mapper.SaasFeatureResourceMapper;
import cn.azxo.framework.common.utils.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Repository;
@ -27,9 +26,6 @@ public class SaasFeatureResourceDao extends ServiceImpl<SaasFeatureResourceMappe
return this.lambdaQuery().eq(SaasFeatureResource::getFeatureCode, featureCode).one();
}
public void replacePath(String oldPath, String newPath) {
this.baseMapper.replacePath(oldPath, newPath);
}
public List<SaasFeatureResource> getByResourceTreeParam(GetFeatureResourceTreeReq req) {
return this.lambdaQuery().select(SaasFeatureResource::getId, SaasFeatureResource::getFeatureCode,

View File

@ -2,8 +2,6 @@ package cn.axzo.tyr.server.repository.mapper;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
/**
* <p>
@ -15,8 +13,4 @@ import org.apache.ibatis.annotations.Update;
*/
public interface SaasFeatureResourceMapper extends BaseMapper<SaasFeatureResource> {
@Update("UPDATE saas_feature_resource" +
" SET path = REPLACE(path, #{oldPath}, #{newPath})" +
" WHERE is_delete = 0 AND path LIKE CONCAT(#{oldPath}, '%')")
void replacePath(@Param("oldPath") String oldPath, @Param("newPath") String newPath);
}

View File

@ -12,9 +12,9 @@ import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import cn.axzo.tyr.server.service.FeatureResourceSyncService;
import cn.axzo.tyr.server.util.RpcInternalUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@ -122,31 +122,28 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic
SaasFeatureResource baseResource = BeanMapper.copyBean(treeNode, SaasFeatureResource.class);
//修正数据
String parentCode = codeCache.get(baseResource.getParentId());
fixData(baseResource, parentCode);
SaasFeatureResource parent = StringUtils.isBlank(parentCode) ? null : featureResourceDao.getByCode(parentCode);
SaasFeatureResource resource = featureResourceDao.getByCode(treeNode.getFeatureCode());
if (resource == null) {
//新增
baseResource.setCreateBy(operatorId);
baseResource.setUpdateBy(operatorId);
newResource(baseResource);
newResource(baseResource, parent);
} else {
//更新 - 恢复不能变更的数据
baseResource.setId(resource.getId());
if (baseResource.getParentId() < 0) {
baseResource.setPath(resource.getId().toString());
// 当前节点是父节点
if (parent == null) {
baseResource.setPath(resource.getId().toString() + ",");
} else {
baseResource.setPath(baseResource.getPath() + "," + resource.getId());
baseResource.setPath(parent.getPath() + resource.getId() + ",");
}
baseResource.setUpdateBy(operatorId);
baseResource.setAppItemId(resource.getAppItemId());
featureResourceDao.updateById(baseResource);
if (!StrUtil.equals(baseResource.getPath(), resource.getPath())) {
//层级变化
log.info("replace path from old:{} to new:{}", resource.getPath(), baseResource.getPath());
featureResourceDao.replacePath(resource.getPath(), baseResource.getPath());
}
}
//递归子节点
if (CollectionUtil.isNotEmpty(treeNode.getChildren())) {
@ -155,38 +152,14 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic
}
}
/** 修正当前环境的数据 parentId path **/
private void fixData(SaasFeatureResource resource, String parentCode) {
// 原数据的parentId为负数表示是端下面的第一层数据此数据的path为当前数据的idparentId为原数据的parentId
if (resource.getParentId() < 0) {
resource.setParentId(resource.getParentId());
return;
}
if (StrUtil.isBlank(parentCode)) {
resource.setParentId(0L);
resource.setPath("0");
} else {
//找当前环境的parent
SaasFeatureResource parent = featureResourceDao.getByCode(parentCode);
if (parent == null) {
resource.setParentId(0L);
resource.setPath("0");
} else {
resource.setParentId(parent.getId());
resource.setPath(parent.getPath());
}
}
}
private void newResource(SaasFeatureResource resource) {
private void newResource(SaasFeatureResource resource, SaasFeatureResource parent) {
featureResourceDao.save(resource);
//path追加自身ID
if (resource.getParentId() < 0) {
resource.setPath(resource.getId().toString());
// 当前节点是父节点
if (parent == null) {
resource.setPath(resource.getId().toString() + ",");
} else {
resource.setPath(resource.getPath() + "," + resource.getId());
resource.setPath(parent.getPath() + resource.getId() + ",");
}
featureResourceDao.updateById(resource);

View File

@ -3,18 +3,14 @@ package cn.axzo.tyr.server.service.impl;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.basics.common.util.StopWatchUtil;
import cn.axzo.basics.common.util.TreeUtil;
import cn.axzo.framework.domain.web.BizException;
import cn.axzo.framework.domain.web.code.BaseCode;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.pokonyan.config.redis.RedisClient;
import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType;
import cn.axzo.tyr.client.common.enums.FeatureResourceStatus;
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
import cn.axzo.tyr.client.model.req.CommonDictQueryReq;
import cn.axzo.tyr.client.model.req.FeatureComponentSaveReq;
import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq;
import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq;
import cn.axzo.tyr.client.model.res.CommonDictResp;
import cn.axzo.tyr.client.model.res.FeatureResourceDTO;
import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode;
import cn.axzo.tyr.server.common.util.Throws;
@ -23,16 +19,13 @@ import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO;
import cn.axzo.tyr.server.model.convert.SaasFeatureResourceConvert;
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import cn.axzo.tyr.server.service.RoleService;
import cn.axzo.tyr.server.service.SaasCommonDictService;
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService;
import cn.azxo.framework.common.utils.StringUtils;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
@ -46,15 +39,9 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.axzo.framework.domain.web.code.BaseCode.BAD_REQUEST;
import static cn.axzo.framework.domain.web.code.BaseCode.SERVER_ERROR;
import static cn.axzo.tyr.server.common.constants.CacheConstant.KEY_AUTH_FREE;
/**
* 功能资源服务实现
* 功能资源树查询增加了redis缓存在新增修改该表时记得清空缓存
@ -121,17 +108,6 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic
@Override
public List<FeatureResourceTreeNode> getTree(GetFeatureResourceTreeReq req) {
// List<CommonDictResp> commonDictResponses = saasCommonDictService.query(CommonDictQueryReq.builder().scope(RESOURCE_TERMINAL_SCOPE).build());
// if (CollectionUtils.isEmpty(commonDictResponses)) {
// log.error("not config resource terminal in saas_common_dict table");
// return Collections.emptyList();
// }
// final AtomicLong rootIdIndex = new AtomicLong(0L);
// List<FeatureResourceTreeNode> rootNodes = commonDictResponses.stream().map(e -> FeatureResourceTreeNode.builder()
// .id(rootIdIndex.decrementAndGet()).terminal(e.getDictCode()).featureName(e.getDictValue())
// .featureCode(e.getDictCode()).featureType(-1).children(Lists.newArrayList()).build()).collect(Collectors.toList());
StopWatchUtil watch = StopWatchUtil.createStarted("feature-resource-tree");
watch.start("dbQuery");
List<SaasFeatureResource> saasFeatureResources = saasFeatureResourceCacheService.getByResourceTreeParam(req);
@ -144,18 +120,12 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic
.map(this::featureResource2Node)
.sorted(Comparator.comparing(FeatureResourceDTO::getDisplayOrder))
.collect(Collectors.toList()));
saasFeatureResources = null; // help GC
//搜索或需要按授权策略过滤 - 有额外的过滤条件
watch.start("filter-node");
List<FeatureResourceTreeNode> resultNode = filterTreeNode(req.getKeyword(), treeList);
watch.stop();
//把处理后的树结构添加上根节点
// watch.start("fill-children-to-root");
// List<FeatureResourceTreeNode> resultNode = fillChildren2Root(rootNodes, filterResultNode);
// watch.stop();
log.info("feature-resource-tree cost:{} , ms:{}", watch.prettyPrint(), watch.getTotalTimeMillis());
return resultNode;
}
@ -234,7 +204,8 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic
private void newResource(SaasFeatureResource resource, String parentPath) {
featureResourceDao.save(resource);
//path追加自身ID
resource.setPath(StringUtils.isBlank(parentPath) ? resource.getId().toString() : parentPath + "," + resource.getId());
// path增加","后缀方便后续查询所有子节点
resource.setPath(StringUtils.isBlank(parentPath) ? resource.getId().toString() + "," : parentPath + resource.getId() + ",");
featureResourceDao.updateById(resource);
}