feat(2227-syncFeature): feature同步实现
This commit is contained in:
parent
6cf46dba73
commit
bffda7fbc0
@ -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<Void> syncFromBase(@RequestBody List<Long> ids);
|
||||
ApiResult<Void> syncFromBase(@RequestBody @Valid ResourceSyncReq req);
|
||||
}
|
||||
|
||||
@ -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<Long> ids;
|
||||
|
||||
/** 操作人personId **/
|
||||
@NotNull(message = "操作人ID不能为空")
|
||||
private Long operatorId;
|
||||
}
|
||||
@ -17,4 +17,19 @@ import lombok.NoArgsConstructor;
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CommonDictResp {
|
||||
|
||||
/**
|
||||
* 业务域
|
||||
*/
|
||||
private String scope;
|
||||
|
||||
/**
|
||||
* 字典编码
|
||||
*/
|
||||
private String dictCode;
|
||||
|
||||
/**
|
||||
* 字典值
|
||||
*/
|
||||
private String dictValue;
|
||||
}
|
||||
|
||||
@ -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<FeatureResourceTreeNode> children;
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public Long getNodeCode() {
|
||||
return super.getId();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public Long getParentNodeCode() {
|
||||
return super.getParentId();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public List<FeatureResourceTreeNode> getNodeChildren() {
|
||||
return this.children;
|
||||
|
||||
@ -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);
|
||||
// }
|
||||
}
|
||||
|
||||
@ -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";
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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<List<FeatureResourceTreeNode>> getSyncTreeById(Long id) {
|
||||
@ -34,13 +35,13 @@ public class FeatureResourceController implements FeatureResourceApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<Void> syncFromBase(List<Long> ids) {
|
||||
public ApiResult<Void> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
|
||||
|
||||
@ -19,4 +19,8 @@ public class SaasFeatureResourceDao extends ServiceImpl<SaasFeatureResourceMappe
|
||||
public SaasFeatureResource getByCode(String featureCode) {
|
||||
return this.lambdaQuery().eq(SaasFeatureResource::getFeatureCode, featureCode).one();
|
||||
}
|
||||
|
||||
public void replacePath(String oldPath, String newPath) {
|
||||
this.baseMapper.replacePath(oldPath, newPath);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@ 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>
|
||||
@ -13,4 +15,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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<FeatureResourceTreeNode> getSyncTreeById(Long id);
|
||||
|
||||
void syncFromBase(List<Long> ids);
|
||||
void syncFromBase(ResourceSyncReq req);
|
||||
}
|
||||
|
||||
@ -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<SaasFeatureResource> 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<Long> ids) {
|
||||
final Map<String, Long> idCache = new HashMap<>();
|
||||
public void syncFromBase(ResourceSyncReq req) {
|
||||
final Map<Long, String> codeCache = new ConcurrentHashMap<>();
|
||||
for (Long id : ids) {
|
||||
doSyncFromBase(id, idCache, codeCache);
|
||||
for (Long id : req.getIds()) {
|
||||
//TODO:@Zhan 并发处理;同一个parent下同批查询
|
||||
//获取基准环境配置数据:同步某个ID的数据 需要同步处理它所有上级及下级组件
|
||||
List<FeatureResourceTreeNode> 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<String, Long> idCache, Map<Long, String> codeCache) {
|
||||
if (codeCache.containsKey(id)) {
|
||||
//已处理过
|
||||
log.info("already sync resource:{}", id);
|
||||
return;
|
||||
}
|
||||
List<FeatureResourceTreeNode> syncList = RpcInternalUtil.rpcProcessor(() -> baseFeatureResourceApi.getSyncTreeById(id),
|
||||
"get sync tree by id", id).getData();
|
||||
private void doSyncFromBase(List<FeatureResourceTreeNode> syncList, Map<Long, String> 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<Long, String> 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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user