From bffda7fbc0e98e3d46d9498726b4caffdc867305 Mon Sep 17 00:00:00 2001 From: zhansihu Date: Sun, 7 Apr 2024 14:40:23 +0800 Subject: [PATCH] =?UTF-8?q?feat(2227-syncFeature):=20feature=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/feign/FeatureResourceApi.java | 4 +- .../tyr/client/model/req/ResourceSyncReq.java | 32 +++++++ .../tyr/client/model/res/CommonDictResp.java | 15 ++++ .../model/res/FeatureResourceTreeNode.java | 4 + .../cn/axzo/tyr/server/TyrApplication.java | 49 ++++------ .../axzo/tyr/server/config/GlobalConfig.java | 7 +- .../permission/FeatureResourceController.java | 9 +- .../inner/feign/BaseFeatureResourceApi.java | 3 +- .../dao/SaasFeatureResourceDao.java | 4 + .../mapper/SaasFeatureResourceMapper.java | 6 ++ .../service/SaasFeatureResourceService.java | 3 +- .../impl/SaasFeatureResourceServiceImpl.java | 90 ++++++++++++++----- 12 files changed, 165 insertions(+), 61 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ResourceSyncReq.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/FeatureResourceApi.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/FeatureResourceApi.java index 8133f42a..d669b2c9 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/FeatureResourceApi.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/FeatureResourceApi.java @@ -1,12 +1,14 @@ package cn.axzo.tyr.client.feign; import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.tyr.client.model.req.ResourceSyncReq; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; +import javax.validation.Valid; import java.util.List; /** @@ -27,5 +29,5 @@ public interface FeatureResourceApi { /** 从基准环境同步接口功能资源 **/ @PostMapping("/api/featureResource/sync/fromBase") - ApiResult syncFromBase(@RequestBody List ids); + ApiResult syncFromBase(@RequestBody @Valid ResourceSyncReq req); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ResourceSyncReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ResourceSyncReq.java new file mode 100644 index 00000000..88e4c9c4 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ResourceSyncReq.java @@ -0,0 +1,32 @@ +package cn.axzo.tyr.client.model.req; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 功能资源同步请求 + * + * @version V1.0 + * @author: ZhanSiHu + * @date: 2024/4/7 11:31 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ResourceSyncReq { + + /** 同步资源ID **/ + @NotEmpty(message = "要同步的资源ID不能为空") + private List ids; + + /** 操作人personId **/ + @NotNull(message = "操作人ID不能为空") + private Long operatorId; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/CommonDictResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/CommonDictResp.java index a1d1c0b9..a53d2c5e 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/CommonDictResp.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/CommonDictResp.java @@ -17,4 +17,19 @@ import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor public class CommonDictResp { + + /** + * 业务域 + */ + private String scope; + + /** + * 字典编码 + */ + private String dictCode; + + /** + * 字典值 + */ + private String dictValue; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourceTreeNode.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourceTreeNode.java index 2104c4b7..73cf25c6 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourceTreeNode.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/FeatureResourceTreeNode.java @@ -1,6 +1,7 @@ package cn.axzo.tyr.client.model.res; import cn.axzo.basics.common.model.IBaseTree; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -23,16 +24,19 @@ public class FeatureResourceTreeNode extends FeatureResourceDTO implements IBase private List children; + @JsonIgnore @Override public Long getNodeCode() { return super.getId(); } + @JsonIgnore @Override public Long getParentNodeCode() { return super.getParentId(); } + @JsonIgnore @Override public List getNodeChildren() { return this.children; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/TyrApplication.java b/tyr-server/src/main/java/cn/axzo/tyr/server/TyrApplication.java index 3c1129e7..1247f100 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/TyrApplication.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/TyrApplication.java @@ -1,10 +1,7 @@ package cn.axzo.tyr.server; -import cn.axzo.tyr.server.job.CMSRoleJobHandler; -import cn.hutool.extra.spring.SpringUtil; import lombok.extern.slf4j.Slf4j; import org.mybatis.spring.annotation.MapperScan; -import cn.axzo.tyr.server.job.OMSRoleJobHandler; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @@ -15,7 +12,6 @@ import org.springframework.scheduling.annotation.EnableAsync; @Slf4j @EnableAsync @EnableDiscoveryClient -//@EnableFeignClients @MapperScan(value = {"cn.axzo.tyr.server.repository.mapper"}) @SpringBootApplication(scanBasePackages = "cn.axzo") public class TyrApplication { @@ -23,33 +19,22 @@ public class TyrApplication { ConfigurableApplicationContext run = SpringApplication.run(TyrApplication.class, args); Environment env = run.getEnvironment(); log.info( - "--------------------------------------------------------------------------------------------------------------------\n" + - "Application 【{}】 is running on 【{}】 environment!\n" + - "Api Local: \thttp://127.0.0.1:{}\n" + - "Mysql: \t{}\t username:{}\n" + - "Redis: \t{}:{}\t database:{}\n" + - "RabbitMQ: \t{}\t username:{}", - env.getProperty("spring.application.name"), - env.getProperty("spring.profiles.active"), - env.getProperty("server.port"), - env.getProperty("spring.datasource.url"), - env.getProperty("spring.datasource.username"), - env.getProperty("spring.redis.host"), - env.getProperty("spring.redis.port"), - env.getProperty("spring.redis.database"), - env.getProperty("spring.rabbitmq.addresses"), - env.getProperty("spring.rabbitmq.username") + - "\n----------------------------------------------------------"); - -// try { -// test(); -// } catch (Exception e) { -// e.printStackTrace(); -// } + "--------------------------------------------------------------------------------------------------------------------\n" + + "Application 【{}】 is running on 【{}】 environment!\n" + + "Api Local: \thttp://127.0.0.1:{}\n" + + "Mysql: \t{}\t username:{}\n" + + "Redis: \t{}:{}\t database:{}\n" + + "RabbitMQ: \t{}\t username:{}", + env.getProperty("spring.application.name"), + env.getProperty("spring.profiles.active"), + env.getProperty("server.port"), + env.getProperty("spring.datasource.url"), + env.getProperty("spring.datasource.username"), + env.getProperty("spring.redis.host"), + env.getProperty("spring.redis.port"), + env.getProperty("spring.redis.database"), + env.getProperty("spring.rabbitmq.addresses"), + env.getProperty("spring.rabbitmq.username") + + "\n----------------------------------------------------------"); } - -// public static void test() throws Exception { -// CMSRoleJobHandler executor = SpringUtil.getBean(CMSRoleJobHandler.class); -// executor.execute(null); -// } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/config/GlobalConfig.java b/tyr-server/src/main/java/cn/axzo/tyr/server/config/GlobalConfig.java index ac439b8f..a9aadbde 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/config/GlobalConfig.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/config/GlobalConfig.java @@ -17,15 +17,18 @@ import static cn.axzo.tyr.server.config.GlobalConfig.FeignClientConstant.*; */ @Configuration @EnableFeignClients(basePackages = { - WORKFLOW_ENGINE + WORKFLOW_ENGINE, + INNER_FEIGN }) public class GlobalConfig { /** * 第三方Feign */ - public class FeignClientConstant { + public static class FeignClientConstant { public static final String WORKFLOW_ENGINE = "cn.axzo.workflow.client.feign.bpmn"; + public static final String INNER_FEIGN = "cn.axzo.tyr.server.inner.feign"; + } /** diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/FeatureResourceController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/FeatureResourceController.java index 7e9dd883..42feafdd 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/FeatureResourceController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/FeatureResourceController.java @@ -2,6 +2,7 @@ package cn.axzo.tyr.server.controller.permission; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.feign.FeatureResourceApi; +import cn.axzo.tyr.client.model.req.ResourceSyncReq; import cn.axzo.tyr.client.model.res.FeatureResourceDTO; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; import cn.axzo.tyr.server.service.SaasFeatureResourceService; @@ -26,7 +27,7 @@ import java.util.List; @RequiredArgsConstructor public class FeatureResourceController implements FeatureResourceApi { - private SaasFeatureResourceService featureResourceService; + private final SaasFeatureResourceService featureResourceService; @Override public ApiResult> getSyncTreeById(Long id) { @@ -34,13 +35,13 @@ public class FeatureResourceController implements FeatureResourceApi { } @Override - public ApiResult syncFromBase(List ids) { + public ApiResult syncFromBase(ResourceSyncReq req) { - if (CollectionUtil.isEmpty(ids)) { + if (CollectionUtil.isEmpty(req.getIds())) { log.warn("no ids to sync from base env"); return ApiResult.ok(); } - featureResourceService.syncFromBase(ids); + featureResourceService.syncFromBase(req); return ApiResult.ok(); } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/inner/feign/BaseFeatureResourceApi.java b/tyr-server/src/main/java/cn/axzo/tyr/server/inner/feign/BaseFeatureResourceApi.java index 84787030..19ad14fb 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/inner/feign/BaseFeatureResourceApi.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/inner/feign/BaseFeatureResourceApi.java @@ -15,7 +15,8 @@ import java.util.List; * @author: ZhanSiHu * @date: 2024/4/3 10:25 */ -@FeignClient(name = "tyr", url = "${axzo.service.base.tyr:https://pre-api.axzo.cn/tyr}") +//@FeignClient(name = "tyr", url = "${axzo.service.base.tyr:https://pre-api.axzo.cn/tyr}") +@FeignClient(name = "tyr", url = "${axzo.service.base.tyr:http://127.0.0.1:8080}") public interface BaseFeatureResourceApi { diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java index 618cd184..e421cdc0 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java @@ -19,4 +19,8 @@ public class SaasFeatureResourceDao extends ServiceImpl @@ -13,4 +15,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; */ public interface SaasFeatureResourceMapper extends BaseMapper { + @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); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java index edbd3bd1..8855d645 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.server.service; +import cn.axzo.tyr.client.model.req.ResourceSyncReq; import cn.axzo.tyr.client.model.res.FeatureResourceDTO; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; @@ -16,5 +17,5 @@ public interface SaasFeatureResourceService { List getSyncTreeById(Long id); - void syncFromBase(List ids); + void syncFromBase(ResourceSyncReq req); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java index 3dd9373b..b6f9bd76 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java @@ -4,6 +4,7 @@ import cn.axzo.basics.common.BeanMapper; import cn.axzo.basics.common.util.TreeUtil; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.model.req.ResourceSyncReq; import cn.axzo.tyr.client.model.res.FeatureResourceDTO; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; import cn.axzo.tyr.server.inner.feign.BaseFeatureResourceApi; @@ -12,6 +13,7 @@ import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import cn.axzo.tyr.server.service.SaasFeatureResourceService; 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.springframework.stereotype.Service; @@ -56,7 +58,7 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic //如果是页面或应用入口-同时返回所有页面组件 if (FeatureResourceType.applyPage(resource.getFeatureType())) { List componentList = featureResourceDao.lambdaQuery() - .eq(SaasFeatureResource::getFeatureCode, FeatureResourceType.COMPONENT.getCode()) + .eq(SaasFeatureResource::getFeatureType, FeatureResourceType.COMPONENT.getCode()) .apply("FIND_IN_SET(" + id + ", path)") .list(); resourceList.addAll(componentList); @@ -66,40 +68,88 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic } @Override - public void syncFromBase(List ids) { - final Map idCache = new HashMap<>(); + public void syncFromBase(ResourceSyncReq req) { final Map codeCache = new ConcurrentHashMap<>(); - for (Long id : ids) { - doSyncFromBase(id, idCache, codeCache); + for (Long id : req.getIds()) { + //TODO:@Zhan 并发处理;同一个parent下同批查询 + //获取基准环境配置数据:同步某个ID的数据 需要同步处理它所有上级及下级组件 + List syncList = RpcInternalUtil.rpcProcessor(() -> baseFeatureResourceApi.getSyncTreeById(id), + "get base sync tree by id", id).getData(); + doSyncFromBase(syncList, codeCache, req.getOperatorId()); } } - private void doSyncFromBase(Long id, Map idCache, Map codeCache) { - if (codeCache.containsKey(id)) { - //已处理过 - log.info("already sync resource:{}", id); - return; - } - List syncList = RpcInternalUtil.rpcProcessor(() -> baseFeatureResourceApi.getSyncTreeById(id), - "get sync tree by id", id).getData(); + private void doSyncFromBase(List syncList, Map codeCache, Long operatorId) { + for (FeatureResourceTreeNode treeNode : syncList) { + if (codeCache.containsKey(treeNode.getId())) { + //已处理过 + log.info("already sync resource:{}", treeNode.getId()); + //递归子节点 + if (CollectionUtil.isNotEmpty(treeNode.getChildren())) { + doSyncFromBase(treeNode.getChildren(), codeCache, operatorId); + } + continue; + } + //缓存code + codeCache.put(treeNode.getId(), treeNode.getFeatureCode()); + + SaasFeatureResource baseResource = BeanMapper.copyBean(treeNode, SaasFeatureResource.class); + //修正数据 + String parentCode = codeCache.get(baseResource.getParentId()); + fixData(baseResource, parentCode); + SaasFeatureResource resource = featureResourceDao.getByCode(treeNode.getFeatureCode()); if (resource == null) { - syncInsert(treeNode, codeCache); + //新增 + baseResource.setCreateBy(operatorId); + baseResource.setUpdateBy(operatorId); + newResource(baseResource); } else { - syncUpdate(resource, treeNode); + //更新 + baseResource.setId(resource.getId()); + baseResource.setPath(baseResource.getPath() + "," + resource.getId()); + baseResource.setUpdateBy(operatorId); + 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())) { + doSyncFromBase(treeNode.getChildren(), codeCache, operatorId); } } } - private void syncUpdate(SaasFeatureResource resource, FeatureResourceTreeNode treeNode) { + /** 修正当前环境的数据 parentId path **/ + private void fixData(SaasFeatureResource resource, String parentCode) { + 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 syncInsert(FeatureResourceTreeNode treeNode, Map codeCache) { - SaasFeatureResource resource = BeanMapper.copyBean(treeNode, SaasFeatureResource.class); - //修正parent id 和path - String parentCode = codeCache.get(resource.getParentId()); + private void newResource(SaasFeatureResource resource) { + + featureResourceDao.save(resource); + //path追加自身ID + resource.setPath(resource.getPath() + "," + resource.getId()); + featureResourceDao.updateById(resource); } }