feat:(REQ-2545) 增加项目的产品缓存,提高鉴权接口响应
This commit is contained in:
parent
1087c505c8
commit
bef5d839e2
@ -1,6 +1,7 @@
|
|||||||
package cn.axzo.tyr.server;
|
package cn.axzo.tyr.server;
|
||||||
|
|
||||||
import cn.axzo.pokonyan.config.mybatisplus.EntityMetaObjectHandler;
|
import cn.axzo.pokonyan.config.mybatisplus.EntityMetaObjectHandler;
|
||||||
|
import cn.axzo.tyr.server.config.RocketMQEventConfiguration;
|
||||||
import cn.axzo.tyr.server.job.CMSRoleJobHandler;
|
import cn.axzo.tyr.server.job.CMSRoleJobHandler;
|
||||||
import cn.hutool.extra.spring.SpringUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -20,6 +21,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
|||||||
@EnableDiscoveryClient
|
@EnableDiscoveryClient
|
||||||
@MapperScan(value = {"cn.axzo.tyr.server.repository.mapper"})
|
@MapperScan(value = {"cn.axzo.tyr.server.repository.mapper"})
|
||||||
@SpringBootApplication(scanBasePackages = "cn.axzo")
|
@SpringBootApplication(scanBasePackages = "cn.axzo")
|
||||||
|
@Import(RocketMQEventConfiguration.class)
|
||||||
public class TyrApplication {
|
public class TyrApplication {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
ConfigurableApplicationContext run = SpringApplication.run(TyrApplication.class, args);
|
ConfigurableApplicationContext run = SpringApplication.run(TyrApplication.class, args);
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
package cn.axzo.tyr.server;
|
package cn.axzo.tyr.server;
|
||||||
|
|
||||||
|
import cn.axzo.tyr.server.config.RocketMQEventConfiguration;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.scheduling.annotation.EnableAsync;
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
@ -15,6 +17,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
|||||||
@EnableFeignClients(basePackages = {"cn.axzo"})
|
@EnableFeignClients(basePackages = {"cn.axzo"})
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@EnableAsync
|
@EnableAsync
|
||||||
|
@Import(RocketMQEventConfiguration.class)
|
||||||
public class TyrServerDevApplication {
|
public class TyrServerDevApplication {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
package cn.axzo.tyr.server;
|
package cn.axzo.tyr.server;
|
||||||
|
|
||||||
|
import cn.axzo.tyr.server.config.RocketMQEventConfiguration;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.scheduling.annotation.EnableAsync;
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
@ -16,6 +18,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
|||||||
@EnableFeignClients(basePackages = {"cn.axzo"})
|
@EnableFeignClients(basePackages = {"cn.axzo"})
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@EnableAsync
|
@EnableAsync
|
||||||
|
@Import(RocketMQEventConfiguration.class)
|
||||||
public class TyrServerPreApplication {
|
public class TyrServerPreApplication {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
package cn.axzo.tyr.server;
|
package cn.axzo.tyr.server;
|
||||||
|
|
||||||
|
import cn.axzo.tyr.server.config.RocketMQEventConfiguration;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.scheduling.annotation.EnableAsync;
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
@ -16,6 +18,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
|||||||
@EnableFeignClients(basePackages = {"cn.axzo"})
|
@EnableFeignClients(basePackages = {"cn.axzo"})
|
||||||
@Log4j2
|
@Log4j2
|
||||||
@EnableAsync
|
@EnableAsync
|
||||||
|
@Import(RocketMQEventConfiguration.class)
|
||||||
public class TyrServerTestApplication {
|
public class TyrServerTestApplication {
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
|||||||
@ -0,0 +1,90 @@
|
|||||||
|
package cn.axzo.tyr.server.config;
|
||||||
|
|
||||||
|
import cn.axzo.framework.rocketmq.BaseListener;
|
||||||
|
import cn.axzo.framework.rocketmq.DefaultEventConsumer;
|
||||||
|
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||||
|
import cn.axzo.framework.rocketmq.EventHandlerRepository;
|
||||||
|
import cn.axzo.framework.rocketmq.EventProducer;
|
||||||
|
import cn.axzo.framework.rocketmq.RocketMQEventProducer;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.rocketmq.common.message.MessageExt;
|
||||||
|
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
||||||
|
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||||
|
import org.apache.rocketmq.spring.core.RocketMQListener;
|
||||||
|
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: liyong.tian
|
||||||
|
* @Date: 2023/7/25 14:43
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class RocketMQEventConfiguration {
|
||||||
|
|
||||||
|
@Value("${spring.application.name}")
|
||||||
|
private String appName;
|
||||||
|
|
||||||
|
@Value("${topic}")
|
||||||
|
private String topic;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RocketMQTemplate ser(){
|
||||||
|
return new RocketMQTemplate();
|
||||||
|
}
|
||||||
|
@Bean
|
||||||
|
EventProducer eventProducer(RocketMQTemplate rocketMQTemplate) {
|
||||||
|
return new RocketMQEventProducer(rocketMQTemplate,
|
||||||
|
appName,
|
||||||
|
appName,
|
||||||
|
EventProducer.Context.<RocketMQEventProducer.RocketMQMessageMeta>builder()
|
||||||
|
.meta(RocketMQEventProducer.RocketMQMessageMeta.builder()
|
||||||
|
.topic(topic)
|
||||||
|
.build())
|
||||||
|
.build(),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
EventConsumer eventConsumer(EventHandlerRepository eventHandlerRepository) {
|
||||||
|
Consumer<EventConsumer.EventWrapper> callback = (eventWrapper) -> {
|
||||||
|
if (eventWrapper.isHandled()) {
|
||||||
|
// 只收集被App真正消费的消息.
|
||||||
|
//String topic = (String) eventWrapper.getExt().get(EVENT_TOPIC_KEY);
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return new DefaultEventConsumer(appName, eventHandlerRepository, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RocketMQMessageListener(topic = "topic_thrones_${spring.profiles.active}",
|
||||||
|
consumerGroup = "GID_topic_thrones_${spring.application.name}_${spring.profiles.active}",
|
||||||
|
consumeMode = ConsumeMode.ORDERLY,
|
||||||
|
nameServer = "${rocketmq.name-server}"
|
||||||
|
)
|
||||||
|
public static class DefaultListener extends BaseListener implements RocketMQListener<MessageExt> {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EventConsumer eventConsumer;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMessage(MessageExt message) {
|
||||||
|
super.onEvent(message, eventConsumer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
EventHandlerRepository eventHandlerRepository() {
|
||||||
|
return new EventHandlerRepository((ex, logText) -> {
|
||||||
|
log.warn("MQ, handle warning {}", logText, ex);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,8 +11,9 @@ public enum BizResultCode implements IResultCode {
|
|||||||
CANT_DELETE_ROLE_GROUP("100001", "不能删除角色分组,当前角色分组下有子角色分组"),
|
CANT_DELETE_ROLE_GROUP("100001", "不能删除角色分组,当前角色分组下有子角色分组"),
|
||||||
ROLE_GROUP_NOT_FOUND("100002", "角色分组不存在"),
|
ROLE_GROUP_NOT_FOUND("100002", "角色分组不存在"),
|
||||||
REDIS_ROLE_NOT_NULL("100003", "角色id不能为空"),
|
REDIS_ROLE_NOT_NULL("100003", "角色id不能为空"),
|
||||||
REDIS_PRODUCT_NOT_NULL("100004", "产品id不能为空"),
|
REDIS_PRODUCT_NOT_NULL("100004", "产品不能为空"),
|
||||||
FEATURE_RESOURCE_NOT_FOUND("100005", "菜单资源不存在");
|
FEATURE_RESOURCE_NOT_FOUND("100005", "菜单资源不存在"),
|
||||||
|
WORKSPACE_ID_NOT_NULL("100006", "项目id不能为空");
|
||||||
|
|
||||||
private String errorCode;
|
private String errorCode;
|
||||||
private String errorMessage;
|
private String errorMessage;
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum;
|
|||||||
import cn.axzo.basics.common.util.TreeUtil;
|
import cn.axzo.basics.common.util.TreeUtil;
|
||||||
import cn.axzo.foundation.page.PageResp;
|
import cn.axzo.foundation.page.PageResp;
|
||||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||||
|
import cn.axzo.framework.rocketmq.Event;
|
||||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||||
import cn.axzo.tyr.client.model.req.CommonDictQueryReq;
|
import cn.axzo.tyr.client.model.req.CommonDictQueryReq;
|
||||||
import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq;
|
import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq;
|
||||||
@ -17,6 +18,8 @@ import cn.axzo.tyr.client.model.res.FeatureResourceDTO;
|
|||||||
import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode;
|
import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode;
|
||||||
import cn.axzo.tyr.client.model.res.SaasRoleRes;
|
import cn.axzo.tyr.client.model.res.SaasRoleRes;
|
||||||
import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO;
|
import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO;
|
||||||
|
import cn.axzo.tyr.server.event.outer.CacheWorkspaceProductHandler;
|
||||||
|
import cn.axzo.tyr.server.event.payload.ServicePkgProductCreatedPayload;
|
||||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
|
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
|
||||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
|
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
|
||||||
import cn.axzo.tyr.server.repository.dao.SaasPgroupPermissionRelationDao;
|
import cn.axzo.tyr.server.repository.dao.SaasPgroupPermissionRelationDao;
|
||||||
@ -40,6 +43,7 @@ import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
|||||||
import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService;
|
import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService;
|
||||||
import cn.axzo.tyr.server.service.SaasRoleGroupService;
|
import cn.axzo.tyr.server.service.SaasRoleGroupService;
|
||||||
import cn.axzo.tyr.server.service.TyrSaasAuthService;
|
import cn.axzo.tyr.server.service.TyrSaasAuthService;
|
||||||
|
import cn.axzo.tyr.server.service.WorkspaceProductService;
|
||||||
import cn.axzo.tyr.server.service.impl.SaasFeatureResourceCacheService;
|
import cn.axzo.tyr.server.service.impl.SaasFeatureResourceCacheService;
|
||||||
import cn.axzo.tyr.server.util.FeatureCodeUtil;
|
import cn.axzo.tyr.server.util.FeatureCodeUtil;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
@ -112,7 +116,10 @@ public class PrivateController {
|
|||||||
private ProductFeatureRelationService productFeatureRelationService;
|
private ProductFeatureRelationService productFeatureRelationService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private FeatureCodeUtil featureCodeUtil;
|
private FeatureCodeUtil featureCodeUtil;
|
||||||
|
@Autowired
|
||||||
|
private WorkspaceProductService workspaceProductService;
|
||||||
|
@Autowired
|
||||||
|
private CacheWorkspaceProductHandler cacheWorkspaceProductHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统一层级的roleGroup按照id升序,sort从1递增
|
* 统一层级的roleGroup按照id升序,sort从1递增
|
||||||
@ -567,6 +574,26 @@ public class PrivateController {
|
|||||||
return featureCodeUtil.resolveFeatureCode(request.getFeatureCodes());
|
return featureCodeUtil.resolveFeatureCode(request.getFeatureCodes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/api/private/workspaceProduct/store")
|
||||||
|
public Object storeWorkspaceProduct(@RequestBody WorkspaceProductService.StoreWorkspaceProductParam request) {
|
||||||
|
workspaceProductService.storeWorkspaceProduct(request);
|
||||||
|
return "ok";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/api/private/workspaceProduct/list")
|
||||||
|
public Object listWorkspaceProduct(@RequestBody WorkspaceProductService.WorkspaceProductParam request) {
|
||||||
|
return workspaceProductService.listWorkspaceProductCached(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/api/private/cacheWorkspaceProductHandler/process")
|
||||||
|
public Object processCacheWorkspaceProductHandler(@RequestBody ServicePkgProductCreatedPayload request) {
|
||||||
|
Event event = Event.builder()
|
||||||
|
.data(request)
|
||||||
|
.build();
|
||||||
|
cacheWorkspaceProductHandler.onEvent(event, null);
|
||||||
|
return "ok";
|
||||||
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
|
|||||||
@ -63,7 +63,6 @@ public class TyrSaasAuthController implements TyrSaasAuthApi {
|
|||||||
}
|
}
|
||||||
return ApiResult.ok(tyrSaasAuthService.findIdentityAuthMix(identityAuthReq));
|
return ApiResult.ok(tyrSaasAuthService.findIdentityAuthMix(identityAuthReq));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ApiResult<Boolean> hasPermissionForIdentityV2(CheckIdentityPermissionReq req) {
|
public ApiResult<Boolean> hasPermissionForIdentityV2(CheckIdentityPermissionReq req) {
|
||||||
//单独做下参数校验
|
//单独做下参数校验
|
||||||
|
|||||||
@ -0,0 +1,58 @@
|
|||||||
|
package cn.axzo.tyr.server.event.outer;
|
||||||
|
|
||||||
|
import cn.axzo.framework.rocketmq.Event;
|
||||||
|
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||||
|
import cn.axzo.framework.rocketmq.EventHandler;
|
||||||
|
import cn.axzo.tyr.server.event.payload.ServicePkgProductCreatedPayload;
|
||||||
|
import cn.axzo.tyr.server.service.WorkspaceProductService;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存项目的产品
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class CacheWorkspaceProductHandler implements EventHandler, InitializingBean {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EventConsumer eventConsumer;
|
||||||
|
@Autowired
|
||||||
|
private WorkspaceProductService workspaceProductService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(Event event, EventConsumer.Context context) {
|
||||||
|
log.info("begin cached workspace product handler rocketmq event: {}", event);
|
||||||
|
ServicePkgProductCreatedPayload payload = event.normalizedData(ServicePkgProductCreatedPayload.class);
|
||||||
|
|
||||||
|
if (Objects.isNull(payload) || CollectionUtils.isEmpty(payload.getSaasServicePkgProducts())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkspaceProductService.WorkspaceProductDTO workspaceProductDTO = WorkspaceProductService.WorkspaceProductDTO.builder()
|
||||||
|
.workspaceId(payload.getSaasServicePackage().getSpaceId())
|
||||||
|
.productIds(payload.getSaasServicePkgProducts().stream()
|
||||||
|
.map(ServicePkgProductCreatedPayload.SaasServicePkgProductPo::getProductId)
|
||||||
|
.collect(Collectors.toSet()))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
WorkspaceProductService.StoreWorkspaceProductParam storeWorkspaceProductParam = WorkspaceProductService.StoreWorkspaceProductParam.builder()
|
||||||
|
.workspaceProducts(Lists.newArrayList(workspaceProductDTO))
|
||||||
|
.build();
|
||||||
|
workspaceProductService.storeWorkspaceProduct(storeWorkspaceProductParam);
|
||||||
|
log.info("end cached workspace product handler rocketmq event: {}", event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
eventConsumer.registerHandler(EventTypeEnum.SERVICE_PKG_PRODUCT_CREATED.getEventCode(), this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
package cn.axzo.tyr.server.event.outer;
|
||||||
|
|
||||||
|
import cn.axzo.framework.rocketmq.Event;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Classname EventTypeEnum
|
||||||
|
* @Date 2021/2/7 6:05 下午
|
||||||
|
* @Created by lilong
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public enum EventTypeEnum {
|
||||||
|
|
||||||
|
SERVICE_PKG_PRODUCT_CREATED("service-pkg-product", "service-pkg-product-created", "创建服务包的产品"),
|
||||||
|
;
|
||||||
|
|
||||||
|
EventTypeEnum(String model, String name, String desc) {
|
||||||
|
this.eventCode = Event.EventCode.builder()
|
||||||
|
.module(model)
|
||||||
|
.name(name)
|
||||||
|
.build();
|
||||||
|
this.model = model;
|
||||||
|
this.name = name;
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String model;
|
||||||
|
private String name;
|
||||||
|
private String desc;
|
||||||
|
private Event.EventCode eventCode;
|
||||||
|
}
|
||||||
@ -0,0 +1,99 @@
|
|||||||
|
package cn.axzo.tyr.server.event.payload;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ServicePkgProductCreatedPayload implements Serializable {
|
||||||
|
|
||||||
|
private SaasServicePackagePo saasServicePackage;
|
||||||
|
|
||||||
|
private List<SaasServicePkgProductPo> saasServicePkgProducts;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class SaasServicePackagePo {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单位ID
|
||||||
|
*/
|
||||||
|
private Long ouId;
|
||||||
|
/**
|
||||||
|
* 租户id
|
||||||
|
*/
|
||||||
|
private Long saasTenantId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务包类型: 1.企业空间 ,2.项目空间 ,3.政企空间,6.OMS空间
|
||||||
|
*/
|
||||||
|
private Integer type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 空间id
|
||||||
|
*/
|
||||||
|
private Long spaceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* license 名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 有效期:开始
|
||||||
|
*/
|
||||||
|
private LocalDateTime effectiveDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 有效斯:结束
|
||||||
|
*/
|
||||||
|
private LocalDateTime ineffectiveDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* license状态 : 1.未生效 2.有效 3.限制使用 4.停用 5.过期
|
||||||
|
*/
|
||||||
|
private Integer status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class SaasServicePkgProductPo {
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* license id
|
||||||
|
*/
|
||||||
|
private Long servicePkgId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* license相关联的产品
|
||||||
|
*/
|
||||||
|
private Long productId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品功能名称
|
||||||
|
*/
|
||||||
|
private String productName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 0是基础产品 1非基础产品
|
||||||
|
*/
|
||||||
|
|
||||||
|
private Boolean isBasic;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -33,6 +33,8 @@ public class PermissionCacheKey {
|
|||||||
private Boolean disableAll;
|
private Boolean disableAll;
|
||||||
|
|
||||||
public String buildAuthKey() {
|
public String buildAuthKey() {
|
||||||
|
// 因为personId、identityId、identityType这三个参数用户现在可以随意组合
|
||||||
|
//
|
||||||
return personId == null ? KeyUtil.buildKeyBySeparator("auth-i", identityId, identityType.getCode(), ouId, workspaceId)
|
return personId == null ? KeyUtil.buildKeyBySeparator("auth-i", identityId, identityType.getCode(), ouId, workspaceId)
|
||||||
: KeyUtil.buildKeyBySeparator("auth-p", personId, ouId, workspaceId);
|
: KeyUtil.buildKeyBySeparator("auth-p", personId, ouId, workspaceId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,19 @@ public interface WorkspaceProductService {
|
|||||||
|
|
||||||
List<WorkspaceProduct> listWorkspaceProduct(WorkspaceProductParam param);
|
List<WorkspaceProduct> listWorkspaceProduct(WorkspaceProductParam param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从缓存中查询项目的产品
|
||||||
|
* @param param
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<WorkspaceProduct> listWorkspaceProductCached(WorkspaceProductParam param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存项目的产品
|
||||||
|
* @param param
|
||||||
|
*/
|
||||||
|
void storeWorkspaceProduct(StoreWorkspaceProductParam param);
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@ -60,5 +73,42 @@ public interface WorkspaceProductService {
|
|||||||
*/
|
*/
|
||||||
private List<SaasProductModuleFeatureRelation> saasProductModuleFeatureRelations;
|
private List<SaasProductModuleFeatureRelation> saasProductModuleFeatureRelations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class StoreWorkspaceProductParam {
|
||||||
|
|
||||||
|
private List<WorkspaceProductDTO> workspaceProducts;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class WorkspaceProductDTO {
|
||||||
|
/**
|
||||||
|
* 项目id
|
||||||
|
*/
|
||||||
|
private Long workspaceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 产品id
|
||||||
|
*/
|
||||||
|
private Set<Long> productIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
class ListWorkspaceProductParam {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目id
|
||||||
|
*/
|
||||||
|
private Set<Long> workspaceIds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1407,7 +1407,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
|
|||||||
FeatureIdPair.builder().featureIds(featureIds).type(NEW_FEATURE).build()
|
FeatureIdPair.builder().featureIds(featureIds).type(NEW_FEATURE).build()
|
||||||
))
|
))
|
||||||
.build();
|
.build();
|
||||||
Set<SaasProductModuleFeatureRelation> workspaceProductFeatures = workspaceProductService.listWorkspaceProduct(workspaceProductParam).stream()
|
Set<SaasProductModuleFeatureRelation> workspaceProductFeatures = workspaceProductService.listWorkspaceProductCached(workspaceProductParam).stream()
|
||||||
.map(WorkspaceProductService.WorkspaceProduct::getSaasProductModuleFeatureRelations)
|
.map(WorkspaceProductService.WorkspaceProduct::getSaasProductModuleFeatureRelations)
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.flatMap(Collection::stream)
|
.flatMap(Collection::stream)
|
||||||
@ -1468,7 +1468,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
|
|||||||
FeatureIdPair.builder().featureIds(featureIds).type(OLD_FEATURE).build()
|
FeatureIdPair.builder().featureIds(featureIds).type(OLD_FEATURE).build()
|
||||||
))
|
))
|
||||||
.build();
|
.build();
|
||||||
Set<SaasProductModuleFeatureRelation> workspaceProductFeatures = workspaceProductService.listWorkspaceProduct(workspaceProductParam).stream()
|
Set<SaasProductModuleFeatureRelation> workspaceProductFeatures = workspaceProductService.listWorkspaceProductCached(workspaceProductParam).stream()
|
||||||
.map(WorkspaceProductService.WorkspaceProduct::getSaasProductModuleFeatureRelations)
|
.map(WorkspaceProductService.WorkspaceProduct::getSaasProductModuleFeatureRelations)
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.flatMap(Collection::stream)
|
.flatMap(Collection::stream)
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package cn.axzo.tyr.server.service.impl;
|
package cn.axzo.tyr.server.service.impl;
|
||||||
|
|
||||||
|
import cn.axzo.foundation.exception.Axssert;
|
||||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||||
|
import cn.axzo.pokonyan.config.redis.RedisUtil;
|
||||||
import cn.axzo.thrones.client.saas.ServicePkgClient;
|
import cn.axzo.thrones.client.saas.ServicePkgClient;
|
||||||
import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct;
|
import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct;
|
||||||
import cn.axzo.thrones.client.saas.entity.servicepkg.ServicePkgDetailRes;
|
import cn.axzo.thrones.client.saas.entity.servicepkg.ServicePkgDetailRes;
|
||||||
@ -12,9 +14,20 @@ import cn.axzo.tyr.server.service.WorkspaceProductService;
|
|||||||
import cn.axzo.tyr.server.utils.RpcInternalUtil;
|
import cn.axzo.tyr.server.utils.RpcInternalUtil;
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import cn.hutool.core.lang.Pair;
|
import cn.hutool.core.lang.Pair;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import com.google.common.collect.Streams;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.data.redis.core.RedisOperations;
|
||||||
|
import org.springframework.data.redis.core.SessionCallback;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -23,8 +36,12 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static cn.axzo.tyr.server.config.exception.BizResultCode.REDIS_PRODUCT_NOT_NULL;
|
||||||
|
import static cn.axzo.tyr.server.config.exception.BizResultCode.WORKSPACE_ID_NOT_NULL;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class WorkspaceProductServiceImpl implements WorkspaceProductService {
|
public class WorkspaceProductServiceImpl implements WorkspaceProductService {
|
||||||
@ -35,6 +52,14 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
|
|||||||
private ProductModuleDao productModuleDao;
|
private ProductModuleDao productModuleDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ProductFeatureRelationService productFeatureRelationService;
|
private ProductFeatureRelationService productFeatureRelationService;
|
||||||
|
@Autowired
|
||||||
|
protected StringRedisTemplate redisTemplate;
|
||||||
|
|
||||||
|
/** 授权缓存过期时间 **/
|
||||||
|
@Value("${workspace.product.expire:90}")
|
||||||
|
private Long expireInDays;
|
||||||
|
|
||||||
|
private static final String WORKSPACE_PRODUCT_KEY = "workspace:product:%s";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<WorkspaceProduct> listWorkspaceProduct(WorkspaceProductParam param) {
|
public List<WorkspaceProduct> listWorkspaceProduct(WorkspaceProductParam param) {
|
||||||
@ -104,4 +129,162 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
|
|||||||
.build())
|
.build())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<WorkspaceProduct> listWorkspaceProductCached(WorkspaceProductParam param) {
|
||||||
|
if (CollectionUtils.isEmpty(param.getWorkspaceIds())) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
ListWorkspaceProductParam listWorkspaceProductParam = ListWorkspaceProductParam.builder()
|
||||||
|
.workspaceIds(param.getWorkspaceIds())
|
||||||
|
.build();
|
||||||
|
Map<Long, Set<Long>> workspaceProducts = listWorkspaceProduct(listWorkspaceProductParam);
|
||||||
|
|
||||||
|
// 存在项目没有在缓存中查询到产品的情况
|
||||||
|
fillCacheWorkspaseProducts(param, workspaceProducts);
|
||||||
|
|
||||||
|
Set<Long> productIds = workspaceProducts.values().stream()
|
||||||
|
.flatMap(Collection::stream)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(productIds)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已被删除产品过滤一层
|
||||||
|
Set<Long> finalProductIds = productModuleDao.listByIds(productIds)
|
||||||
|
.stream()
|
||||||
|
.filter(productModule -> Objects.equals(productModule.getIsDelete(),0L))
|
||||||
|
.map(BaseEntity::getId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
if (CollectionUtil.isEmpty(finalProductIds)) {
|
||||||
|
log.warn("all product is deleted for workspace :{}", param.getWorkspaceIds());
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProductFeatureQuery productFeatureQuery = ProductFeatureQuery.builder()
|
||||||
|
.productIds(finalProductIds)
|
||||||
|
.featureResourceTypes(param.getFeatureResourceTypes())
|
||||||
|
.terminal(param.getTerminal())
|
||||||
|
.type(param.getType())
|
||||||
|
.featureIdPairs(param.getFeatureIdPairs())
|
||||||
|
.build();
|
||||||
|
Map<Long, List<SaasProductModuleFeatureRelation>> saasProductModuleFeatureRelations = productFeatureRelationService.queryOnCondition(productFeatureQuery).stream()
|
||||||
|
.collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId));
|
||||||
|
|
||||||
|
return workspaceProducts.entrySet().stream()
|
||||||
|
.filter(e -> CollectionUtils.isNotEmpty(e.getValue()))
|
||||||
|
.map(e -> {
|
||||||
|
List<SaasProductModuleFeatureRelation> features = e.getValue().stream()
|
||||||
|
.map(saasProductModuleFeatureRelations::get)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.flatMap(Collection::stream)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return WorkspaceProduct.builder()
|
||||||
|
.workspaceId(e.getKey())
|
||||||
|
.saasProductModuleFeatureRelations(features)
|
||||||
|
.build();
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void storeWorkspaceProduct(StoreWorkspaceProductParam param) {
|
||||||
|
Axssert.checkNotEmpty(param.getWorkspaceProducts(), REDIS_PRODUCT_NOT_NULL);
|
||||||
|
|
||||||
|
|
||||||
|
redisTemplate.executePipelined(new SessionCallback<Object>() {
|
||||||
|
@Override
|
||||||
|
public Object execute(RedisOperations operations) throws DataAccessException {
|
||||||
|
|
||||||
|
for (WorkspaceProductDTO workspaceProduct : param.getWorkspaceProducts()) {
|
||||||
|
String redisKey = getKey(workspaceProduct.getWorkspaceId());
|
||||||
|
RedisUtil.StringValueOps.setEx(redisKey, JSON.toJSONString(workspaceProduct.getProductIds()),
|
||||||
|
expireInDays, TimeUnit.DAYS);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Long, Set<Long>> listWorkspaceProduct(ListWorkspaceProductParam param) {
|
||||||
|
Axssert.checkNotEmpty(param.getWorkspaceIds(), WORKSPACE_ID_NOT_NULL);
|
||||||
|
|
||||||
|
List<String> redisKeys = param.getWorkspaceIds().stream()
|
||||||
|
.map(this::getKey)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
List<String> redisValues = redisTemplate.opsForValue().multiGet(redisKeys);
|
||||||
|
|
||||||
|
return Streams.zip(param.getWorkspaceIds().stream(),
|
||||||
|
redisValues.stream(),
|
||||||
|
(workspaceId, redisValue) -> {
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(redisValue)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<Long> productIds = JSON.parseArray(redisValue.toString())
|
||||||
|
.stream()
|
||||||
|
.map(e -> Long.valueOf(e.toString()))
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
return Pair.of(workspaceId, productIds);
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toMap(Pair::getKey, Pair::getValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组装在缓存中没有查询到产品的项目
|
||||||
|
* @param param
|
||||||
|
* @param workspaceProducts
|
||||||
|
*/
|
||||||
|
private void fillCacheWorkspaseProducts(WorkspaceProductParam param,
|
||||||
|
Map<Long, Set<Long>> workspaceProducts) {
|
||||||
|
|
||||||
|
Sets.SetView<Long> difference = Sets.difference(param.getWorkspaceIds(), workspaceProducts.keySet());
|
||||||
|
if (difference.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ServicePkgDetailRes> servicePkgDetailRes = RpcInternalUtil.rpcListProcessor(() -> servicePkgClient.getServicePkgDetailBySpaceId(difference),
|
||||||
|
"查询项目的产品", difference).getData();
|
||||||
|
if (CollectionUtil.isEmpty(servicePkgDetailRes)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<WorkspaceProductDTO> workspaceProductDTOS = Lists.newArrayList();
|
||||||
|
|
||||||
|
servicePkgDetailRes.forEach(e -> {
|
||||||
|
Set<Long> workpsaceProductIds = e.getProducts().stream()
|
||||||
|
.map(ServicePkgProduct::getProductId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
if (CollectionUtils.isEmpty(workpsaceProductIds)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
workspaceProducts.put(e.getSpaceId(), workpsaceProductIds);
|
||||||
|
|
||||||
|
WorkspaceProductDTO workspaceProductDTO = WorkspaceProductDTO.builder()
|
||||||
|
.workspaceId(e.getSpaceId())
|
||||||
|
.productIds(workpsaceProductIds)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
workspaceProductDTOS.add(workspaceProductDTO);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(workspaceProductDTOS)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StoreWorkspaceProductParam storeWorkspaceProductParam = StoreWorkspaceProductParam.builder()
|
||||||
|
.workspaceProducts(workspaceProductDTOS)
|
||||||
|
.build();
|
||||||
|
storeWorkspaceProduct(storeWorkspaceProductParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getKey(Object... params) {
|
||||||
|
return String.format(WORKSPACE_PRODUCT_KEY, params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user