feat:(REQ-2545) 增加项目的产品缓存,提高鉴权接口响应
This commit is contained in:
parent
1087c505c8
commit
bef5d839e2
@ -1,6 +1,7 @@
|
||||
package cn.axzo.tyr.server;
|
||||
|
||||
import cn.axzo.pokonyan.config.mybatisplus.EntityMetaObjectHandler;
|
||||
import cn.axzo.tyr.server.config.RocketMQEventConfiguration;
|
||||
import cn.axzo.tyr.server.job.CMSRoleJobHandler;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -20,6 +21,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
||||
@EnableDiscoveryClient
|
||||
@MapperScan(value = {"cn.axzo.tyr.server.repository.mapper"})
|
||||
@SpringBootApplication(scanBasePackages = "cn.axzo")
|
||||
@Import(RocketMQEventConfiguration.class)
|
||||
public class TyrApplication {
|
||||
public static void main(String[] args) {
|
||||
ConfigurableApplicationContext run = SpringApplication.run(TyrApplication.class, args);
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
package cn.axzo.tyr.server;
|
||||
|
||||
import cn.axzo.tyr.server.config.RocketMQEventConfiguration;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
@ -15,6 +17,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
||||
@EnableFeignClients(basePackages = {"cn.axzo"})
|
||||
@Log4j2
|
||||
@EnableAsync
|
||||
@Import(RocketMQEventConfiguration.class)
|
||||
public class TyrServerDevApplication {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
package cn.axzo.tyr.server;
|
||||
|
||||
import cn.axzo.tyr.server.config.RocketMQEventConfiguration;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
@ -16,6 +18,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
||||
@EnableFeignClients(basePackages = {"cn.axzo"})
|
||||
@Log4j2
|
||||
@EnableAsync
|
||||
@Import(RocketMQEventConfiguration.class)
|
||||
public class TyrServerPreApplication {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
package cn.axzo.tyr.server;
|
||||
|
||||
import cn.axzo.tyr.server.config.RocketMQEventConfiguration;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
@ -16,6 +18,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
||||
@EnableFeignClients(basePackages = {"cn.axzo"})
|
||||
@Log4j2
|
||||
@EnableAsync
|
||||
@Import(RocketMQEventConfiguration.class)
|
||||
public class TyrServerTestApplication {
|
||||
|
||||
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", "不能删除角色分组,当前角色分组下有子角色分组"),
|
||||
ROLE_GROUP_NOT_FOUND("100002", "角色分组不存在"),
|
||||
REDIS_ROLE_NOT_NULL("100003", "角色id不能为空"),
|
||||
REDIS_PRODUCT_NOT_NULL("100004", "产品id不能为空"),
|
||||
FEATURE_RESOURCE_NOT_FOUND("100005", "菜单资源不存在");
|
||||
REDIS_PRODUCT_NOT_NULL("100004", "产品不能为空"),
|
||||
FEATURE_RESOURCE_NOT_FOUND("100005", "菜单资源不存在"),
|
||||
WORKSPACE_ID_NOT_NULL("100006", "项目id不能为空");
|
||||
|
||||
private String errorCode;
|
||||
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.foundation.page.PageResp;
|
||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import cn.axzo.tyr.client.model.req.CommonDictQueryReq;
|
||||
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.SaasRoleRes;
|
||||
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.SaasFeatureResourceDao;
|
||||
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.SaasRoleGroupService;
|
||||
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.util.FeatureCodeUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
@ -112,7 +116,10 @@ public class PrivateController {
|
||||
private ProductFeatureRelationService productFeatureRelationService;
|
||||
@Autowired
|
||||
private FeatureCodeUtil featureCodeUtil;
|
||||
|
||||
@Autowired
|
||||
private WorkspaceProductService workspaceProductService;
|
||||
@Autowired
|
||||
private CacheWorkspaceProductHandler cacheWorkspaceProductHandler;
|
||||
|
||||
/**
|
||||
* 统一层级的roleGroup按照id升序,sort从1递增
|
||||
@ -567,6 +574,26 @@ public class PrivateController {
|
||||
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
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
|
||||
@ -63,7 +63,6 @@ public class TyrSaasAuthController implements TyrSaasAuthApi {
|
||||
}
|
||||
return ApiResult.ok(tyrSaasAuthService.findIdentityAuthMix(identityAuthReq));
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
|
||||
public String buildAuthKey() {
|
||||
// 因为personId、identityId、identityType这三个参数用户现在可以随意组合
|
||||
//
|
||||
return personId == null ? KeyUtil.buildKeyBySeparator("auth-i", identityId, identityType.getCode(), ouId, workspaceId)
|
||||
: KeyUtil.buildKeyBySeparator("auth-p", personId, ouId, workspaceId);
|
||||
}
|
||||
|
||||
@ -16,6 +16,19 @@ public interface WorkspaceProductService {
|
||||
|
||||
List<WorkspaceProduct> listWorkspaceProduct(WorkspaceProductParam param);
|
||||
|
||||
/**
|
||||
* 从缓存中查询项目的产品
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
List<WorkspaceProduct> listWorkspaceProductCached(WorkspaceProductParam param);
|
||||
|
||||
/**
|
||||
* 缓存项目的产品
|
||||
* @param param
|
||||
*/
|
||||
void storeWorkspaceProduct(StoreWorkspaceProductParam param);
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@ -60,5 +73,42 @@ public interface WorkspaceProductService {
|
||||
*/
|
||||
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()
|
||||
))
|
||||
.build();
|
||||
Set<SaasProductModuleFeatureRelation> workspaceProductFeatures = workspaceProductService.listWorkspaceProduct(workspaceProductParam).stream()
|
||||
Set<SaasProductModuleFeatureRelation> workspaceProductFeatures = workspaceProductService.listWorkspaceProductCached(workspaceProductParam).stream()
|
||||
.map(WorkspaceProductService.WorkspaceProduct::getSaasProductModuleFeatureRelations)
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
@ -1468,7 +1468,7 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
|
||||
FeatureIdPair.builder().featureIds(featureIds).type(OLD_FEATURE).build()
|
||||
))
|
||||
.build();
|
||||
Set<SaasProductModuleFeatureRelation> workspaceProductFeatures = workspaceProductService.listWorkspaceProduct(workspaceProductParam).stream()
|
||||
Set<SaasProductModuleFeatureRelation> workspaceProductFeatures = workspaceProductService.listWorkspaceProductCached(workspaceProductParam).stream()
|
||||
.map(WorkspaceProductService.WorkspaceProduct::getSaasProductModuleFeatureRelations)
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
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.redis.RedisUtil;
|
||||
import cn.axzo.thrones.client.saas.ServicePkgClient;
|
||||
import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct;
|
||||
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.hutool.core.collection.CollectionUtil;
|
||||
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 org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
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 java.util.Collection;
|
||||
@ -23,8 +36,12 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
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
|
||||
@Service
|
||||
public class WorkspaceProductServiceImpl implements WorkspaceProductService {
|
||||
@ -35,6 +52,14 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
|
||||
private ProductModuleDao productModuleDao;
|
||||
@Autowired
|
||||
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
|
||||
public List<WorkspaceProduct> listWorkspaceProduct(WorkspaceProductParam param) {
|
||||
@ -104,4 +129,162 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
|
||||
.build())
|
||||
.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