Merge branch 'feature/REQ-2720' into feature/REQ-2699
# Conflicts: # tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleServiceImpl.java # tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java # tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java
This commit is contained in:
commit
9e0e09f805
@ -5,6 +5,7 @@ import lombok.Getter;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 权限点授权策略类型
|
||||
@ -39,4 +40,8 @@ public enum DelegatedType {
|
||||
public boolean sameCode(Integer code) {
|
||||
return this.code.equals(code);
|
||||
}
|
||||
|
||||
public static boolean notAuth(Integer delegatedType) {
|
||||
return Objects.equals(NO_NEED.getCode(), delegatedType);
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,6 +64,7 @@ public class IdentityAuthReq {
|
||||
/** 是否使用缓存 - 默认true **/
|
||||
@Builder.Default
|
||||
private boolean useCache = true;
|
||||
|
||||
public IdentityAuthRes toEmpty() {
|
||||
IdentityAuthRes result = new IdentityAuthRes();
|
||||
result.setIdentity(this.getIdentityId());
|
||||
@ -112,6 +113,9 @@ public class IdentityAuthReq {
|
||||
/** 基于角色标签查询逻辑不再用该参数 **/
|
||||
private Integer workspaceJoinType;
|
||||
|
||||
public String buildOuWorkspaceKey() {
|
||||
return this.getOuId() + "_" + this.getWorkspaceId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -25,5 +25,4 @@ public class ListSaasRoleGroupParam {
|
||||
|
||||
@CriteriaField(ignore = true)
|
||||
private Boolean needRole;
|
||||
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ public class PageElementFeatureResourceRelationReq implements IPageReq {
|
||||
List<String> sort;
|
||||
|
||||
@CriteriaField(field = "featureResourceUniCode", operator = Operator.IN)
|
||||
private List<String> featureResourceUniCodes;
|
||||
private Set<String> featureResourceUniCodes;
|
||||
|
||||
@CriteriaField(field = "pageElementCode", operator = Operator.IN)
|
||||
private Set<String> pageElementCodes;
|
||||
|
||||
@ -3,12 +3,14 @@ package cn.axzo.tyr.client.model.req;
|
||||
import cn.axzo.foundation.dao.support.wrapper.CriteriaField;
|
||||
import cn.axzo.foundation.dao.support.wrapper.Operator;
|
||||
import cn.axzo.foundation.page.IPageReq;
|
||||
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@ -30,4 +32,22 @@ public class PageProductFeatureRelationReq implements IPageReq {
|
||||
|
||||
@CriteriaField(field = "id", operator = Operator.IN)
|
||||
private List<Long> ids;
|
||||
|
||||
/**
|
||||
* 产品 ID
|
||||
*/
|
||||
@CriteriaField(field = "productModuleId", operator = Operator.IN)
|
||||
private Set<Long> productModuleIds;
|
||||
|
||||
@CriteriaField(field = "type", operator = Operator.EQ)
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 查询菜单树节点类型
|
||||
*/
|
||||
@CriteriaField(field = "featureType", operator = Operator.IN)
|
||||
private List<Integer> featureResourceTypes;
|
||||
|
||||
@CriteriaField(field = "terminal", operator = Operator.EQ)
|
||||
private String terminal;
|
||||
}
|
||||
|
||||
@ -70,6 +70,9 @@ public class PageSaasFeatureResourceReq implements IPageReq {
|
||||
@CriteriaField(ignore = true)
|
||||
private Set<String> paths;
|
||||
|
||||
@CriteriaField(field = "terminal", operator = Operator.IN)
|
||||
private Set<String> terminals;
|
||||
|
||||
public PageResp toEmpty() {
|
||||
return PageResp.builder()
|
||||
.current(this.getPage())
|
||||
|
||||
@ -56,16 +56,11 @@ public class IdentityAuthRes {
|
||||
public static class PermissionPoint {
|
||||
private Long featureId;
|
||||
|
||||
private String featureCode;
|
||||
private String featureCode;
|
||||
|
||||
// private FeatureType featureType;
|
||||
private Integer featureType;
|
||||
|
||||
private String terminal;
|
||||
|
||||
/**
|
||||
* 应用范围(租户类型):1:企业工作台 2;项目工作台
|
||||
*/
|
||||
private Long workspaceType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -3,13 +3,17 @@ package cn.axzo.tyr.client.model.res;
|
||||
import cn.axzo.tyr.client.model.base.FeatureResourceExtraDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@ -143,4 +147,10 @@ public class SaasFeatureResourceResp {
|
||||
* 唯一编码,用于pre环境菜单同步
|
||||
*/
|
||||
private String uniCode;
|
||||
|
||||
public Set<Long> resolvePath() {
|
||||
return Optional.ofNullable(this.getPath())
|
||||
.map(e -> Arrays.stream(e.split(",")).map(Long::valueOf).collect(Collectors.toSet()))
|
||||
.orElseGet(Sets::newHashSet);
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,6 +37,11 @@ public class SimplePermissionPointResp implements IBaseTree<SimplePermissionPoin
|
||||
/** 上级权限点ID **/
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 类型 0.模块 1.菜单 2页面 3功能
|
||||
*/
|
||||
private Integer featureType;
|
||||
|
||||
/** 子节点 **/
|
||||
private List<SimplePermissionPointResp> children;
|
||||
|
||||
|
||||
@ -52,6 +52,19 @@ public class SaasRoleUserV2DTO {
|
||||
*/
|
||||
private Long workspaceId;
|
||||
|
||||
/**
|
||||
* 身份Id
|
||||
*/
|
||||
private Long identityId;
|
||||
|
||||
/**
|
||||
* 身份类型 1:工人 2:从业人员 3:班组长 4:运营人员 5:政务人员
|
||||
*/
|
||||
private Integer identityType;
|
||||
|
||||
public String buildOuWorkspaceKey() {
|
||||
return this.getOuId() + "_" + this.getWorkspaceId();
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
package cn.axzo.tyr.server.config;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventProducer;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RefreshScope
|
||||
public class MqProducer {
|
||||
|
||||
@Autowired
|
||||
private EventProducer<?> eventProducer;
|
||||
|
||||
@Value("${sendMq}")
|
||||
private Boolean sendMq;
|
||||
|
||||
public void send(Event event){
|
||||
log.info(JSON.toJSONString(event));
|
||||
if(sendMq != null && !sendMq){
|
||||
return;
|
||||
}
|
||||
//生产消息
|
||||
eventProducer.send(event);
|
||||
}
|
||||
|
||||
public void sendBatch(List<Event> events){
|
||||
events.forEach(this::send);
|
||||
}
|
||||
}
|
||||
@ -70,7 +70,43 @@ public class RocketMQEventConfiguration {
|
||||
consumeMode = ConsumeMode.ORDERLY,
|
||||
nameServer = "${rocketmq.name-server}"
|
||||
)
|
||||
public static class DefaultListener extends BaseListener implements RocketMQListener<MessageExt> {
|
||||
public static class ThronesListener extends BaseListener implements RocketMQListener<MessageExt> {
|
||||
|
||||
@Autowired
|
||||
private EventConsumer eventConsumer;
|
||||
|
||||
@Override
|
||||
public void onMessage(MessageExt message) {
|
||||
super.onEvent(message, eventConsumer);
|
||||
}
|
||||
}
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RocketMQMessageListener(topic = "topic_tyr_${spring.profiles.active}",
|
||||
consumerGroup = "GID_topic_tyr_${spring.application.name}_${spring.profiles.active}",
|
||||
consumeMode = ConsumeMode.ORDERLY,
|
||||
nameServer = "${rocketmq.name-server}"
|
||||
)
|
||||
public static class TyrListener extends BaseListener implements RocketMQListener<MessageExt> {
|
||||
|
||||
@Autowired
|
||||
private EventConsumer eventConsumer;
|
||||
|
||||
@Override
|
||||
public void onMessage(MessageExt message) {
|
||||
super.onEvent(message, eventConsumer);
|
||||
}
|
||||
}
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RocketMQMessageListener(topic = "topic_apisix_plat_${spring.profiles.active}",
|
||||
consumerGroup = "GID_topic_apisix_plat_${spring.application.name}_${spring.profiles.active}",
|
||||
consumeMode = ConsumeMode.ORDERLY,
|
||||
nameServer = "${rocketmq.name-server}"
|
||||
)
|
||||
public static class ApiSixPlatListener extends BaseListener implements RocketMQListener<MessageExt> {
|
||||
|
||||
@Autowired
|
||||
private EventConsumer eventConsumer;
|
||||
|
||||
@ -7,6 +7,7 @@ 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.product.ProductSearchListReq;
|
||||
import cn.axzo.tyr.client.model.req.CommonDictQueryReq;
|
||||
import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq;
|
||||
import cn.axzo.tyr.client.model.req.PagePgroupPermissionRelationReq;
|
||||
@ -21,6 +22,11 @@ import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO;
|
||||
import cn.axzo.tyr.client.model.vo.SaveOrUpdateRoleVO;
|
||||
import cn.axzo.tyr.server.event.outer.CacheWorkspaceProductHandler;
|
||||
import cn.axzo.tyr.server.event.payload.ServicePkgProductCreatedPayload;
|
||||
import cn.axzo.tyr.server.job.CacheProductFeatureResourceJob;
|
||||
import cn.axzo.tyr.server.job.CacheProductPermissionJob;
|
||||
import cn.axzo.tyr.server.job.CacheRoleFeatureResourceJob;
|
||||
import cn.axzo.tyr.server.job.CacheRolePermissionJob;
|
||||
import cn.axzo.tyr.server.job.CacheSaasFeatureJob;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPgroupPermissionRelationDao;
|
||||
@ -38,8 +44,10 @@ import cn.axzo.tyr.server.repository.entity.SaasRoleGroup;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasRoleGroupRelation;
|
||||
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
|
||||
import cn.axzo.tyr.server.service.ProductPermissionCacheService;
|
||||
import cn.axzo.tyr.server.service.RolePermissionCacheService;
|
||||
import cn.axzo.tyr.server.service.RoleService;
|
||||
import cn.axzo.tyr.server.service.SaasCommonDictService;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService;
|
||||
import cn.axzo.tyr.server.service.SaasRoleGroupService;
|
||||
import cn.axzo.tyr.server.service.TyrSaasAuthService;
|
||||
@ -123,6 +131,20 @@ public class PrivateController {
|
||||
private CacheWorkspaceProductHandler cacheWorkspaceProductHandler;
|
||||
@Autowired
|
||||
private SaasRoleGroupDao saasRoleGroupDao;
|
||||
@Autowired
|
||||
private CacheProductPermissionJob cacheProductPermissionJob;
|
||||
@Autowired
|
||||
private CacheRolePermissionJob cacheRolePermissionJob;
|
||||
@Autowired
|
||||
private CacheSaasFeatureJob cacheSaasFeatureJob;
|
||||
@Autowired
|
||||
private CacheProductFeatureResourceJob cacheProductFeatureResourceJob;
|
||||
@Autowired
|
||||
private CacheRoleFeatureResourceJob cacheRoleFeatureResourceJob;
|
||||
@Autowired
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
@Autowired
|
||||
private RolePermissionCacheService rolePermissionCacheService;
|
||||
|
||||
/**
|
||||
* 统一层级的roleGroup按照id升序,sort从1递增
|
||||
@ -578,8 +600,8 @@ public class PrivateController {
|
||||
}
|
||||
|
||||
@PostMapping("/api/private/workspaceProduct/store")
|
||||
public Object storeWorkspaceProduct(@RequestBody WorkspaceProductService.StoreWorkspaceProductParam request) {
|
||||
workspaceProductService.storeWorkspaceProduct(request);
|
||||
public Object storeWorkspaceProduct(@RequestBody ProductSearchListReq request) throws Exception {
|
||||
cacheProductPermissionJob.execute(JSON.toJSONString(request));
|
||||
return "ok";
|
||||
}
|
||||
|
||||
@ -651,6 +673,53 @@ public class PrivateController {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
@PostMapping("/api/private/rolePermission/store")
|
||||
public Object storeRolePermission(@RequestBody RoleService.PageSaasRoleParam request) throws Exception {
|
||||
cacheRolePermissionJob.execute(JSON.toJSONString(request));
|
||||
return "ok";
|
||||
}
|
||||
|
||||
@PostMapping("/api/private/saasFeature/store")
|
||||
public Object storeSaasFeature(@RequestBody StoreFeatureParam request) throws Exception {
|
||||
cacheSaasFeatureJob.execute(request.getTerminal());
|
||||
return "ok";
|
||||
}
|
||||
|
||||
@PostMapping("/api/private/productSaasFeature/store")
|
||||
public Object storeProductSaasFeature(@RequestBody ProductSearchListReq request) throws Exception {
|
||||
cacheProductFeatureResourceJob.execute(JSON.toJSONString(request));
|
||||
return "ok";
|
||||
}
|
||||
|
||||
@PostMapping("/api/private/roleSaasFeature/store")
|
||||
public Object storeRoleSaasFeature(@RequestBody RoleService.PageSaasRoleParam request) throws Exception {
|
||||
cacheRoleFeatureResourceJob.execute(JSON.toJSONString(request));
|
||||
return "ok";
|
||||
}
|
||||
|
||||
@PostMapping("/api/private/saasFeature/list")
|
||||
public Object listSaasFeature(@RequestBody SaasFeatureResourceService.ListSaasFeatureResourceCache request) throws Exception {
|
||||
return saasFeatureResourceService.listCache(request);
|
||||
}
|
||||
|
||||
@PostMapping("/api/private/workspaceProductCached/list")
|
||||
public Object workspaceProductCached(@RequestBody WorkspaceProductService.ListWorkspaceProductPermissionCacheParam request) {
|
||||
return workspaceProductService.listWorkspaceProductPermissionCached(request);
|
||||
}
|
||||
|
||||
@PostMapping("/api/private/rolePermissionCache/list")
|
||||
public Object rolePermissionCache(@RequestBody RolePermissionCacheService.ListRolePermissionParam request) {
|
||||
return rolePermissionCacheService.list(request);
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class StoreFeatureParam {
|
||||
private String terminal;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
|
||||
@ -85,6 +85,7 @@ public class TyrSaasAuthController implements TyrSaasAuthApi {
|
||||
|
||||
@Override
|
||||
public ApiResult<List<ListIdentityFromPermissionResp>> listWorkspacePermissionIdentity(WorkspacePermissionIdentityReq req) {
|
||||
|
||||
return ApiResult.ok(tyrSaasAuthService.listWorkspacePermissionIdentity(req));
|
||||
}
|
||||
@Override
|
||||
|
||||
@ -0,0 +1,330 @@
|
||||
package cn.axzo.tyr.server.event.inner;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq;
|
||||
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
|
||||
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
|
||||
import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload;
|
||||
import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeature;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation;
|
||||
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
|
||||
import cn.axzo.tyr.server.service.ProductPermissionCacheService;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE;
|
||||
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE;
|
||||
|
||||
/**
|
||||
* 缓存产品的权限
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CacheProductPermissionHandler implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private EventConsumer eventConsumer;
|
||||
@Autowired
|
||||
private ProductPermissionCacheService productPermissionCacheService;
|
||||
@Autowired
|
||||
private ProductFeatureRelationService productFeatureRelationService;
|
||||
@Autowired
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
@Autowired
|
||||
private SaasFeatureDao saasFeatureDao;
|
||||
|
||||
private void storeProductPermission(List<SaasProductModuleFeatureRelation> productFeatures) {
|
||||
|
||||
if (CollectionUtils.isEmpty(productFeatures)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<ProductPermissionCacheService.ProductPermission> productPermissions = resolveProductPermissions(productFeatures);
|
||||
|
||||
if (CollectionUtils.isEmpty(productPermissions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ProductPermissionCacheService.StoreProductPermissionParam storeProductPermissionParam = ProductPermissionCacheService.StoreProductPermissionParam.builder()
|
||||
.productPermissions(productPermissions)
|
||||
.build();
|
||||
productPermissionCacheService.store(storeProductPermissionParam);
|
||||
}
|
||||
|
||||
public void onProductPermissionUpsert(Event event, EventConsumer.Context context) {
|
||||
log.info("begin cached product permission handler rocketmq event: {}", event);
|
||||
ProductPermissionCreatedPayload payload = event.normalizedData(ProductPermissionCreatedPayload.class);
|
||||
|
||||
if (CollectionUtils.isEmpty(payload.getProductModuleIds())) {
|
||||
return;
|
||||
}
|
||||
PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder()
|
||||
.productModuleIds(payload.getProductModuleIds())
|
||||
.build();
|
||||
List<SaasProductModuleFeatureRelation> productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq);
|
||||
|
||||
if (CollectionUtils.isEmpty(productFeatures)) {
|
||||
return;
|
||||
}
|
||||
|
||||
storeProductPermission(productFeatures);
|
||||
log.info("end cached product permission handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
public void onPageElementFeatureResourceUpsert(Event event, EventConsumer.Context context) {
|
||||
log.info("begin cached product permission handler rocketmq event: {}", event);
|
||||
PageElementFeatureResourceUpsertPayload payload = event.normalizedData(PageElementFeatureResourceUpsertPayload.class);
|
||||
|
||||
if (StringUtils.isBlank(payload.getTerminal())) {
|
||||
return;
|
||||
}
|
||||
|
||||
PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder()
|
||||
.build();
|
||||
List<SaasProductModuleFeatureRelation> productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq);
|
||||
|
||||
if (CollectionUtils.isEmpty(productFeatures)) {
|
||||
return;
|
||||
}
|
||||
storeProductPermission(productFeatures);
|
||||
log.info("end cached product permission handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
eventConsumer.registerHandler(EventTypeEnum.PRODUCT_PERMISSION_CREATED.getEventCode(), this::onProductPermissionUpsert);
|
||||
eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert);
|
||||
}
|
||||
|
||||
public List<ProductPermissionCacheService.ProductPermission> resolveProductPermissions(List<SaasProductModuleFeatureRelation> productPermissions) {
|
||||
if (CollectionUtils.isEmpty(productPermissions)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 新的菜单树是是把有权限点的父节点也存进去了,所以直接解析
|
||||
Map<Long, SaasFeatureResourceResp> featureResources = listSaasFeatureResource(productPermissions);
|
||||
|
||||
Map<Long, SaasFeatureResourceResp> parentFeatureResources = listParentSaasFeatureResource(featureResources);
|
||||
|
||||
// 旧的菜单树只存储了权限点信息,没有把父节点存进去,需要解析父节点进行存储
|
||||
Map<Long, SaasFeature> saasFeatures = listSaasFeature(productPermissions);
|
||||
|
||||
Map<Long, SaasFeature> parentSaasFeatures = listParentSaasFeature(saasFeatures);
|
||||
|
||||
return productPermissions.stream()
|
||||
.collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.map(e -> {
|
||||
List<SaasProductModuleFeatureRelation> productFeatureRelations = e.getValue();
|
||||
|
||||
if (CollectionUtils.isEmpty(productFeatureRelations)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ProductPermissionCacheService.PermissionDTO> permissions = productFeatureRelations.stream()
|
||||
.map(relation -> {
|
||||
if (Objects.equals(relation.getType(), NEW_FEATURE)) {
|
||||
return resolveFeatureResourcePermission(relation, featureResources, parentFeatureResources);
|
||||
}
|
||||
|
||||
return resolveFeaturePermission(relation, saasFeatures, parentSaasFeatures);
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(permissions)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ProductPermissionCacheService.ProductPermission.builder()
|
||||
.productId(e.getKey())
|
||||
.permissions(permissions)
|
||||
.build();
|
||||
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<ProductPermissionCacheService.PermissionDTO> resolveFeaturePermission(SaasProductModuleFeatureRelation relation, Map<Long, SaasFeature> saasFeatures, Map<Long, SaasFeature> parentSaasFeatures) {
|
||||
SaasFeature saasFeature = saasFeatures.get(relation.getFeatureId());
|
||||
if (Objects.isNull(saasFeature)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ProductPermissionCacheService.PermissionDTO> permissionDTOS = Lists.newArrayList(ProductPermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(saasFeature.getId())
|
||||
.featureCode(saasFeature.getFeatureCode())
|
||||
.featureType(saasFeature.getFeatureType())
|
||||
.terminal(saasFeature.getTerminal())
|
||||
.cooperateType(relation.getDictCode())
|
||||
.build());
|
||||
|
||||
List<ProductPermissionCacheService.PermissionDTO> parentPermissions = saasFeature.splitPath().stream()
|
||||
.map(parentSaasFeatures::get)
|
||||
.filter(Objects::nonNull)
|
||||
.map(f -> ProductPermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(f.getId())
|
||||
.featureCode(f.getFeatureCode())
|
||||
.featureType(f.getFeatureType())
|
||||
.terminal(f.getTerminal())
|
||||
.cooperateType(relation.getDictCode())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
permissionDTOS.addAll(parentPermissions);
|
||||
return permissionDTOS;
|
||||
}
|
||||
|
||||
private List<ProductPermissionCacheService.PermissionDTO> resolveFeatureResourcePermission(SaasProductModuleFeatureRelation relation, Map<Long, SaasFeatureResourceResp> featureResources, Map<Long, SaasFeatureResourceResp> parentFeatureResources) {
|
||||
SaasFeatureResourceResp featureResource = featureResources.get(relation.getFeatureId());
|
||||
// 菜单节点是不会关联元素code,所以缓存的featureCode使用菜单编码
|
||||
if (Objects.isNull(featureResource)) {
|
||||
return null;
|
||||
}
|
||||
Set<String> featureCodes = Optional.ofNullable(featureResource.getFeatureCodes())
|
||||
.orElseGet(() -> Sets.newHashSet(featureResource.getUniCode()));
|
||||
|
||||
if (CollectionUtils.isEmpty(featureCodes)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ProductPermissionCacheService.PermissionDTO> permissionDTOS = featureCodes.stream()
|
||||
.map(featureCode -> ProductPermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(featureResource.getId())
|
||||
.featureCode(featureCode)
|
||||
.featureType(featureResource.getFeatureType())
|
||||
.terminal(featureResource.getTerminal())
|
||||
.cooperateType(relation.getDictCode())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<ProductPermissionCacheService.PermissionDTO> parentPermissions = featureResource.resolvePath().stream()
|
||||
.map(parentFeatureResources::get)
|
||||
.filter(Objects::nonNull)
|
||||
.map(f -> {
|
||||
|
||||
Set<String> parentFeatureCodes = Optional.ofNullable(f.getFeatureCodes())
|
||||
.orElseGet(() -> Sets.newHashSet(f.getUniCode()));
|
||||
if (CollectionUtils.isEmpty(parentFeatureCodes)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return parentFeatureCodes.stream()
|
||||
.map(featureCode -> ProductPermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(f.getId())
|
||||
.featureCode(featureCode)
|
||||
.featureType(f.getFeatureType())
|
||||
.terminal(f.getTerminal())
|
||||
.cooperateType(relation.getDictCode())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
permissionDTOS.addAll(parentPermissions);
|
||||
return permissionDTOS;
|
||||
}
|
||||
|
||||
|
||||
private Map<Long, SaasFeatureResourceResp> listSaasFeatureResource(List<SaasProductModuleFeatureRelation> productPermissions) {
|
||||
|
||||
List<Long> featureIds = productPermissions.stream()
|
||||
.filter(e -> Objects.equals(e.getType(), NEW_FEATURE))
|
||||
.map(SaasProductModuleFeatureRelation::getFeatureId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(featureIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.ids(featureIds)
|
||||
.needFeatureCodes(true)
|
||||
.build();
|
||||
return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream()
|
||||
.collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s));
|
||||
}
|
||||
|
||||
private Map<Long, SaasFeatureResourceResp> listParentSaasFeatureResource(Map<Long, SaasFeatureResourceResp> productPermissions) {
|
||||
|
||||
List<Long> parentIds = productPermissions.values().stream()
|
||||
.map(SaasFeatureResourceResp::resolvePath)
|
||||
.flatMap(Collection::stream)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(parentIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.ids(parentIds)
|
||||
.needFeatureCodes(true)
|
||||
.build();
|
||||
return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream()
|
||||
.collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s));
|
||||
}
|
||||
|
||||
private Map<Long, SaasFeature> listSaasFeature(List<SaasProductModuleFeatureRelation> productPermissions) {
|
||||
|
||||
Set<Long> featureIds = productPermissions.stream()
|
||||
.filter(e -> Objects.equals(e.getType(), OLD_FEATURE))
|
||||
.map(SaasProductModuleFeatureRelation::getFeatureId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (CollectionUtils.isEmpty(featureIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
return saasFeatureDao.listByIds(featureIds).stream()
|
||||
.collect(Collectors.toMap(SaasFeature::getId, Function.identity()));
|
||||
}
|
||||
|
||||
private Map<Long, SaasFeature> listParentSaasFeature(Map<Long, SaasFeature> saasFeatures) {
|
||||
|
||||
if (CollectionUtils.isEmpty(saasFeatures)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
List<Long> parentIds = saasFeatures.values().stream()
|
||||
.map(SaasFeature::splitPath)
|
||||
.flatMap(Collection::stream)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(parentIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
return saasFeatureDao.listByIds(parentIds).stream()
|
||||
.collect(Collectors.toMap(SaasFeature::getId, Function.identity()));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,238 @@
|
||||
package cn.axzo.tyr.server.event.inner;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.framework.rocketmq.EventHandler;
|
||||
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
|
||||
import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq;
|
||||
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
|
||||
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
|
||||
import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload;
|
||||
import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation;
|
||||
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
|
||||
import cn.axzo.tyr.server.service.ProductSaasFeatureResourceCacheService;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CacheProductSaasFeatureResourceHandler implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private EventConsumer eventConsumer;
|
||||
@Autowired
|
||||
private ProductFeatureRelationService productFeatureRelationService;
|
||||
@Autowired
|
||||
private ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService;
|
||||
@Autowired
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
|
||||
public static final Set<Integer> FEATURE_RESOURCE_TYPES = Sets.newHashSet(FeatureResourceType.MENU.getCode(),
|
||||
FeatureResourceType.PAGE.getCode(),
|
||||
FeatureResourceType.MENU_PARTITION_GROUP.getCode(),
|
||||
FeatureResourceType.GROUP.getCode(),
|
||||
FeatureResourceType.APP_ENTRY.getCode());
|
||||
|
||||
private void storeProductFeatureResource(List<SaasProductModuleFeatureRelation> productFeatures) {
|
||||
|
||||
if (CollectionUtils.isEmpty(productFeatures)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<ProductSaasFeatureResourceCacheService.ProductFeatureResource> productFeatureResources = resolveProductFeatureResources(productFeatures);
|
||||
|
||||
if (CollectionUtils.isEmpty(productFeatureResources)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ProductSaasFeatureResourceCacheService.StoreProductFeatureResourceParam storeProductFeatureResourceParam = ProductSaasFeatureResourceCacheService.StoreProductFeatureResourceParam.builder()
|
||||
.productFeatureResources(productFeatureResources)
|
||||
.build();
|
||||
productSaasFeatureResourceCacheService.store(storeProductFeatureResourceParam);
|
||||
|
||||
}
|
||||
|
||||
public void onProductPermissionUpsert(Event event, EventConsumer.Context context) {
|
||||
log.info("begin cached product featureResource handler rocketmq event: {}", event);
|
||||
ProductPermissionCreatedPayload payload = event.normalizedData(ProductPermissionCreatedPayload.class);
|
||||
|
||||
if (CollectionUtils.isEmpty(payload.getProductModuleIds())) {
|
||||
return;
|
||||
}
|
||||
|
||||
PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder()
|
||||
.productModuleIds(payload.getProductModuleIds())
|
||||
.type(NEW_FEATURE)
|
||||
.build();
|
||||
List<SaasProductModuleFeatureRelation> productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq);
|
||||
|
||||
storeProductFeatureResource(productFeatures);
|
||||
log.info("end cached product featureResource handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
public void onPageElementFeatureResourceUpsert(Event event, EventConsumer.Context context) {
|
||||
log.info("begin cached product featureResource handler rocketmq event: {}", event);
|
||||
PageElementFeatureResourceUpsertPayload payload = event.normalizedData(PageElementFeatureResourceUpsertPayload.class);
|
||||
|
||||
if (StringUtils.isBlank(payload.getTerminal())) {
|
||||
return;
|
||||
}
|
||||
|
||||
PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder()
|
||||
.type(NEW_FEATURE)
|
||||
.build();
|
||||
List<SaasProductModuleFeatureRelation> productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq);
|
||||
|
||||
if (CollectionUtils.isEmpty(productFeatures)) {
|
||||
return;
|
||||
}
|
||||
storeProductFeatureResource(productFeatures);
|
||||
log.info("end cached product featureResource handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
eventConsumer.registerHandler(EventTypeEnum.PRODUCT_PERMISSION_CREATED.getEventCode(), this::onProductPermissionUpsert);
|
||||
eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert);
|
||||
|
||||
}
|
||||
|
||||
public List<ProductSaasFeatureResourceCacheService.ProductFeatureResource> resolveProductFeatureResources(List<SaasProductModuleFeatureRelation> productPermissions) {
|
||||
if (CollectionUtils.isEmpty(productPermissions)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Map<Long, SaasFeatureResourceResp> featureResources = listSaasFeatureResource(productPermissions);
|
||||
|
||||
Map<Long, SaasFeatureResourceResp> parentFeatureResources = listParentSaasFeatureResource(featureResources);
|
||||
|
||||
return productPermissions.stream()
|
||||
.collect(Collectors.groupingBy(SaasProductModuleFeatureRelation::getProductModuleId))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.map(e -> {
|
||||
List<SaasProductModuleFeatureRelation> productFeatureRelations = e.getValue();
|
||||
|
||||
if (CollectionUtils.isEmpty(productFeatureRelations)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> productFeatureResources = productFeatureRelations.stream()
|
||||
.map(relation -> {
|
||||
SaasFeatureResourceResp featureResource = featureResources.get(relation.getFeatureId());
|
||||
if (Objects.isNull(featureResource) || StringUtils.isBlank(featureResource.getUniCode())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> featureResourceDTOS = Lists.newArrayList(ProductSaasFeatureResourceCacheService.FeatureResourceDTO.builder()
|
||||
.featureId(featureResource.getId())
|
||||
.featureType(featureResource.getFeatureType())
|
||||
.terminal(featureResource.getTerminal())
|
||||
.uniCode(featureResource.getUniCode())
|
||||
.cooperateType(relation.getDictCode())
|
||||
.build());
|
||||
List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> parentPermissions = featureResource.resolvePath().stream()
|
||||
.map(parentFeatureResources::get)
|
||||
.filter(Objects::nonNull)
|
||||
.map(f -> {
|
||||
|
||||
if (StringUtils.isBlank(f.getUniCode())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ProductSaasFeatureResourceCacheService.FeatureResourceDTO.builder()
|
||||
.featureId(f.getId())
|
||||
.featureType(f.getFeatureType())
|
||||
.terminal(f.getTerminal())
|
||||
.uniCode(f.getUniCode())
|
||||
.cooperateType(relation.getDictCode())
|
||||
.build();
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
featureResourceDTOS.addAll(parentPermissions);
|
||||
|
||||
return featureResourceDTOS;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.distinct()
|
||||
.filter(f -> FEATURE_RESOURCE_TYPES.contains(f.getFeatureType()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(productFeatureResources)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ProductSaasFeatureResourceCacheService.ProductFeatureResource.builder()
|
||||
.productId(e.getKey())
|
||||
.featureResources(productFeatureResources)
|
||||
.build();
|
||||
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
private Map<Long, SaasFeatureResourceResp> listSaasFeatureResource(List<SaasProductModuleFeatureRelation> productPermissions) {
|
||||
|
||||
List<Long> featureIds = productPermissions.stream()
|
||||
.map(SaasProductModuleFeatureRelation::getFeatureId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(featureIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.ids(featureIds)
|
||||
.needFeatureCodes(true)
|
||||
.build();
|
||||
return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream()
|
||||
.collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s));
|
||||
}
|
||||
|
||||
private Map<Long, SaasFeatureResourceResp> listParentSaasFeatureResource(Map<Long, SaasFeatureResourceResp> productPermissions) {
|
||||
|
||||
List<Long> parentIds = productPermissions.values().stream()
|
||||
.map(SaasFeatureResourceResp::resolvePath)
|
||||
.flatMap(Collection::stream)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(parentIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.ids(parentIds)
|
||||
.needFeatureCodes(true)
|
||||
.build();
|
||||
return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream()
|
||||
.collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,324 @@
|
||||
package cn.axzo.tyr.server.event.inner;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.framework.rocketmq.EventHandler;
|
||||
import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq;
|
||||
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
|
||||
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
|
||||
import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes;
|
||||
import cn.axzo.tyr.client.model.res.SaasRoleRes;
|
||||
import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload;
|
||||
import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeature;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation;
|
||||
import cn.axzo.tyr.server.service.RolePermissionCacheService;
|
||||
import cn.axzo.tyr.server.service.RoleService;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE;
|
||||
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE;
|
||||
|
||||
/**
|
||||
* 缓存角色的权限
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CacheRolePermissionHandler implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private EventConsumer eventConsumer;
|
||||
@Autowired
|
||||
private RolePermissionCacheService rolePermissionCacheService;
|
||||
@Autowired
|
||||
private RoleService roleService;
|
||||
@Autowired
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
@Autowired
|
||||
private SaasFeatureDao saasFeatureDao;
|
||||
|
||||
private void storeRolePermission(List<SaasRoleRes> roles) {
|
||||
|
||||
if (CollectionUtils.isEmpty(roles)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<RolePermissionCacheService.RolePermission> rolePermissions = resolveRolePermission(roles);
|
||||
|
||||
if (CollectionUtils.isEmpty(rolePermissions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RolePermissionCacheService.StoreRolePermissionParam storeRolePermissionParam = RolePermissionCacheService.StoreRolePermissionParam.builder()
|
||||
.rolePermissions(rolePermissions)
|
||||
.build();
|
||||
rolePermissionCacheService.store(storeRolePermissionParam);
|
||||
}
|
||||
|
||||
public void onRolePermissionUpsert(Event event, EventConsumer.Context context) {
|
||||
log.info("begin cached role permission handler rocketmq event: {}", event);
|
||||
RolePermissionCreatedPayload payload = event.normalizedData(RolePermissionCreatedPayload.class);
|
||||
|
||||
if (CollectionUtils.isEmpty(payload.getRoleIds())) {
|
||||
return;
|
||||
}
|
||||
|
||||
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
|
||||
.roleIds(Lists.newArrayList(payload.getRoleIds()))
|
||||
.needPermissionRelation(true)
|
||||
.build();
|
||||
List<SaasRoleRes> roles = roleService.list(listSaasRoleParam);
|
||||
|
||||
storeRolePermission(roles);
|
||||
log.info("end cached role permission handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
public void onPageElementFeatureResourceUpsert(Event event, EventConsumer.Context context) {
|
||||
PageElementFeatureResourceUpsertPayload payload = event.normalizedData(PageElementFeatureResourceUpsertPayload.class);
|
||||
|
||||
if (StringUtils.isBlank(payload.getTerminal())) {
|
||||
return;
|
||||
}
|
||||
|
||||
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
|
||||
.needPermissionRelation(true)
|
||||
.build();
|
||||
List<SaasRoleRes> roles = roleService.list(listSaasRoleParam);
|
||||
|
||||
storeRolePermission(roles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
eventConsumer.registerHandler(EventTypeEnum.ROLE_PERMISSION_CREATED.getEventCode(), this::onRolePermissionUpsert);
|
||||
eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert);
|
||||
}
|
||||
|
||||
public List<RolePermissionCacheService.RolePermission> resolveRolePermission(List<SaasRoleRes> roles) {
|
||||
|
||||
|
||||
Map<Long, SaasFeatureResourceResp> featureResources = listSaasFeatureResource(roles);
|
||||
|
||||
Map<Long, SaasFeatureResourceResp> parentFeatureResources = listParentSaasFeatureResource(featureResources);
|
||||
|
||||
Map<Long, SaasFeature> saasFeatures = listSaasFeature(roles);
|
||||
|
||||
Map<Long, SaasFeature> parentSaasFeatures = listParentSaasFeature(saasFeatures);
|
||||
|
||||
|
||||
return roles.stream()
|
||||
.map(e -> {
|
||||
if (CollectionUtils.isEmpty(e.getPermissionRelations())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<RolePermissionCacheService.PermissionDTO> permissions = e.getPermissionRelations().stream()
|
||||
.distinct()
|
||||
.map(permissionRelation -> {
|
||||
if (Objects.equals(permissionRelation.getType(), NEW_FEATURE)) {
|
||||
return resolveFeatureResourcePermission(permissionRelation, featureResources, parentFeatureResources);
|
||||
}
|
||||
return resolveFeaturePermission(permissionRelation, saasFeatures, parentSaasFeatures);
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(permissions)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return RolePermissionCacheService.RolePermission.builder()
|
||||
.roleId(e.getId())
|
||||
.permissions(permissions)
|
||||
.build();
|
||||
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static List<RolePermissionCacheService.PermissionDTO> resolveFeaturePermission(SaasPermissionRelationRes permissionRelation, Map<Long, SaasFeature> saasFeatures, Map<Long, SaasFeature> parentSaasFeatures) {
|
||||
SaasFeature saasFeature = saasFeatures.get(permissionRelation.getFeatureId());
|
||||
if (Objects.isNull(saasFeature)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<RolePermissionCacheService.PermissionDTO> permissionDTOS = Lists.newArrayList(RolePermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(saasFeature.getId())
|
||||
.featureCode(saasFeature.getFeatureCode())
|
||||
.featureType(saasFeature.getFeatureType())
|
||||
.terminal(saasFeature.getTerminal())
|
||||
.build());
|
||||
|
||||
List<RolePermissionCacheService.PermissionDTO> parentPermissions = saasFeature.splitPath().stream()
|
||||
.map(parentSaasFeatures::get)
|
||||
.filter(Objects::nonNull)
|
||||
.map(f -> RolePermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(f.getId())
|
||||
.featureCode(f.getFeatureCode())
|
||||
.featureType(f.getFeatureType())
|
||||
.terminal(f.getTerminal())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
permissionDTOS.addAll(parentPermissions);
|
||||
return permissionDTOS;
|
||||
}
|
||||
|
||||
private static List<RolePermissionCacheService.PermissionDTO> resolveFeatureResourcePermission(SaasPermissionRelationRes permissionRelation, Map<Long, SaasFeatureResourceResp> featureResources, Map<Long, SaasFeatureResourceResp> parentFeatureResources) {
|
||||
SaasFeatureResourceResp featureResource = featureResources.get(permissionRelation.getFeatureId());
|
||||
// 菜单节点是不会关联元素code,所以缓存的featureCode使用菜单编码
|
||||
if (Objects.isNull(featureResource)) {
|
||||
return null;
|
||||
}
|
||||
Set<String> featureCodes = Optional.ofNullable(featureResource.getFeatureCodes())
|
||||
.orElseGet(() -> Sets.newHashSet(featureResource.getUniCode()));
|
||||
|
||||
if (CollectionUtils.isEmpty(featureCodes)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<RolePermissionCacheService.PermissionDTO> permissionDTOS = featureCodes.stream()
|
||||
.map(featureCode -> RolePermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(featureResource.getId())
|
||||
.featureCode(featureCode)
|
||||
.featureType(featureResource.getFeatureType())
|
||||
.terminal(featureResource.getTerminal())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<RolePermissionCacheService.PermissionDTO> parentPermissions = featureResource.resolvePath().stream()
|
||||
.map(parentFeatureResources::get)
|
||||
.filter(Objects::nonNull)
|
||||
.map(f -> {
|
||||
|
||||
Set<String> parentFeatureCodes = Optional.ofNullable(f.getFeatureCodes())
|
||||
.orElseGet(() -> Sets.newHashSet(f.getUniCode()));
|
||||
if (CollectionUtils.isEmpty(parentFeatureCodes)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return parentFeatureCodes.stream()
|
||||
.map(featureCode -> RolePermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(f.getId())
|
||||
.featureCode(featureCode)
|
||||
.featureType(f.getFeatureType())
|
||||
.terminal(f.getTerminal())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
permissionDTOS.addAll(parentPermissions);
|
||||
|
||||
return permissionDTOS;
|
||||
}
|
||||
|
||||
|
||||
private Map<Long, SaasFeatureResourceResp> listSaasFeatureResource(List<SaasRoleRes> roles) {
|
||||
|
||||
List<Long> featureIds = roles.stream()
|
||||
.filter(e -> !CollectionUtils.isEmpty(e.getPermissionRelations()))
|
||||
.map(SaasRoleRes::getPermissionRelations)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(e -> Objects.equals(e.getType(), NEW_FEATURE))
|
||||
.map(SaasPermissionRelationRes::getFeatureId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(featureIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.ids(featureIds)
|
||||
.needFeatureCodes(true)
|
||||
.build();
|
||||
return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream()
|
||||
.collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s));
|
||||
}
|
||||
|
||||
private Map<Long, SaasFeatureResourceResp> listParentSaasFeatureResource(Map<Long, SaasFeatureResourceResp> productPermissions) {
|
||||
|
||||
List<Long> parentIds = productPermissions.values().stream()
|
||||
.map(SaasFeatureResourceResp::resolvePath)
|
||||
.flatMap(Collection::stream)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(parentIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.ids(parentIds)
|
||||
.needFeatureCodes(true)
|
||||
.build();
|
||||
return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream()
|
||||
.collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s));
|
||||
}
|
||||
|
||||
private Map<Long, SaasFeature> listSaasFeature(List<SaasRoleRes> roles) {
|
||||
|
||||
Set<Long> featureIds = roles.stream()
|
||||
.filter(e -> !CollectionUtils.isEmpty(e.getPermissionRelations()))
|
||||
.map(SaasRoleRes::getPermissionRelations)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(e -> Objects.equals(e.getType(), OLD_FEATURE))
|
||||
.map(SaasPermissionRelationRes::getFeatureId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (CollectionUtils.isEmpty(featureIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
return saasFeatureDao.listByIds(featureIds)
|
||||
.stream()
|
||||
.collect(Collectors.toMap(SaasFeature::getId, Function.identity(), (f, s) -> s));
|
||||
}
|
||||
|
||||
private Map<Long, SaasFeature> listParentSaasFeature(Map<Long, SaasFeature> saasFeatures) {
|
||||
|
||||
if (CollectionUtils.isEmpty(saasFeatures)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
List<Long> parentIds = saasFeatures.values().stream()
|
||||
.map(SaasFeature::splitPath)
|
||||
.flatMap(Collection::stream)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(parentIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
return saasFeatureDao.listByIds(parentIds).stream()
|
||||
.collect(Collectors.toMap(SaasFeature::getId, Function.identity()));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,221 @@
|
||||
package cn.axzo.tyr.server.event.inner;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
|
||||
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
|
||||
import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes;
|
||||
import cn.axzo.tyr.client.model.res.SaasRoleRes;
|
||||
import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload;
|
||||
import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload;
|
||||
import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService;
|
||||
import cn.axzo.tyr.server.service.RoleService;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.tyr.server.event.inner.CacheProductSaasFeatureResourceHandler.FEATURE_RESOURCE_TYPES;
|
||||
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE;
|
||||
|
||||
/**
|
||||
* 因为菜单树不一定有权限code
|
||||
* 登录时需要查询菜单树,所以把菜单树缓存起来
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CacheRoleSaasFeatureResourceHandler implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private EventConsumer eventConsumer;
|
||||
@Autowired
|
||||
private RoleService roleService;
|
||||
@Autowired
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
@Autowired
|
||||
private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService;
|
||||
|
||||
private void storeRoleFeatureResource(List<SaasRoleRes> roles) {
|
||||
|
||||
if (CollectionUtils.isEmpty(roles)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<RoleSaasFeatureResourceCacheService.RoleFeatureResource> rolePermissions = resolveRoleFeatureResource(roles);
|
||||
|
||||
if (CollectionUtils.isEmpty(rolePermissions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam storeRoleFeatureResourceParam = RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam.builder()
|
||||
.roleSaasFeatureResources(rolePermissions)
|
||||
.build();
|
||||
roleSaasFeatureResourceCacheService.store(storeRoleFeatureResourceParam);
|
||||
}
|
||||
public void onRolePermissionUpsert(Event event, EventConsumer.Context context) {
|
||||
log.info("begin cached role saasFeatureResource handler rocketmq event: {}", event);
|
||||
RolePermissionCreatedPayload payload = event.normalizedData(RolePermissionCreatedPayload.class);
|
||||
|
||||
if (CollectionUtils.isEmpty(payload.getRoleIds())) {
|
||||
return;
|
||||
}
|
||||
|
||||
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
|
||||
.roleIds(Lists.newArrayList(payload.getRoleIds()))
|
||||
.needPermissionRelation(true)
|
||||
.type(NEW_FEATURE)
|
||||
.build();
|
||||
List<SaasRoleRes> roles = roleService.list(listSaasRoleParam);
|
||||
|
||||
storeRoleFeatureResource(roles);
|
||||
|
||||
log.info("end cached role saasFeatureResource handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
public void onPageElementFeatureResourceUpsert(Event event, EventConsumer.Context context) {
|
||||
PageElementFeatureResourceUpsertPayload payload = event.normalizedData(PageElementFeatureResourceUpsertPayload.class);
|
||||
|
||||
if (StringUtils.isBlank(payload.getTerminal())) {
|
||||
return;
|
||||
}
|
||||
|
||||
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
|
||||
.needPermissionRelation(true)
|
||||
.type(NEW_FEATURE)
|
||||
.build();
|
||||
List<SaasRoleRes> roles = roleService.list(listSaasRoleParam);
|
||||
|
||||
storeRoleFeatureResource(roles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
eventConsumer.registerHandler(EventTypeEnum.ROLE_PERMISSION_CREATED.getEventCode(), this::onRolePermissionUpsert);
|
||||
eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert);
|
||||
|
||||
}
|
||||
|
||||
public List<RoleSaasFeatureResourceCacheService.RoleFeatureResource> resolveRoleFeatureResource(List<SaasRoleRes> roles) {
|
||||
|
||||
Map<Long, SaasFeatureResourceResp> featureResources = listSaasFeatureResource(roles);
|
||||
|
||||
Map<Long, SaasFeatureResourceResp> parentFeatureResources = listParentSaasFeatureResource(featureResources);
|
||||
|
||||
return roles.stream()
|
||||
.map(e -> {
|
||||
if (CollectionUtils.isEmpty(e.getPermissionRelations())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO> permissions = e.getPermissionRelations().stream()
|
||||
.distinct()
|
||||
.map(permissionRelation -> {
|
||||
SaasFeatureResourceResp featureResource = featureResources.get(permissionRelation.getFeatureId());
|
||||
if (Objects.isNull(featureResource) || StringUtils.isBlank(featureResource.getUniCode())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO> featureResourceDTOS = Lists.newArrayList(RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO.builder()
|
||||
.featureId(featureResource.getId())
|
||||
.featureType(featureResource.getFeatureType())
|
||||
.terminal(featureResource.getTerminal())
|
||||
.uniCode(featureResource.getUniCode())
|
||||
.build());
|
||||
List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO> parentPermissions = featureResource.resolvePath().stream()
|
||||
.map(parentFeatureResources::get)
|
||||
.filter(Objects::nonNull)
|
||||
.map(f -> {
|
||||
|
||||
if (StringUtils.isBlank(f.getUniCode())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO.builder()
|
||||
.featureId(f.getId())
|
||||
.featureType(f.getFeatureType())
|
||||
.terminal(f.getTerminal())
|
||||
.uniCode(f.getUniCode())
|
||||
.build();
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
featureResourceDTOS.addAll(parentPermissions);
|
||||
|
||||
return featureResourceDTOS;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.distinct()
|
||||
.filter(f -> FEATURE_RESOURCE_TYPES.contains(f.getFeatureType()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(permissions)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return RoleSaasFeatureResourceCacheService.RoleFeatureResource.builder()
|
||||
.roleId(e.getId())
|
||||
.saasFeatureResources(permissions)
|
||||
.build();
|
||||
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Map<Long, SaasFeatureResourceResp> listSaasFeatureResource(List<SaasRoleRes> roles) {
|
||||
|
||||
List<Long> featureIds = roles.stream()
|
||||
.filter(e -> !CollectionUtils.isEmpty(e.getPermissionRelations()))
|
||||
.map(SaasRoleRes::getPermissionRelations)
|
||||
.flatMap(Collection::stream)
|
||||
.map(SaasPermissionRelationRes::getFeatureId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(featureIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.ids(featureIds)
|
||||
.needFeatureCodes(true)
|
||||
.build();
|
||||
return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream()
|
||||
.collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s));
|
||||
}
|
||||
|
||||
private Map<Long, SaasFeatureResourceResp> listParentSaasFeatureResource(Map<Long, SaasFeatureResourceResp> productPermissions) {
|
||||
|
||||
List<Long> parentIds = productPermissions.values().stream()
|
||||
.map(SaasFeatureResourceResp::resolvePath)
|
||||
.flatMap(Collection::stream)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(parentIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// 存在pre环境更改了节点的父节点,可能导致产品没有父节点的权限,这里补齐父节点的权限
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.ids(parentIds)
|
||||
.needFeatureCodes(true)
|
||||
.build();
|
||||
return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream()
|
||||
.collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
package cn.axzo.tyr.server.event.inner;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.framework.rocketmq.EventHandler;
|
||||
import cn.axzo.tyr.client.model.enums.DelegatedType;
|
||||
import cn.axzo.tyr.server.event.payload.SaasFeatureUpsertPayload;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeature;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 缓存全量权限点,因为鉴权等逻辑,需要查询免授权和权限点是否存在,数据量大,数据库压力大
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CacheSaasFeatureHandler implements EventHandler, InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private EventConsumer eventConsumer;
|
||||
@Autowired
|
||||
private SaasFeatureDao saasFeatureDao;
|
||||
@Autowired
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event, EventConsumer.Context context) {
|
||||
log.info("begin cached saasFeature handler rocketmq event: {}", event);
|
||||
SaasFeatureUpsertPayload payload = event.normalizedData(SaasFeatureUpsertPayload.class);
|
||||
|
||||
if (StringUtils.isBlank(payload.getTerminal())) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<SaasFeatureResourceService.SaasFeatureResourceCache> saasFeatures = saasFeatureDao.lambdaQuery()
|
||||
.eq(SaasFeature::getTerminal, payload.getTerminal())
|
||||
.list()
|
||||
.stream()
|
||||
.map(e -> SaasFeatureResourceService.SaasFeatureResourceCache.builder()
|
||||
.featureId(e.getId())
|
||||
.notAuth(DelegatedType.notAuth(e.getDelegatedType()))
|
||||
.parentIds(e.splitPath())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
SaasFeatureResourceService.SaasFeatureResourceDTO saasFeatureResourceDTO = SaasFeatureResourceService.SaasFeatureResourceDTO.builder()
|
||||
.terminal(payload.getTerminal())
|
||||
.features(saasFeatures)
|
||||
.build();
|
||||
SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder()
|
||||
.saasFeatureResources(Lists.newArrayList(saasFeatureResourceDTO))
|
||||
.build();
|
||||
saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache);
|
||||
|
||||
|
||||
log.info("end cached saasFeature handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_UPSERT.getEventCode(), this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
package cn.axzo.tyr.server.event.inner;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.framework.rocketmq.EventHandler;
|
||||
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
|
||||
import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 缓存全量权限点,因为鉴权等逻辑,需要查询免授权和权限点是否存在,数据量大,数据库压力大
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CacheSaasFeatureResourceHandler implements EventHandler, InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private EventConsumer eventConsumer;
|
||||
@Autowired
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event, EventConsumer.Context context) {
|
||||
log.info("begin cached saasFeatureResource handler rocketmq event: {}", event);
|
||||
SaasFeatureResourceUpsertPayload payload = event.normalizedData(SaasFeatureResourceUpsertPayload.class);
|
||||
|
||||
if (StringUtils.isBlank(payload.getTerminal())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 直接查询缓存所有节点,因为修改的代码不好改
|
||||
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.terminal(payload.getTerminal())
|
||||
.build();
|
||||
|
||||
List<SaasFeatureResourceService.SaasFeatureResourceCache> saasFeatures = saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream()
|
||||
.map(e -> SaasFeatureResourceService.SaasFeatureResourceCache.builder()
|
||||
.featureId(e.getId())
|
||||
.notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType()))
|
||||
.parentIds(e.resolvePath())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
SaasFeatureResourceService.SaasFeatureResourceDTO saasFeatureResourceDTO = SaasFeatureResourceService.SaasFeatureResourceDTO.builder()
|
||||
.terminal(payload.getTerminal())
|
||||
.features(saasFeatures)
|
||||
.build();
|
||||
SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder()
|
||||
.saasFeatureResources(Lists.newArrayList(saasFeatureResourceDTO))
|
||||
.build();
|
||||
saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache);
|
||||
|
||||
log.info("end cached saasFeatureResource handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT.getEventCode(), this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package cn.axzo.tyr.server.event.inner;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum EventTypeEnum {
|
||||
|
||||
PRODUCT_PERMISSION_CREATED("product-permission", "product-permission-created", "产品权限添加"),
|
||||
ROLE_PERMISSION_CREATED("role-permission", "role-permission-created", "角色权限添加"),
|
||||
SAAS_FEATURE_UPSERT("saas-feature", "saas-feature-upsert", "旧菜单树更新"),
|
||||
SAAS_FEATURE_RESOURCE_UPSERT("saas-feature-resource", "saas-feature-resource-upsert", "新菜单树更新"),
|
||||
PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT("page-element-feature-resource", "page-element-feature-resource-upsert", "菜单-页面元素绑定关系更新"),
|
||||
;
|
||||
|
||||
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,85 @@
|
||||
package cn.axzo.tyr.server.event.outer;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.tyr.client.model.enums.DelegatedType;
|
||||
import cn.axzo.tyr.server.event.payload.SaasFeatureDeletedPayload;
|
||||
import cn.axzo.tyr.server.event.payload.SaasFeatureUpsertPayload;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeature;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 缓存全量权限点,因为鉴权等逻辑,需要查询免授权和权限点是否存在,数据量大,数据库压力大
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CacheSaasFeatureOldHandler implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private EventConsumer eventConsumer;
|
||||
@Autowired
|
||||
private SaasFeatureDao saasFeatureDao;
|
||||
@Autowired
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
|
||||
public void onSaasFeatureUpserted(Event event, EventConsumer.Context context) {
|
||||
log.info("begin cached saasFeature handler rocketmq event: {}", event);
|
||||
SaasFeatureUpsertPayload payload = event.normalizedData(SaasFeatureUpsertPayload.class);
|
||||
|
||||
if (StringUtils.isBlank(payload.getTerminal())) {
|
||||
return;
|
||||
}
|
||||
cacheFeature(payload.getTerminal());
|
||||
log.info("end cached saasFeature handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
public void onSaasFeatureDeleted(Event event, EventConsumer.Context context) {
|
||||
log.info("begin cached saasFeature handler rocketmq event: {}", event);
|
||||
SaasFeatureDeletedPayload payload = event.normalizedData(SaasFeatureDeletedPayload.class);
|
||||
|
||||
if (StringUtils.isBlank(payload.getTerminal())) {
|
||||
return;
|
||||
}
|
||||
|
||||
cacheFeature(payload.getTerminal());
|
||||
|
||||
log.info("end cached saasFeature handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
private void cacheFeature(String terminal) {
|
||||
List<SaasFeatureResourceService.SaasFeatureResourceCache> saasFeatures = saasFeatureDao.lambdaQuery()
|
||||
.eq(SaasFeature::getTerminal, terminal)
|
||||
.list()
|
||||
.stream()
|
||||
.map(e -> SaasFeatureResourceService.SaasFeatureResourceCache.builder()
|
||||
.featureId(e.getId())
|
||||
.notAuth(DelegatedType.notAuth(e.getDelegatedType()))
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
SaasFeatureResourceService.SaasFeatureResourceDTO saasFeatureResourceDTO = SaasFeatureResourceService.SaasFeatureResourceDTO.builder()
|
||||
.terminal(terminal)
|
||||
.features(saasFeatures)
|
||||
.build();
|
||||
SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder()
|
||||
.saasFeatureResources(Lists.newArrayList(saasFeatureResourceDTO))
|
||||
.build();
|
||||
saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_UPSERT.getEventCode(), this::onSaasFeatureUpserted);
|
||||
eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_DELETED.getEventCode(), this::onSaasFeatureDeleted);
|
||||
}
|
||||
}
|
||||
@ -12,6 +12,8 @@ import lombok.Getter;
|
||||
public enum EventTypeEnum {
|
||||
|
||||
SERVICE_PKG_PRODUCT_CREATED("service-pkg-product", "service-pkg-product-created", "创建服务包的产品"),
|
||||
SAAS_FEATURE_UPSERT("saas-feature", "saas-feature-upsert", "旧菜单树更新"),
|
||||
SAAS_FEATURE_DELETED("saas-feature", "saas-feature-deleted", "旧菜单树删除"),
|
||||
;
|
||||
|
||||
EventTypeEnum(String model, String name, String desc) {
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
package cn.axzo.tyr.server.event.payload;
|
||||
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PageElementFeatureResourceUpsertPayload implements Serializable {
|
||||
|
||||
private String terminal;
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
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.util.Set;
|
||||
|
||||
/**
|
||||
* 产品权限点做了更新,没有发送相关权限点消息,是因为日志太大,只能消费的时候实时查询
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ProductPermissionCreatedPayload implements Serializable {
|
||||
|
||||
private Set<Long> productModuleIds;
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
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.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* 角色权限点做了更新,没有发送相关权限点消息,是因为日志太大,只能消费的时候实时查询
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RolePermissionCreatedPayload implements Serializable {
|
||||
|
||||
private Set<Long> roleIds;
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package cn.axzo.tyr.server.event.payload;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SaasFeatureDeletedPayload implements Serializable {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String terminal;
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package cn.axzo.tyr.server.event.payload;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SaasFeatureResourceUpsertPayload implements Serializable {
|
||||
|
||||
private String terminal;
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package cn.axzo.tyr.server.event.payload;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SaasFeatureUpsertPayload implements Serializable {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String terminal;
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
package cn.axzo.tyr.server.job;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.tyr.client.model.product.ProductSearchListReq;
|
||||
import cn.axzo.tyr.client.model.product.ProductVO;
|
||||
import cn.axzo.tyr.server.event.inner.CacheProductSaasFeatureResourceHandler;
|
||||
import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload;
|
||||
import cn.axzo.tyr.server.service.ProductService;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.handler.IJobHandler;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CacheProductFeatureResourceJob extends IJobHandler {
|
||||
|
||||
@Autowired
|
||||
private CacheProductSaasFeatureResourceHandler cacheProductSaasFeatureResourceHandler;
|
||||
@Autowired
|
||||
private ProductService productService;
|
||||
|
||||
@Override
|
||||
@XxlJob("CacheProductFeatureResourceJob")
|
||||
public ReturnT<String> execute(String s) throws Exception {
|
||||
|
||||
log.info("start CacheProductFeatureResourceJob, s:{}", s);
|
||||
ProductSearchListReq productSearchListReq = Optional.ofNullable(s)
|
||||
.map(e -> JSONObject.parseObject(e, ProductSearchListReq.class))
|
||||
.orElseGet(ProductSearchListReq::new);
|
||||
|
||||
Set<Long> productIds = productService.list(productSearchListReq).getData()
|
||||
.stream()
|
||||
.map(ProductVO::getId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
ProductPermissionCreatedPayload payload = ProductPermissionCreatedPayload.builder()
|
||||
.productModuleIds(productIds)
|
||||
.build();
|
||||
|
||||
Event event = Event.builder()
|
||||
.data(payload)
|
||||
.build();
|
||||
cacheProductSaasFeatureResourceHandler.onProductPermissionUpsert(event, null);
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
package cn.axzo.tyr.server.job;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.tyr.client.model.product.ProductSearchListReq;
|
||||
import cn.axzo.tyr.client.model.product.ProductVO;
|
||||
import cn.axzo.tyr.server.event.inner.CacheProductPermissionHandler;
|
||||
import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload;
|
||||
import cn.axzo.tyr.server.service.ProductService;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.handler.IJobHandler;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CacheProductPermissionJob extends IJobHandler {
|
||||
|
||||
@Autowired
|
||||
private CacheProductPermissionHandler cacheProductPermissionHandler;
|
||||
@Autowired
|
||||
private ProductService productService;
|
||||
|
||||
@Override
|
||||
@XxlJob("CacheProductPermissionJob")
|
||||
public ReturnT<String> execute(String s) throws Exception {
|
||||
|
||||
log.info("start CacheProductPermissionJob, s:{}", s);
|
||||
ProductSearchListReq productSearchListReq = Optional.ofNullable(s)
|
||||
.map(e -> JSONObject.parseObject(e, ProductSearchListReq.class))
|
||||
.orElseGet(ProductSearchListReq::new);
|
||||
|
||||
Set<Long> productIds = productService.list(productSearchListReq).getData()
|
||||
.stream()
|
||||
.map(ProductVO::getId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
ProductPermissionCreatedPayload payload = ProductPermissionCreatedPayload.builder()
|
||||
.productModuleIds(productIds)
|
||||
.build();
|
||||
|
||||
Event event = Event.builder()
|
||||
.data(payload)
|
||||
.build();
|
||||
cacheProductPermissionHandler.onProductPermissionUpsert(event, null);
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,131 @@
|
||||
package cn.axzo.tyr.server.job;
|
||||
|
||||
import cn.axzo.foundation.page.PageResp;
|
||||
import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes;
|
||||
import cn.axzo.tyr.client.model.res.SaasRoleRes;
|
||||
import cn.axzo.tyr.server.event.inner.CacheRoleSaasFeatureResourceHandler;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPgroupRoleRelationDao;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPgroupRoleRelation;
|
||||
import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService;
|
||||
import cn.axzo.tyr.server.service.RoleService;
|
||||
import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.handler.IJobHandler;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CacheRoleFeatureResourceJob extends IJobHandler {
|
||||
|
||||
@Autowired
|
||||
private CacheRoleSaasFeatureResourceHandler cacheRoleSaasFeatureResourceHandler;
|
||||
@Autowired
|
||||
private RoleService roleService;
|
||||
@Autowired
|
||||
private SaasPgroupPermissionRelationService saasPgroupPermissionRelationService;
|
||||
@Autowired
|
||||
private SaasPgroupRoleRelationDao saasPgroupRoleRelationDao;
|
||||
@Autowired
|
||||
private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService;
|
||||
|
||||
private static final Integer DEFAULT_PAGE_SIZE = 2000;
|
||||
|
||||
@Override
|
||||
@XxlJob("CacheRoleFeatureResourceJob")
|
||||
public ReturnT<String> execute(String s) throws Exception {
|
||||
|
||||
log.info("start CacheRoleFeatureResourceJob, s:{}", s);
|
||||
RoleService.PageSaasRoleParam pageSaasRoleParam = Optional.ofNullable(s)
|
||||
.map(e -> JSONObject.parseObject(e, RoleService.PageSaasRoleParam.class))
|
||||
.orElseGet(() -> RoleService.PageSaasRoleParam.builder().build());
|
||||
|
||||
// 因为角色权限集是重复使用,通过角色找权限集数据量太大,直接查询所有权限集的权限,比较快
|
||||
Map<Long, List<SaasPermissionRelationRes>> permissionRelations = listPgroupPermissionRelation();
|
||||
|
||||
Integer pageNumber = 1;
|
||||
while (true) {
|
||||
pageSaasRoleParam.setPage(pageNumber++);
|
||||
pageSaasRoleParam.setPageSize(DEFAULT_PAGE_SIZE);
|
||||
PageResp<SaasRoleRes> page = roleService.page(pageSaasRoleParam);
|
||||
|
||||
store(page.getData(), permissionRelations);
|
||||
|
||||
if (!page.hasNext()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
private Map<Long, List<SaasPermissionRelationRes>> listPgroupPermissionRelation() {
|
||||
return saasPgroupPermissionRelationService.list().stream()
|
||||
.collect(Collectors.groupingBy(SaasPgroupPermissionRelation::getGroupId,
|
||||
Collectors.mapping(e -> SaasPermissionRelationRes.builder()
|
||||
.featureId(e.getFeatureId())
|
||||
.featureType(e.getFeatureType())
|
||||
.type(e.getType())
|
||||
.build(), Collectors.toList())));
|
||||
|
||||
}
|
||||
|
||||
private Map<Long, Set<Long>> listPermissionGroup(List<Long> roleIds) {
|
||||
|
||||
return saasPgroupRoleRelationDao.findByRoleIds(roleIds).stream()
|
||||
.collect(Collectors.groupingBy(SaasPgroupRoleRelation::getRoleId,
|
||||
Collectors.mapping(SaasPgroupRoleRelation::getGroupId, Collectors.toSet())));
|
||||
}
|
||||
|
||||
private void store(List<SaasRoleRes> roles,
|
||||
Map<Long, List<SaasPermissionRelationRes>> permissionRelations) {
|
||||
|
||||
if (CollectionUtils.isEmpty(roles)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Long> roleIds = roles.stream()
|
||||
.map(SaasRoleRes::getId)
|
||||
.collect(Collectors.toList());
|
||||
Map<Long, Set<Long>> roleGroupMap = listPermissionGroup(roleIds);
|
||||
|
||||
roles.forEach(e -> {
|
||||
Set<Long> groupIds = roleGroupMap.get(e.getId());
|
||||
if (CollectionUtils.isEmpty(groupIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<SaasPermissionRelationRes> rolePermissions = groupIds.stream()
|
||||
.map(permissionRelations::get)
|
||||
.filter(f -> !CollectionUtils.isEmpty(f))
|
||||
.flatMap(Collection::stream)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
e.setPermissionRelations(rolePermissions);
|
||||
});
|
||||
|
||||
List<RoleSaasFeatureResourceCacheService.RoleFeatureResource> roleFeatureResources = cacheRoleSaasFeatureResourceHandler.resolveRoleFeatureResource(roles);
|
||||
|
||||
if (CollectionUtils.isEmpty(roleFeatureResources)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam storeRolePermissionParam = RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam.builder()
|
||||
.roleSaasFeatureResources(roleFeatureResources)
|
||||
.build();
|
||||
roleSaasFeatureResourceCacheService.store(storeRolePermissionParam);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,131 @@
|
||||
package cn.axzo.tyr.server.job;
|
||||
|
||||
import cn.axzo.foundation.page.PageResp;
|
||||
import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes;
|
||||
import cn.axzo.tyr.client.model.res.SaasRoleRes;
|
||||
import cn.axzo.tyr.server.event.inner.CacheRolePermissionHandler;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPgroupRoleRelationDao;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPgroupRoleRelation;
|
||||
import cn.axzo.tyr.server.service.RolePermissionCacheService;
|
||||
import cn.axzo.tyr.server.service.RoleService;
|
||||
import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.handler.IJobHandler;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CacheRolePermissionJob extends IJobHandler {
|
||||
|
||||
@Autowired
|
||||
private CacheRolePermissionHandler cacheRolePermissionHandler;
|
||||
@Autowired
|
||||
private RoleService roleService;
|
||||
@Autowired
|
||||
private SaasPgroupPermissionRelationService saasPgroupPermissionRelationService;
|
||||
@Autowired
|
||||
private SaasPgroupRoleRelationDao saasPgroupRoleRelationDao;
|
||||
@Autowired
|
||||
private RolePermissionCacheService rolePermissionCacheService;
|
||||
|
||||
private static final Integer DEFAULT_PAGE_SIZE = 2000;
|
||||
|
||||
@Override
|
||||
@XxlJob("CacheRolePermissionJob")
|
||||
public ReturnT<String> execute(String s) throws Exception {
|
||||
|
||||
log.info("start CacheRolePermissionJob, s:{}", s);
|
||||
RoleService.PageSaasRoleParam pageSaasRoleParam = Optional.ofNullable(s)
|
||||
.map(e -> JSONObject.parseObject(e, RoleService.PageSaasRoleParam.class))
|
||||
.orElseGet(() -> RoleService.PageSaasRoleParam.builder().build());
|
||||
|
||||
// 因为角色权限集是重复使用,通过角色找权限集数据量太大,直接查询所有权限集的权限,比较快
|
||||
Map<Long, List<SaasPermissionRelationRes>> permissionRelations = listPgroupPermissionRelation();
|
||||
|
||||
Integer pageNumber = 1;
|
||||
while (true) {
|
||||
pageSaasRoleParam.setPage(pageNumber++);
|
||||
pageSaasRoleParam.setPageSize(DEFAULT_PAGE_SIZE);
|
||||
PageResp<SaasRoleRes> page = roleService.page(pageSaasRoleParam);
|
||||
|
||||
store(page.getData(), permissionRelations);
|
||||
|
||||
if (!page.hasNext()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
private Map<Long, List<SaasPermissionRelationRes>> listPgroupPermissionRelation() {
|
||||
return saasPgroupPermissionRelationService.list().stream()
|
||||
.collect(Collectors.groupingBy(SaasPgroupPermissionRelation::getGroupId,
|
||||
Collectors.mapping(e -> SaasPermissionRelationRes.builder()
|
||||
.featureId(e.getFeatureId())
|
||||
.featureType(e.getFeatureType())
|
||||
.type(e.getType())
|
||||
.build(), Collectors.toList())));
|
||||
|
||||
}
|
||||
|
||||
private Map<Long, Set<Long>> listPermissionGroup(List<Long> roleIds) {
|
||||
|
||||
return saasPgroupRoleRelationDao.findByRoleIds(roleIds).stream()
|
||||
.collect(Collectors.groupingBy(SaasPgroupRoleRelation::getRoleId,
|
||||
Collectors.mapping(SaasPgroupRoleRelation::getGroupId, Collectors.toSet())));
|
||||
}
|
||||
|
||||
private void store(List<SaasRoleRes> roles,
|
||||
Map<Long, List<SaasPermissionRelationRes>> permissionRelations) {
|
||||
|
||||
if (CollectionUtils.isEmpty(roles)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Long> roleIds = roles.stream()
|
||||
.map(SaasRoleRes::getId)
|
||||
.collect(Collectors.toList());
|
||||
Map<Long, Set<Long>> roleGroupMap = listPermissionGroup(roleIds);
|
||||
|
||||
roles.forEach(e -> {
|
||||
Set<Long> groupIds = roleGroupMap.get(e.getId());
|
||||
if (CollectionUtils.isEmpty(groupIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<SaasPermissionRelationRes> rolePermissions = groupIds.stream()
|
||||
.map(permissionRelations::get)
|
||||
.filter(f -> !CollectionUtils.isEmpty(f))
|
||||
.flatMap(Collection::stream)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
e.setPermissionRelations(rolePermissions);
|
||||
});
|
||||
|
||||
List<RolePermissionCacheService.RolePermission> rolePermissions = cacheRolePermissionHandler.resolveRolePermission(roles);
|
||||
|
||||
if (CollectionUtils.isEmpty(rolePermissions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RolePermissionCacheService.StoreRolePermissionParam storeRolePermissionParam = RolePermissionCacheService.StoreRolePermissionParam.builder()
|
||||
.rolePermissions(rolePermissions)
|
||||
.build();
|
||||
rolePermissionCacheService.store(storeRolePermissionParam);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
package cn.axzo.tyr.server.job;
|
||||
|
||||
import cn.axzo.tyr.client.model.enums.DelegatedType;
|
||||
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
|
||||
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeature;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.handler.IJobHandler;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CacheSaasFeatureJob extends IJobHandler {
|
||||
|
||||
@Autowired
|
||||
private SaasFeatureDao saasFeatureDao;
|
||||
@Autowired
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
|
||||
@Override
|
||||
@XxlJob("CacheSaasFeatureJob")
|
||||
public ReturnT<String> execute(String s) throws Exception {
|
||||
|
||||
log.info("start CacheSaasFeatureJob, s:{}", s);
|
||||
|
||||
cacheSaasFeature(s);
|
||||
|
||||
cacheSaasFeatureResource(s);
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
private void cacheSaasFeature(String terminal) {
|
||||
Map<String, List<SaasFeatureResourceService.SaasFeatureResourceCache>> saasFeatures = saasFeatureDao.lambdaQuery()
|
||||
.eq(StringUtils.isNotBlank(terminal), SaasFeature::getTerminal, terminal)
|
||||
.list()
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(SaasFeature::getTerminal,
|
||||
Collectors.mapping(e -> SaasFeatureResourceService.SaasFeatureResourceCache
|
||||
.builder()
|
||||
.featureId(e.getId())
|
||||
.notAuth(DelegatedType.notAuth(e.getDelegatedType()))
|
||||
.parentIds(e.splitPath())
|
||||
.build(), Collectors.toList())));
|
||||
|
||||
List<SaasFeatureResourceService.SaasFeatureResourceDTO> saasFeatureResources = saasFeatures.entrySet().stream()
|
||||
.map(e -> SaasFeatureResourceService.SaasFeatureResourceDTO.builder()
|
||||
.terminal(e.getKey())
|
||||
.features(e.getValue())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder()
|
||||
.saasFeatureResources(saasFeatureResources)
|
||||
.build();
|
||||
saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache);
|
||||
}
|
||||
|
||||
private void cacheSaasFeatureResource(String terminal) {
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.terminal(terminal)
|
||||
.build();
|
||||
|
||||
Map<String, List<SaasFeatureResourceService.SaasFeatureResourceCache>> saasFeatureResources = saasFeatureResourceService.list(pageSaasFeatureResourceReq)
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(SaasFeatureResourceResp::getTerminal,
|
||||
Collectors.mapping(e -> SaasFeatureResourceService.SaasFeatureResourceCache
|
||||
.builder()
|
||||
.featureId(e.getId())
|
||||
.notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType()))
|
||||
.parentIds(e.resolvePath())
|
||||
.build(), Collectors.toList())));
|
||||
|
||||
List<SaasFeatureResourceService.SaasFeatureResourceDTO> featureResources = saasFeatureResources.entrySet().stream()
|
||||
.map(e -> SaasFeatureResourceService.SaasFeatureResourceDTO.builder()
|
||||
.terminal(e.getKey())
|
||||
.features(e.getValue())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder()
|
||||
.saasFeatureResources(featureResources)
|
||||
.build();
|
||||
saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache);
|
||||
}
|
||||
}
|
||||
@ -4,12 +4,35 @@ import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@Mapper
|
||||
public interface SaasRoleUserRelationMapper extends BaseMapper<SaasRoleUserRelation> {
|
||||
|
||||
Page<SaasRoleUserRelation> batListCleanRelation(IPage<SaasRoleUserRelation> page, @Param("param") SaasRoleUserRelation cleanParam);
|
||||
|
||||
/**
|
||||
* 现在没有数据可以查询项目的角色
|
||||
* 通过权限点找有权限的人,需要这个接口
|
||||
* @param listRole
|
||||
* @return
|
||||
*/
|
||||
Set<Long> listRoleIds(@Param("param") ListRole listRole);
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class ListRole {
|
||||
private Long ouId;
|
||||
private Long workspaceId;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,14 +6,29 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public interface ProductPermissionCacheService {
|
||||
|
||||
List<PermissionDTO> list(ListProductPermissionParam param);
|
||||
/**
|
||||
* 查询产品的权限信息
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
Map<Long, List<PermissionDTO>> list(ListProductPermissionParam param);
|
||||
|
||||
/**
|
||||
* 存储产品的权限信息
|
||||
* @param param
|
||||
*/
|
||||
void store(StoreProductPermissionParam param);
|
||||
|
||||
|
||||
/**
|
||||
* 产品是否有缓存权限
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
List<Long> hasProductIds(HasProductPermissionParam param);
|
||||
|
||||
@Data
|
||||
@ -47,7 +62,9 @@ public interface ProductPermissionCacheService {
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class ListProductPermissionParam {
|
||||
private List<Long> productIds;
|
||||
private Set<Long> productIds;
|
||||
|
||||
private Set<String> featureCodes;
|
||||
}
|
||||
|
||||
@Data
|
||||
@ -57,12 +74,17 @@ public interface ProductPermissionCacheService {
|
||||
class PermissionDTO {
|
||||
|
||||
/**
|
||||
* 产品关联的字典 Code 原值
|
||||
* 协同关系类型
|
||||
* 原saas_product_module_feature_relation.dictCode
|
||||
*/
|
||||
private String dictCode;
|
||||
private String cooperateType;
|
||||
|
||||
private Long featureId;
|
||||
|
||||
private String featureCode;
|
||||
|
||||
private String terminal;
|
||||
|
||||
private Integer featureType;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
package cn.axzo.tyr.server.service;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public interface ProductSaasFeatureResourceCacheService {
|
||||
|
||||
Map<Long, List<FeatureResourceDTO>> list(ListProductFeatureResourceParam param);
|
||||
|
||||
void store(StoreProductFeatureResourceParam param);
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class StoreProductFeatureResourceParam {
|
||||
private List<ProductFeatureResource> productFeatureResources;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class ProductFeatureResource {
|
||||
private Long productId;
|
||||
|
||||
private List<FeatureResourceDTO> featureResources;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class ListProductFeatureResourceParam {
|
||||
private Set<Long> productIds;
|
||||
|
||||
private Set<String> uniCodes;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class FeatureResourceDTO {
|
||||
|
||||
/**
|
||||
* 协同关系类型
|
||||
* 原saas_product_module_feature_relation.dictCode
|
||||
*/
|
||||
private String cooperateType;
|
||||
|
||||
private Long featureId;
|
||||
|
||||
private String uniCode;
|
||||
|
||||
private String terminal;
|
||||
|
||||
private Integer featureType;
|
||||
}
|
||||
}
|
||||
@ -6,12 +6,13 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public interface RolePermissionCacheService {
|
||||
|
||||
|
||||
List<PermissionDTO> list(ListRolePermissionParam param);
|
||||
Map<Long, List<PermissionDTO>> list(ListRolePermissionParam param);
|
||||
|
||||
/**
|
||||
* redisKey:roleId
|
||||
@ -53,7 +54,9 @@ public interface RolePermissionCacheService {
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class ListRolePermissionParam {
|
||||
private List<Long> roleIds;
|
||||
private Set<Long> roleIds;
|
||||
|
||||
private Set<String> featureCodes;
|
||||
}
|
||||
|
||||
@Data
|
||||
@ -80,5 +83,7 @@ public interface RolePermissionCacheService {
|
||||
* 资源所属端
|
||||
*/
|
||||
private String terminal;
|
||||
|
||||
private Integer featureType;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,67 @@
|
||||
package cn.axzo.tyr.server.service;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public interface RoleSaasFeatureResourceCacheService {
|
||||
|
||||
Map<Long, List<SaasFeatureResourceDTO>> list(ListRoleSaasFeatureResourceParam param);
|
||||
|
||||
void store(StoreRoleSaasFeatureResourceParam param);
|
||||
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class StoreRoleSaasFeatureResourceParam {
|
||||
private List<RoleFeatureResource> roleSaasFeatureResources;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class RoleFeatureResource {
|
||||
private Long roleId;
|
||||
|
||||
private List<SaasFeatureResourceDTO> saasFeatureResources;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class ListRoleSaasFeatureResourceParam {
|
||||
private Set<Long> roleIds;
|
||||
|
||||
private Set<String> uniCodes;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class SaasFeatureResourceDTO {
|
||||
|
||||
private Long featureId;
|
||||
|
||||
/**
|
||||
* 资源所属端
|
||||
*/
|
||||
private String terminal;
|
||||
|
||||
/**
|
||||
* 菜单资源类型1-菜单 2-页面 3-应用入口 4-组件 5-root节点 6-分组
|
||||
*/
|
||||
private Integer featureType;
|
||||
|
||||
private String uniCode;
|
||||
}
|
||||
}
|
||||
@ -183,6 +183,12 @@ public interface RoleService extends IService<SaasRole> {
|
||||
*/
|
||||
@CriteriaField(ignore = true)
|
||||
private String terminal;
|
||||
|
||||
@CriteriaField(field = "workspaceId", operator = Operator.EQ)
|
||||
private Long workspaceId;
|
||||
|
||||
@CriteriaField(field = "ownerOuId", operator = Operator.EQ)
|
||||
private Long ouId;
|
||||
}
|
||||
|
||||
@SuperBuilder
|
||||
|
||||
@ -11,8 +11,13 @@ import cn.axzo.tyr.server.model.ResourcePermission;
|
||||
import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -59,4 +64,48 @@ public interface SaasFeatureResourceService extends IService<SaasFeatureResource
|
||||
|
||||
void deleteFeatureResource(DeleteFeatureResourceReq param);
|
||||
|
||||
void storeCache(StoreSaasFeatureResourceCache param);
|
||||
|
||||
Map<String, List<SaasFeatureResourceCache>> listCache(ListSaasFeatureResourceCache param);
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class StoreSaasFeatureResourceCache {
|
||||
|
||||
private List<SaasFeatureResourceDTO> saasFeatureResources;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class SaasFeatureResourceDTO {
|
||||
private String terminal;
|
||||
|
||||
private List<SaasFeatureResourceCache> features;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class ListSaasFeatureResourceCache {
|
||||
|
||||
private Set<String> terminals;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class SaasFeatureResourceCache {
|
||||
|
||||
private Long featureId;
|
||||
|
||||
private boolean notAuth;
|
||||
|
||||
private Set<Long> parentIds;
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,4 +66,10 @@ public interface TyrSaasAuthService {
|
||||
* @return
|
||||
*/
|
||||
boolean authNewPermission(PermissionCheckReq req);
|
||||
|
||||
/**
|
||||
* 增加统一的开关:权限是否从数据库查询
|
||||
* @return
|
||||
*/
|
||||
boolean permissionFromDB();
|
||||
}
|
||||
|
||||
@ -29,6 +29,46 @@ public interface WorkspaceProductService {
|
||||
*/
|
||||
void storeWorkspaceProduct(StoreWorkspaceProductParam param);
|
||||
|
||||
/**
|
||||
* 从缓存中查询项目的产品及产品的权限
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
List<WorkspaceProductPermission> listWorkspaceProductPermissionCached(ListWorkspaceProductPermissionCacheParam param);
|
||||
|
||||
/**
|
||||
* 从缓存中查询项目的产品及产品的菜单信息
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
List<WorkspaceProductFeatureSource> listWorkspaceProductFeatureResourceCached(ListWorkspaceProductFeatureSourceCacheParam param);
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class ListWorkspaceProductFeatureSourceCacheParam {
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
private Set<Long> workspaceIds;
|
||||
|
||||
private Set<String> uniCodes;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class ListWorkspaceProductPermissionCacheParam {
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
private Set<Long> workspaceIds;
|
||||
|
||||
private Set<String> featureCodes;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@ -74,6 +114,31 @@ public interface WorkspaceProductService {
|
||||
private List<SaasProductModuleFeatureRelation> saasProductModuleFeatureRelations;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class WorkspaceProductPermission {
|
||||
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
private Long workspaceId;
|
||||
|
||||
private List<ProductPermission> productPermissions;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class ProductPermission {
|
||||
|
||||
private Long productId;
|
||||
|
||||
private List<ProductPermissionCacheService.PermissionDTO> permissions;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@ -110,5 +175,30 @@ public interface WorkspaceProductService {
|
||||
*/
|
||||
private Set<Long> workspaceIds;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class WorkspaceProductFeatureSource {
|
||||
|
||||
/**
|
||||
* 项目id
|
||||
*/
|
||||
private Long workspaceId;
|
||||
|
||||
private List<ProductFeatureSource> productFeatureSources;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class ProductFeatureSource {
|
||||
|
||||
private Long productId;
|
||||
|
||||
private List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> featureResources;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,37 +1,29 @@
|
||||
package cn.axzo.tyr.server.service.impl;
|
||||
|
||||
import static cn.axzo.tyr.client.model.enums.FeatureType.BUTTON;
|
||||
import static cn.axzo.tyr.client.model.enums.FeatureType.MODULE;
|
||||
import static cn.axzo.tyr.server.common.constants.PermissionConstant.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import cn.axzo.tyr.client.model.enums.FeatureDataType;
|
||||
import cn.axzo.tyr.client.model.req.QueryPermissionByIdsReq;
|
||||
import cn.axzo.tyr.client.model.res.SimplePermissionPointResp;
|
||||
import cn.hutool.core.date.StopWatch;
|
||||
import cn.hutool.core.lang.Opt;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
|
||||
import cn.axzo.basics.common.BeanMapper;
|
||||
import cn.axzo.basics.common.util.StopWatchUtil;
|
||||
import cn.axzo.basics.common.util.TreeUtil;
|
||||
import cn.axzo.framework.domain.web.code.BaseCode;
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.tyr.client.model.dict.request.BasicDictNodeReq;
|
||||
import cn.axzo.tyr.client.model.dict.request.BasicDictQueryReq;
|
||||
import cn.axzo.tyr.client.model.dict.response.BasicDictNodeResp;
|
||||
import cn.axzo.tyr.client.model.dict.response.BasicDictTreeResp;
|
||||
import cn.axzo.tyr.client.model.enums.DictTypeFiledEnum;
|
||||
import cn.axzo.tyr.client.model.enums.DictWorkSpaceTypeEnum;
|
||||
import cn.axzo.tyr.client.model.enums.FeatureDataType;
|
||||
import cn.axzo.tyr.client.model.enums.FeatureType;
|
||||
import cn.axzo.tyr.client.model.permission.*;
|
||||
import cn.axzo.tyr.client.model.permission.PermissionPointDTO;
|
||||
import cn.axzo.tyr.client.model.permission.PermissionPointListQueryRequest;
|
||||
import cn.axzo.tyr.client.model.permission.PermissionPointMoveRequest;
|
||||
import cn.axzo.tyr.client.model.permission.PermissionPointTreeNode;
|
||||
import cn.axzo.tyr.client.model.permission.PermissionPointTreeQueryReq;
|
||||
import cn.axzo.tyr.client.model.permission.PermissionPointVO;
|
||||
import cn.axzo.tyr.client.model.req.QueryPermissionByIdsReq;
|
||||
import cn.axzo.tyr.client.model.res.SimplePermissionPointResp;
|
||||
import cn.axzo.tyr.server.common.util.Throws;
|
||||
import cn.axzo.tyr.server.config.MqProducer;
|
||||
import cn.axzo.tyr.server.event.payload.SaasFeatureUpsertPayload;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPgroupPermissionRelationDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasProductModuleFeatureRelationDao;
|
||||
@ -40,10 +32,32 @@ import cn.axzo.tyr.server.service.PermissionPointService;
|
||||
import cn.axzo.tyr.server.service.SaasBasicDictService;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static cn.axzo.tyr.server.util.RpcInternalUtil.checkAndGetData;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.tyr.client.model.enums.FeatureType.BUTTON;
|
||||
import static cn.axzo.tyr.client.model.enums.FeatureType.MODULE;
|
||||
import static cn.axzo.tyr.server.common.constants.PermissionConstant.FEATURE_BIZ_NO_PREFIX;
|
||||
import static cn.axzo.tyr.server.common.constants.PermissionConstant.FEATURE_PATH_DELIMITER;
|
||||
import static cn.axzo.tyr.server.common.constants.PermissionConstant.FEATURE_TOP_BIZ_NO;
|
||||
import static cn.axzo.tyr.server.common.constants.PermissionConstant.FEATURE_TOP_PATH;
|
||||
import static cn.axzo.tyr.server.event.inner.EventTypeEnum.SAAS_FEATURE_UPSERT;
|
||||
|
||||
/**
|
||||
* 权限点服务实现
|
||||
@ -61,6 +75,9 @@ public class PermissionPointServiceImpl implements PermissionPointService {
|
||||
private final SaasBasicDictService saasBasicDictService;
|
||||
private final SaasPgroupPermissionRelationDao saasPgroupPermissionRelationDao;
|
||||
private final SaasProductModuleFeatureRelationDao saasProductModuleFeatureRelationDao;
|
||||
private final MqProducer mqProducer;
|
||||
|
||||
private static final String TARGET_TYPE = "saasFeatureId";
|
||||
|
||||
@Override
|
||||
public List<PermissionPointTreeNode> listTreeNodes(PermissionPointTreeQueryReq request) {
|
||||
@ -333,6 +350,11 @@ public class PermissionPointServiceImpl implements PermissionPointService {
|
||||
this.saasFeatureDao.updateById(saasFeature);
|
||||
//返回一些要用的数据
|
||||
dto.setBusinessNo(feature.getBusinessNo());
|
||||
|
||||
sendMsg(SaasFeatureUpsertPayload.builder()
|
||||
.id(dto.getId())
|
||||
.terminal(feature.getTerminal())
|
||||
.build());
|
||||
return dto;
|
||||
}
|
||||
|
||||
@ -367,6 +389,11 @@ public class PermissionPointServiceImpl implements PermissionPointService {
|
||||
dto.setBusinessNo(saasFeature.getBusinessNo());
|
||||
//调整排序 - 兼容处理老数据,数据规范化
|
||||
changeSort(saasFeature, saasFeature.getSort());
|
||||
|
||||
sendMsg(SaasFeatureUpsertPayload.builder()
|
||||
.id(dto.getId())
|
||||
.terminal(saasFeature.getTerminal())
|
||||
.build());
|
||||
return dto;
|
||||
}
|
||||
|
||||
@ -426,6 +453,11 @@ public class PermissionPointServiceImpl implements PermissionPointService {
|
||||
//删除关联数据
|
||||
this.saasPgroupPermissionRelationDao.removeByPermissionPointIds(delIds);
|
||||
this.saasProductModuleFeatureRelationDao.removeByPermissionPointIds(delIds);
|
||||
|
||||
sendMsg(SaasFeatureUpsertPayload.builder()
|
||||
.id(feature.getId())
|
||||
.terminal(feature.getTerminal())
|
||||
.build());
|
||||
return bizNoList;
|
||||
}
|
||||
|
||||
@ -602,7 +634,8 @@ public class PermissionPointServiceImpl implements PermissionPointService {
|
||||
SaasFeature::getFeatureName,
|
||||
SaasFeature::getParentId,
|
||||
SaasFeature::getPath,
|
||||
SaasFeature::getTerminal));
|
||||
SaasFeature::getTerminal,
|
||||
SaasFeature::getFeatureType));
|
||||
|
||||
Set<Long> parentIds = new HashSet<>();
|
||||
for (SaasFeature permission : allPermissions) {
|
||||
@ -640,7 +673,16 @@ public class PermissionPointServiceImpl implements PermissionPointService {
|
||||
.name(permission.getFeatureName())
|
||||
.parentId(permission.getParentId())
|
||||
.terminal(permission.getTerminal())
|
||||
.featureType(permission.getFeatureType())
|
||||
.build();
|
||||
}
|
||||
|
||||
private void sendMsg(SaasFeatureUpsertPayload saasFeatureUpsertPayload) {
|
||||
Event event = Event.builder()
|
||||
.targetType(TARGET_TYPE)
|
||||
.eventCode(SAAS_FEATURE_UPSERT.getEventCode())
|
||||
.data(saasFeatureUpsertPayload)
|
||||
.build();
|
||||
mqProducer.send(event);
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,12 +46,13 @@ import cn.axzo.tyr.server.model.UserIdentity;
|
||||
import cn.axzo.tyr.server.model.WorkspaceFeatureRelation;
|
||||
import cn.axzo.tyr.server.repository.dao.ProductModuleDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPageElementFeatureResourceRelationDao;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation;
|
||||
import cn.axzo.tyr.server.service.PermissionQueryService;
|
||||
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
|
||||
import cn.axzo.tyr.server.service.ProductSaasFeatureResourceCacheService;
|
||||
import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService;
|
||||
import cn.axzo.tyr.server.service.RoleService;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import cn.axzo.tyr.server.service.SaasRoleUserRelationService;
|
||||
@ -92,7 +93,6 @@ import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.tyr.server.repository.entity.SaasFeatureResource.DISPLAY_STATUS;
|
||||
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE;
|
||||
|
||||
/**
|
||||
* 权限查询服务实现
|
||||
*
|
||||
@ -117,7 +117,10 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
|
||||
private final SaasFeatureResourceService saasFeatureResourceService;
|
||||
private final SaasRoleUserRelationService saasRoleUserRelationService;
|
||||
private final WorkspaceProductService workspaceProductService;
|
||||
private final SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao;
|
||||
private final RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService;
|
||||
private final ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService;
|
||||
private final TyrSaasAuthService tyrSaasAuthService;
|
||||
|
||||
|
||||
@Qualifier("authExecutor")
|
||||
@Autowired
|
||||
@ -322,15 +325,131 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
|
||||
|
||||
}
|
||||
|
||||
private List<Long> resolveFeatureIds(TreePermissionReq treePermissionReq) {
|
||||
if (StringUtils.isBlank(treePermissionReq.getUniCode())) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.uniCodes(Sets.newHashSet(treePermissionReq.getUniCode()))
|
||||
.build();
|
||||
return featureResourceService.list(pageSaasFeatureResourceReq).stream()
|
||||
.map(SaasFeatureResourceResp::getId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<SaasRoleUserV2DTO> listUserPermission(TreePermissionReq treePermissionReq, List<Long> featureIds) {
|
||||
List<ListRoleUserRelationParam.WorkspaceOuPair> workspaceOuPairs = treePermissionReq.getWorkspaceOUPairs().stream()
|
||||
.map(e -> ListRoleUserRelationParam.WorkspaceOuPair.builder()
|
||||
.workspaceId(e.getWorkspaceId())
|
||||
.ouId(e.getOuId())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ListRoleUserRelationParam listRoleUserRelationParam = ListRoleUserRelationParam.builder()
|
||||
.personId(treePermissionReq.getPersonId())
|
||||
.workspaceOuPairs(Lists.newArrayList(workspaceOuPairs))
|
||||
.needRole(true)
|
||||
.needPermissionRelation(true)
|
||||
.featureResourceTypes(treePermissionReq.getFeatureResourceTypes())
|
||||
.type(NEW_FEATURE)
|
||||
.terminal(treePermissionReq.getTerminal())
|
||||
.featureIds(featureIds)
|
||||
.build();
|
||||
return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream()
|
||||
.filter(e -> e.getSaasRole() != null)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Set<Long> listUserPermissionFeatureIdsFromDB(TreePermissionReq treePermissionReq) {
|
||||
|
||||
List<Long> featureIds = resolveFeatureIds(treePermissionReq);
|
||||
|
||||
if (StringUtils.isNotBlank(treePermissionReq.getUniCode()) && CollectionUtils.isEmpty(featureIds)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
List<SaasRoleUserV2DTO> saasRoleUserV2DTOS = listUserPermission(treePermissionReq, featureIds);
|
||||
|
||||
// 用户可能没有角色
|
||||
if (CollectionUtils.isEmpty(saasRoleUserV2DTOS)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
List<WorkspaceProductService.WorkspaceProduct> workspaceProducts = listWorkspaceProducts(treePermissionReq, featureIds);
|
||||
|
||||
//免授权
|
||||
List<Long> authFreeFeatureIds = listNotAuthFeatures(treePermissionReq);
|
||||
|
||||
//取交集确定权限
|
||||
return mixFeatureIds(saasRoleUserV2DTOS, workspaceProducts, authFreeFeatureIds);
|
||||
}
|
||||
|
||||
private Set<Long> mixFeatureIds(List<SaasRoleUserV2DTO> saasRoleUsers,
|
||||
List<WorkspaceProductService.WorkspaceProduct> workspaceProducts,
|
||||
List<Long> authFreeFeatureIds) {
|
||||
|
||||
Map<Long, WorkspaceProductService.WorkspaceProduct> workspaceProductMap = workspaceProducts.stream()
|
||||
.collect(Collectors.toMap(WorkspaceProductService.WorkspaceProduct::getWorkspaceId, Function.identity()));
|
||||
|
||||
return saasRoleUsers.stream()
|
||||
.filter(roleUser -> {
|
||||
WorkspaceProductService.WorkspaceProduct workspaceProduct = workspaceProductMap.get(roleUser.getSaasRoleUser().getWorkspaceId());
|
||||
if (workspaceProduct == null || CollectionUtils.isEmpty(workspaceProduct.getSaasProductModuleFeatureRelations())) {
|
||||
log.warn("no workspace product feature found for id:{}", roleUser.getSaasRoleUser().getWorkspaceId());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(roleUser -> {
|
||||
WorkspaceProductService.WorkspaceProduct workspaceProduct = workspaceProductMap.get(roleUser.getSaasRoleUser().getWorkspaceId());
|
||||
|
||||
SaasRoleUserV2DTO.SaasRole saasRole = roleUser.getSaasRole();
|
||||
if (RoleTypeEnum.isAdmin(saasRole.getRoleType())) {
|
||||
return resolveAdminRole(workspaceProduct, saasRole);
|
||||
}
|
||||
return resolveNormalRole(workspaceProduct, saasRole, authFreeFeatureIds);
|
||||
})
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private List<WorkspaceProductService.WorkspaceProduct> listWorkspaceProducts(TreePermissionReq treePermissionReq,
|
||||
List<Long> featureIds) {
|
||||
//查询租户产品权限点
|
||||
Set<Long> workspaceIds = treePermissionReq.getWorkspaceOUPairs().stream()
|
||||
.map(WorkspaceOUPair::getWorkspaceId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder()
|
||||
.terminal(treePermissionReq.getTerminal())
|
||||
.workspaceIds(workspaceIds)
|
||||
.featureResourceTypes(treePermissionReq.getFeatureResourceTypes())
|
||||
.type(NEW_FEATURE)
|
||||
.build();
|
||||
|
||||
if (CollectionUtils.isNotEmpty(featureIds)) {
|
||||
workspaceProductParam.setFeatureIdPairs(Lists.newArrayList(FeatureIdPair.builder()
|
||||
.featureIds(Sets.newHashSet(featureIds))
|
||||
.type(NEW_FEATURE)
|
||||
.build()));
|
||||
}
|
||||
return workspaceProductService.listWorkspaceProduct(workspaceProductParam);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public List<TreePermissionResp> treePermission(TreePermissionReq req) {
|
||||
|
||||
Set<Long> allFeatureIds = Sets.newHashSet();
|
||||
Set<Long> featureIds = listUserPermissionFeatureIds(req);
|
||||
Set<Long> featureIds = resovlePermission(req);
|
||||
|
||||
Set<Long> defaultFeatureIds = listNotAuthFeatureIds();
|
||||
allFeatureIds.addAll(featureIds);
|
||||
allFeatureIds.addAll(defaultFeatureIds);
|
||||
|
||||
|
||||
if (CollectionUtils.isEmpty(allFeatureIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@ -384,6 +503,20 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Set<Long> resovlePermission(TreePermissionReq req) {
|
||||
|
||||
if (tyrSaasAuthService.permissionFromDB()) {
|
||||
return listUserPermissionFeatureIdsFromDB(req);
|
||||
}
|
||||
|
||||
try {
|
||||
return listUserPermissionFeatureIds(req);
|
||||
} catch (Exception ex) {
|
||||
log.error("查询权限异常,执行降级处理");
|
||||
return listUserPermissionFeatureIdsFromDB(req);
|
||||
}
|
||||
}
|
||||
|
||||
private List<SaasFeatureResourceResp> filterFeature(List<SaasFeatureResourceResp> saasFeatureResources) {
|
||||
if (CollectionUtils.isEmpty(saasFeatureResources)) {
|
||||
return Collections.emptyList();
|
||||
@ -653,26 +786,15 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
|
||||
|
||||
private Set<Long> listUserPermissionFeatureIds(TreePermissionReq treePermissionReq) {
|
||||
|
||||
List<Long> featureIds = resolveFeatureIds(treePermissionReq);
|
||||
List<SaasRoleUserV2DTO> saasRoleUserV2DTOS = listUserPermission(treePermissionReq);
|
||||
|
||||
if (StringUtils.isNotBlank(treePermissionReq.getUniCode()) && CollectionUtils.isEmpty(featureIds)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
List<SaasRoleUserV2DTO> saasRoleUserV2DTOS = listUserPermission(treePermissionReq, featureIds);
|
||||
|
||||
// 用户可能没有角色
|
||||
if (CollectionUtils.isEmpty(saasRoleUserV2DTOS)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
List<WorkspaceProductService.WorkspaceProduct> workspaceProducts = listWorkspaceProducts(treePermissionReq, featureIds);
|
||||
List<WorkspaceProductService.WorkspaceProductFeatureSource> workspaceProductFeatureSources = listWorkspaceProducts(treePermissionReq);
|
||||
|
||||
//免授权
|
||||
List<Long> authFreeFeatureIds = listNotAuthFeatures(treePermissionReq);
|
||||
|
||||
//取交集确定权限
|
||||
return mixFeatureIds(saasRoleUserV2DTOS, workspaceProducts, authFreeFeatureIds);
|
||||
return mixFeatureIds(saasRoleUserV2DTOS, workspaceProductFeatureSources, authFreeFeatureIds, treePermissionReq);
|
||||
}
|
||||
|
||||
private List<Long> listNotAuthFeatures(TreePermissionReq treePermissionReq) {
|
||||
@ -685,30 +807,24 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<WorkspaceProductService.WorkspaceProduct> listWorkspaceProducts(TreePermissionReq treePermissionReq,
|
||||
List<Long> featureIds) {
|
||||
private List<WorkspaceProductService.WorkspaceProductFeatureSource> listWorkspaceProducts(TreePermissionReq treePermissionReq) {
|
||||
//查询租户产品权限点
|
||||
Set<Long> workspaceIds = treePermissionReq.getWorkspaceOUPairs().stream()
|
||||
.map(WorkspaceOUPair::getWorkspaceId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
WorkspaceProductService.WorkspaceProductParam workspaceProductParam = WorkspaceProductService.WorkspaceProductParam.builder()
|
||||
.terminal(treePermissionReq.getTerminal())
|
||||
WorkspaceProductService.ListWorkspaceProductFeatureSourceCacheParam listWorkspaceProductFeatureSourceCacheParam = WorkspaceProductService.ListWorkspaceProductFeatureSourceCacheParam
|
||||
.builder()
|
||||
.workspaceIds(workspaceIds)
|
||||
.featureResourceTypes(treePermissionReq.getFeatureResourceTypes())
|
||||
.type(NEW_FEATURE)
|
||||
.uniCodes(Optional.ofNullable(treePermissionReq.getUniCode())
|
||||
.map(Sets::newHashSet)
|
||||
.orElseGet(Sets::newHashSet))
|
||||
.build();
|
||||
|
||||
if (CollectionUtils.isNotEmpty(featureIds)) {
|
||||
workspaceProductParam.setFeatureIdPairs(Lists.newArrayList(FeatureIdPair.builder()
|
||||
.featureIds(Sets.newHashSet(featureIds))
|
||||
.type(NEW_FEATURE)
|
||||
.build()));
|
||||
}
|
||||
return workspaceProductService.listWorkspaceProduct(workspaceProductParam);
|
||||
return workspaceProductService.listWorkspaceProductFeatureResourceCached(listWorkspaceProductFeatureSourceCacheParam);
|
||||
}
|
||||
|
||||
private List<SaasRoleUserV2DTO> listUserPermission(TreePermissionReq treePermissionReq, List<Long> featureIds) {
|
||||
private List<SaasRoleUserV2DTO> listUserPermission(TreePermissionReq treePermissionReq) {
|
||||
List<ListRoleUserRelationParam.WorkspaceOuPair> workspaceOuPairs = treePermissionReq.getWorkspaceOUPairs().stream()
|
||||
.map(e -> ListRoleUserRelationParam.WorkspaceOuPair.builder()
|
||||
.workspaceId(e.getWorkspaceId())
|
||||
@ -720,59 +836,133 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
|
||||
.personId(treePermissionReq.getPersonId())
|
||||
.workspaceOuPairs(Lists.newArrayList(workspaceOuPairs))
|
||||
.needRole(true)
|
||||
.needPermissionRelation(true)
|
||||
.featureResourceTypes(treePermissionReq.getFeatureResourceTypes())
|
||||
.type(NEW_FEATURE)
|
||||
.terminal(treePermissionReq.getTerminal())
|
||||
.featureIds(featureIds)
|
||||
.build();
|
||||
return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream()
|
||||
.filter(e -> e.getSaasRole() != null)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<Long> resolveFeatureIds(TreePermissionReq treePermissionReq) {
|
||||
if (StringUtils.isBlank(treePermissionReq.getUniCode())) {
|
||||
return Collections.emptyList();
|
||||
private Map<Long, List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO>> listRoleFeatureResource(List<SaasRoleUserV2DTO> saasRoleUsers,
|
||||
TreePermissionReq treePermissionReq) {
|
||||
|
||||
Set<Long> roleIds = saasRoleUsers.stream()
|
||||
.map(SaasRoleUserV2DTO::getRoleId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (CollectionUtils.isEmpty(roleIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.uniCodes(Sets.newHashSet(treePermissionReq.getUniCode()))
|
||||
RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam listRoleSaasFeatureResourceParam = RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam.builder()
|
||||
.roleIds(roleIds)
|
||||
.uniCodes(Optional.ofNullable(treePermissionReq.getUniCode())
|
||||
.map(Sets::newHashSet)
|
||||
.orElseGet(Sets::newHashSet))
|
||||
.build();
|
||||
return featureResourceService.list(pageSaasFeatureResourceReq).stream()
|
||||
.map(SaasFeatureResourceResp::getId)
|
||||
.collect(Collectors.toList());
|
||||
return roleSaasFeatureResourceCacheService.list(listRoleSaasFeatureResourceParam);
|
||||
}
|
||||
|
||||
private Set<Long> mixFeatureIds(List<SaasRoleUserV2DTO> saasRoleUsers,
|
||||
List<WorkspaceProductService.WorkspaceProduct> workspaceProducts,
|
||||
List<Long> authFreeFeatureIds) {
|
||||
List<WorkspaceProductService.WorkspaceProductFeatureSource> workspaceProducts,
|
||||
List<Long> authFreeFeatureIds,
|
||||
TreePermissionReq treePermissionReq) {
|
||||
|
||||
Map<Long, WorkspaceProductService.WorkspaceProduct> workspaceProductMap = workspaceProducts.stream()
|
||||
.collect(Collectors.toMap(WorkspaceProductService.WorkspaceProduct::getWorkspaceId, Function.identity()));
|
||||
Map<Long, List<WorkspaceProductService.ProductFeatureSource>> workspaceProductMap = workspaceProducts.stream()
|
||||
.collect(Collectors.toMap(WorkspaceProductService.WorkspaceProductFeatureSource::getWorkspaceId, WorkspaceProductService.WorkspaceProductFeatureSource::getProductFeatureSources));
|
||||
|
||||
Map<Long, List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO>> roleFeatureResourceMap = listRoleFeatureResource(saasRoleUsers, treePermissionReq);
|
||||
|
||||
Set<Integer> featureTypes = Optional.ofNullable(treePermissionReq.getFeatureResourceTypes())
|
||||
.map(e -> e.stream().map(FeatureResourceType::getCode).collect(Collectors.toSet()))
|
||||
.orElseGet(Sets::newHashSet);
|
||||
|
||||
return saasRoleUsers.stream()
|
||||
.filter(roleUser -> {
|
||||
WorkspaceProductService.WorkspaceProduct workspaceProduct = workspaceProductMap.get(roleUser.getSaasRoleUser().getWorkspaceId());
|
||||
if (workspaceProduct == null || CollectionUtils.isEmpty(workspaceProduct.getSaasProductModuleFeatureRelations())) {
|
||||
log.warn("no workspace product feature found for id:{}", roleUser.getSaasRoleUser().getWorkspaceId());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(roleUser -> {
|
||||
WorkspaceProductService.WorkspaceProduct workspaceProduct = workspaceProductMap.get(roleUser.getSaasRoleUser().getWorkspaceId());
|
||||
List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> productFeatureSources = workspaceProductMap.get(roleUser.getSaasRoleUser().getWorkspaceId())
|
||||
.stream()
|
||||
.map(WorkspaceProductService.ProductFeatureSource::getFeatureResources)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(e -> StringUtils.isBlank(treePermissionReq.getTerminal())
|
||||
|| Objects.equals(e.getTerminal(), treePermissionReq.getTerminal()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(productFeatureSources)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SaasRoleUserV2DTO.SaasRole saasRole = roleUser.getSaasRole();
|
||||
if (RoleTypeEnum.isAdmin(saasRole.getRoleType())) {
|
||||
return resolveAdminRole(workspaceProduct, saasRole);
|
||||
}
|
||||
return resolveNormalRole(workspaceProduct, saasRole, authFreeFeatureIds);
|
||||
|
||||
Set<Long> adminFeatureIds = resolveAdminRole(productFeatureSources, saasRole);
|
||||
Set<Long> notAuthFeatureIds = resolveNotAuthFeatureIds(productFeatureSources, authFreeFeatureIds);
|
||||
|
||||
List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO> roleFeatureResources = roleFeatureResourceMap.get(saasRole.getId()).stream()
|
||||
.filter(e -> StringUtils.isBlank(treePermissionReq.getTerminal())
|
||||
|| Objects.equals(e.getTerminal(), treePermissionReq.getTerminal()))
|
||||
.filter(e -> CollectionUtils.isEmpty(featureTypes) || featureTypes.contains(e.getFeatureType()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Set<Long> normalFeatureIds = resolveNormalRole(productFeatureSources, saasRole, roleFeatureResources);
|
||||
|
||||
Set<Long> allFeatureIds = Sets.newHashSet();
|
||||
allFeatureIds.addAll(adminFeatureIds);
|
||||
allFeatureIds.addAll(notAuthFeatureIds);
|
||||
allFeatureIds.addAll(normalFeatureIds);
|
||||
|
||||
return allFeatureIds;
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private Set<Long> resolveAdminRole(List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> productFeatureSources,
|
||||
SaasRoleUserV2DTO.SaasRole saasRole) {
|
||||
|
||||
if (!RoleTypeEnum.isAdmin(saasRole.getRoleType())) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
//超管和管理员 直接取和角色类型匹配的租户产品权限
|
||||
return productFeatureSources.stream()
|
||||
.filter(e -> Objects.equals(e.getCooperateType(), saasRole.getProductUnitType().toString())
|
||||
|| !NumberUtil.isPositiveNumber(saasRole.getProductUnitType()))
|
||||
.map(ProductSaasFeatureResourceCacheService.FeatureResourceDTO::getFeatureId)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private Set<Long> resolveNormalRole(List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> workspaceProduct,
|
||||
SaasRoleUserV2DTO.SaasRole saasRole,
|
||||
List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO> roleFeatureResources) {
|
||||
|
||||
if (CollectionUtils.isEmpty(roleFeatureResources)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Set<Long> roleFeatureIds = roleFeatureResources.stream()
|
||||
.map(RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO::getFeatureId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
return workspaceProduct.stream()
|
||||
.filter(e -> Objects.equals(e.getCooperateType(), saasRole.getProductUnitType().toString())
|
||||
|| !NumberUtil.isPositiveNumber(saasRole.getProductUnitType()))
|
||||
.map(ProductSaasFeatureResourceCacheService.FeatureResourceDTO::getFeatureId)
|
||||
.filter(roleFeatureIds::contains)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private Set<Long> resolveNotAuthFeatureIds(List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> workspaceProduct,
|
||||
List<Long> authFreeFeatureIds) {
|
||||
|
||||
if (CollectionUtils.isEmpty(authFreeFeatureIds)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
return workspaceProduct.stream()
|
||||
.map(ProductSaasFeatureResourceCacheService.FeatureResourceDTO::getFeatureId)
|
||||
.filter(authFreeFeatureIds::contains)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private List<Long> resolveAdminRole(WorkspaceProductService.WorkspaceProduct workspaceProduct,
|
||||
SaasRoleUserV2DTO.SaasRole saasRole) {
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import cn.axzo.foundation.dao.support.converter.PageConverter;
|
||||
import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper;
|
||||
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.thrones.client.saas.ServicePkgClient;
|
||||
import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct;
|
||||
@ -15,6 +16,8 @@ import cn.axzo.tyr.client.model.product.ProductFeatureRelationUpdateReq;
|
||||
import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO;
|
||||
import cn.axzo.tyr.client.model.req.FeatureIdPair;
|
||||
import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq;
|
||||
import cn.axzo.tyr.server.config.MqProducer;
|
||||
import cn.axzo.tyr.server.event.payload.ProductPermissionCreatedPayload;
|
||||
import cn.axzo.tyr.server.repository.dao.ProductModuleDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
|
||||
@ -50,6 +53,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.tyr.server.event.inner.EventTypeEnum.PRODUCT_PERMISSION_CREATED;
|
||||
import static cn.axzo.tyr.server.util.RpcInternalUtil.checkAndGetData;
|
||||
|
||||
/**
|
||||
@ -68,6 +72,9 @@ public class ProductFeatureRelationServiceImpl extends ServiceImpl<SaasProductMo
|
||||
private final SaasFeatureDao saasFeatureDao;
|
||||
private final ProductModuleDao productModuleDao;
|
||||
private final SaasFeatureResourceDao saasFeatureResourceDao;
|
||||
private final MqProducer mqProducer;
|
||||
|
||||
private static final String TARGET_TYPE = "productModuleId";
|
||||
|
||||
@Override
|
||||
public ApiResult<List<ProductFeatureRelationVO>> featureList(ProductFeatureRelationSearchReq req) {
|
||||
@ -99,6 +106,8 @@ public class ProductFeatureRelationServiceImpl extends ServiceImpl<SaasProductMo
|
||||
saveList.add(relation);
|
||||
}));
|
||||
saasProductModuleFeatureRelationDao.saveBatch(saveList);
|
||||
|
||||
sendProductPermissionCreatedMsg(req);
|
||||
return ApiResult.ok(true);
|
||||
}
|
||||
|
||||
@ -115,6 +124,8 @@ public class ProductFeatureRelationServiceImpl extends ServiceImpl<SaasProductMo
|
||||
.filter(CollectionUtil::isNotEmpty).flatMap(List::stream).collect(Collectors.toSet());
|
||||
if (CollectionUtil.isEmpty(allFeatureResourceIds)) {
|
||||
log.warn("product has no featureResourceIds to bind.");
|
||||
// 产品的权限点可能会被清空,也需要发送mq
|
||||
sendProductPermissionCreatedMsg(req);
|
||||
return;
|
||||
}
|
||||
Map<Long, SaasFeatureResource> resourceMap = saasFeatureResourceDao.lambdaQuery()
|
||||
@ -137,6 +148,27 @@ public class ProductFeatureRelationServiceImpl extends ServiceImpl<SaasProductMo
|
||||
saveList.add(relation);
|
||||
}));
|
||||
saasProductModuleFeatureRelationDao.saveBatch(saveList);
|
||||
|
||||
sendProductPermissionCreatedMsg(req);
|
||||
}
|
||||
|
||||
private void sendProductPermissionCreatedMsg(List<ProductFeatureRelationUpdateReq> req) {
|
||||
|
||||
if (CollectionUtils.isEmpty(req)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<Long> productModuleIds = req.stream()
|
||||
.map(ProductFeatureRelationUpdateReq::getProductModuleId)
|
||||
.collect(Collectors.toSet());
|
||||
Event event = Event.builder()
|
||||
.targetType(TARGET_TYPE)
|
||||
.eventCode(PRODUCT_PERMISSION_CREATED.getEventCode())
|
||||
.data(ProductPermissionCreatedPayload.builder()
|
||||
.productModuleIds(productModuleIds)
|
||||
.build())
|
||||
.build();
|
||||
mqProducer.send(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -326,7 +358,7 @@ public class ProductFeatureRelationServiceImpl extends ServiceImpl<SaasProductMo
|
||||
public List<SaasProductModuleFeatureRelation> list(PageProductFeatureRelationReq param) {
|
||||
return PageConverter.drainAll(pageNumber -> {
|
||||
param.setPage(pageNumber);
|
||||
param.setPageSize(500);
|
||||
param.setPageSize(1000);
|
||||
return page(param);
|
||||
});
|
||||
}
|
||||
|
||||
@ -2,25 +2,36 @@ package cn.axzo.tyr.server.service.impl;
|
||||
|
||||
import cn.axzo.foundation.exception.Axssert;
|
||||
import cn.axzo.pokonyan.config.redis.RedisClient;
|
||||
import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq;
|
||||
import cn.axzo.tyr.server.event.inner.CacheProductPermissionHandler;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation;
|
||||
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
|
||||
import cn.axzo.tyr.server.service.ProductPermissionCacheService;
|
||||
import cn.hutool.core.lang.Pair;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
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.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
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.RedisTemplate;
|
||||
import org.springframework.data.redis.core.SessionCallback;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
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;
|
||||
|
||||
@ -33,24 +44,75 @@ public class ProductPermissionCacheServiceImpl implements ProductPermissionCache
|
||||
private static final String PRODUCT_PERMISSION_KEY = "product:permission:%s";
|
||||
|
||||
@Autowired
|
||||
protected StringRedisTemplate redisTemplate;
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
@Autowired
|
||||
private ProductFeatureRelationService productFeatureRelationService;
|
||||
@Autowired
|
||||
private CacheProductPermissionHandler cacheProductPermissionHandler;
|
||||
|
||||
/** 产品权限缓存过期时间 **/
|
||||
@Value("${product.permission.expire:180}")
|
||||
private Long expireInDays;
|
||||
|
||||
@Override
|
||||
public List<PermissionDTO> list(ListProductPermissionParam param) {
|
||||
public Map<Long, List<PermissionDTO>> list(ListProductPermissionParam param) {
|
||||
|
||||
if (CollectionUtils.isEmpty(param.getProductIds())) {
|
||||
return Collections.emptyList();
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<Long, List<PermissionDTO>> permissionCached = listProductPermissionCached(param);
|
||||
|
||||
Set<String> redisKeys = param.getProductIds().stream()
|
||||
.map(this::getKey)
|
||||
.collect(Collectors.toSet());
|
||||
fillCacheProductPermissions(param, permissionCached);
|
||||
|
||||
Set<String> redisValues = redisTemplate.opsForSet().union(redisKeys);
|
||||
return permissionCached;
|
||||
}
|
||||
|
||||
return redisValues.stream()
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.map(value -> JSONObject.parseObject(value, PermissionDTO.class))
|
||||
.collect(Collectors.toList());
|
||||
private Map<Long, List<PermissionDTO>> listProductPermissionCached(ListProductPermissionParam param) {
|
||||
|
||||
List<Object> redisValues = redisTemplate.executePipelined(new SessionCallback<Object>() {
|
||||
@Override
|
||||
public Object execute(RedisOperations operations) throws DataAccessException {
|
||||
|
||||
for (Long productId : param.getProductIds()) {
|
||||
String redisKey = getKey(productId);
|
||||
|
||||
if (CollectionUtils.isEmpty(param.getFeatureCodes())) {
|
||||
RedisClient.HashOps.hGetAll(redisKey);
|
||||
} else {
|
||||
RedisClient.HashOps.hMultiGet(redisKey, Lists.newArrayList(param.getFeatureCodes()));
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
return Streams.zip(param.getProductIds().stream(),
|
||||
redisValues.stream(),
|
||||
(productId, redisValue) -> {
|
||||
|
||||
if (Objects.isNull(redisValue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(param.getFeatureCodes())) {
|
||||
List<PermissionDTO> permissions = (List<PermissionDTO>) ((Map) redisValue).values().stream()
|
||||
.flatMap(e -> JSONArray.parseArray(JSONArray.toJSONString(e), PermissionDTO.class).stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return Pair.of(productId, permissions);
|
||||
}
|
||||
|
||||
List<PermissionDTO> permissions = (List<PermissionDTO>) ((List) redisValue).stream()
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(e -> JSONArray.parseArray((String) e, PermissionDTO.class).stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return Pair.of(productId, permissions);
|
||||
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(Pair::getKey, Pair::getValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -65,12 +127,16 @@ public class ProductPermissionCacheServiceImpl implements ProductPermissionCache
|
||||
for (ProductPermission productPermission : param.getProductPermissions()) {
|
||||
String redisKey = getKey(productPermission.getProductId());
|
||||
|
||||
String[] redisValues = productPermission.getPermissions().stream()
|
||||
.map(JSONObject::toJSONString)
|
||||
.toArray(String[]::new);
|
||||
Map<String, String> redisValues = productPermission.getPermissions().stream()
|
||||
.collect(Collectors.groupingBy(PermissionDTO::getFeatureCode))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue())));
|
||||
|
||||
RedisClient.SetOps.sAdd(redisKey, redisValues);
|
||||
redisTemplate.expire(redisKey, 4, TimeUnit.DAYS);
|
||||
// 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁
|
||||
redisTemplate.delete(redisKey);
|
||||
RedisClient.HashOps.hPutAll(redisKey, redisValues);
|
||||
redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS);
|
||||
log.info("succeed to store product permission: redisKey:{} value:{}", redisKey, redisValues);
|
||||
}
|
||||
return null;
|
||||
@ -100,7 +166,61 @@ public class ProductPermissionCacheServiceImpl implements ProductPermissionCache
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装在缓存中没有查询到权限的产品
|
||||
* @param param
|
||||
* @param permissionCached
|
||||
*/
|
||||
private void fillCacheProductPermissions(ListProductPermissionParam param,
|
||||
Map<Long, List<PermissionDTO>> permissionCached) {
|
||||
|
||||
Sets.SetView<Long> difference = Sets.difference(param.getProductIds(), permissionCached.keySet());
|
||||
if (difference.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder()
|
||||
.productModuleIds(difference)
|
||||
.build();
|
||||
List<SaasProductModuleFeatureRelation> productPermissions = productFeatureRelationService.list(pageProductFeatureRelationReq);
|
||||
|
||||
List<ProductPermission> productPermissionsCache = cacheProductPermissionHandler.resolveProductPermissions(productPermissions);
|
||||
if (CollectionUtils.isEmpty(productPermissionsCache)) return;
|
||||
|
||||
StoreProductPermissionParam storeWorkspaceProductParam = StoreProductPermissionParam.builder()
|
||||
.productPermissions(productPermissionsCache)
|
||||
.build();
|
||||
store(storeWorkspaceProductParam);
|
||||
|
||||
Map<Long, List<PermissionDTO>> productPermissionMap = productPermissionsCache.stream()
|
||||
.collect(Collectors.toMap(ProductPermission::getProductId, ProductPermission::getPermissions));
|
||||
permissionCached.putAll(productPermissionMap);
|
||||
}
|
||||
|
||||
private String getKey(Object... params) {
|
||||
return String.format(PRODUCT_PERMISSION_KEY, params);
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
static class PermissionWrapper {
|
||||
|
||||
/**
|
||||
* 协同关系类型
|
||||
* 原saas_product_module_feature_relation.dictCode
|
||||
*/
|
||||
private String cooperateType;
|
||||
|
||||
private Long featureId;
|
||||
|
||||
private String featureCode;
|
||||
|
||||
private String terminal;
|
||||
|
||||
private Integer featureType;
|
||||
|
||||
private Long productId;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,176 @@
|
||||
package cn.axzo.tyr.server.service.impl;
|
||||
|
||||
import cn.axzo.foundation.exception.Axssert;
|
||||
import cn.axzo.pokonyan.config.redis.RedisClient;
|
||||
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
|
||||
import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq;
|
||||
import cn.axzo.tyr.server.event.inner.CacheProductSaasFeatureResourceHandler;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation;
|
||||
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
|
||||
import cn.axzo.tyr.server.service.ProductSaasFeatureResourceCacheService;
|
||||
import cn.hutool.core.lang.Pair;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
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.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.RedisTemplate;
|
||||
import org.springframework.data.redis.core.SessionCallback;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
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.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ProductSaasFeatureResourceCacheServiceImpl implements ProductSaasFeatureResourceCacheService {
|
||||
|
||||
private static final String PRODUCT_SAAS_FEATURE_RESOURCE_KEY = "product:feature:resource:%s";
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
@Autowired
|
||||
private ProductFeatureRelationService productFeatureRelationService;
|
||||
@Autowired
|
||||
private CacheProductSaasFeatureResourceHandler cacheProductSaasFeatureResourceHandler;
|
||||
|
||||
@Value("${product.feature.resouce.expire:180}")
|
||||
private Long expireInDays;
|
||||
|
||||
@Override
|
||||
public Map<Long, List<FeatureResourceDTO>> list(ListProductFeatureResourceParam param) {
|
||||
if (CollectionUtils.isEmpty(param.getProductIds())) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<Long, List<FeatureResourceDTO>> featureResourceCached = listProductFeatureResourceCached(param);
|
||||
|
||||
fillCacheProductFeatureResource(param, featureResourceCached);
|
||||
|
||||
return featureResourceCached;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(StoreProductFeatureResourceParam param) {
|
||||
Axssert.check(param.getProductFeatureResources().stream().allMatch(e -> Objects.nonNull(e.getProductId())), REDIS_PRODUCT_NOT_NULL);
|
||||
|
||||
redisTemplate.executePipelined(new SessionCallback<Object>() {
|
||||
@Override
|
||||
public Object execute(RedisOperations operations) throws DataAccessException {
|
||||
|
||||
for (ProductFeatureResource productFeatureResource : param.getProductFeatureResources()) {
|
||||
String redisKey = getKey(productFeatureResource.getProductId());
|
||||
|
||||
Map<String, String> redisValues = productFeatureResource.getFeatureResources().stream()
|
||||
.collect(Collectors.groupingBy(FeatureResourceDTO::getUniCode))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue())));
|
||||
|
||||
// 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁
|
||||
redisTemplate.delete(redisKey);
|
||||
RedisClient.HashOps.hPutAll(redisKey, redisValues);
|
||||
redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS);
|
||||
log.info("succeed to store product featureResource: redisKey:{} value:{}", redisKey, redisValues);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Map<Long, List<FeatureResourceDTO>> listProductFeatureResourceCached(ListProductFeatureResourceParam param) {
|
||||
|
||||
List<Object> redisValues = redisTemplate.executePipelined(new SessionCallback<Object>() {
|
||||
@Override
|
||||
public Object execute(RedisOperations operations) throws DataAccessException {
|
||||
|
||||
for (Long productId : param.getProductIds()) {
|
||||
String redisKey = getKey(productId);
|
||||
|
||||
if (CollectionUtils.isEmpty(param.getUniCodes())) {
|
||||
RedisClient.HashOps.hGetAll(redisKey);
|
||||
} else {
|
||||
RedisClient.HashOps.hMultiGet(redisKey, Lists.newArrayList(param.getUniCodes()));
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
return Streams.zip(param.getProductIds().stream(),
|
||||
redisValues.stream(),
|
||||
(productId, redisValue) -> {
|
||||
|
||||
if (Objects.isNull(redisValue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(param.getUniCodes())) {
|
||||
List<FeatureResourceDTO> featureResources = (List<FeatureResourceDTO>) ((Map) redisValue).values().stream()
|
||||
.flatMap(e -> JSONArray.parseArray(JSONArray.toJSONString(e), FeatureResourceDTO.class).stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return Pair.of(productId, featureResources);
|
||||
}
|
||||
|
||||
List<FeatureResourceDTO> featureResources = (List<FeatureResourceDTO>) ((List) redisValue).stream()
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(e -> JSONArray.parseArray((String) e, FeatureResourceDTO.class).stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return Pair.of(productId, featureResources);
|
||||
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(Pair::getKey, Pair::getValue));
|
||||
}
|
||||
|
||||
private void fillCacheProductFeatureResource(ListProductFeatureResourceParam param,
|
||||
Map<Long, List<FeatureResourceDTO>> featureResourceCached) {
|
||||
|
||||
Sets.SetView<Long> difference = Sets.difference(param.getProductIds(), featureResourceCached.keySet());
|
||||
if (difference.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder()
|
||||
.productModuleIds(difference)
|
||||
.type(NEW_FEATURE)
|
||||
.featureResourceTypes(Lists.newArrayList(FeatureResourceType.MENU.getCode(),
|
||||
FeatureResourceType.PAGE.getCode(),
|
||||
FeatureResourceType.MENU_PARTITION_GROUP.getCode(),
|
||||
FeatureResourceType.GROUP.getCode(),
|
||||
FeatureResourceType.APP_ENTRY.getCode()))
|
||||
.build();
|
||||
List<SaasProductModuleFeatureRelation> productPermissions = productFeatureRelationService.list(pageProductFeatureRelationReq);
|
||||
|
||||
List<ProductFeatureResource> productFeatureResources = cacheProductSaasFeatureResourceHandler.resolveProductFeatureResources(productPermissions);
|
||||
if (CollectionUtils.isEmpty(productFeatureResources)) return;
|
||||
|
||||
StoreProductFeatureResourceParam storeProductFeatureResourceParam = StoreProductFeatureResourceParam.builder()
|
||||
.productFeatureResources(productFeatureResources)
|
||||
.build();
|
||||
store(storeProductFeatureResourceParam);
|
||||
|
||||
Map<Long, List<FeatureResourceDTO>> productFeatureResourceMap = productFeatureResources.stream()
|
||||
.collect(Collectors.toMap(ProductFeatureResource::getProductId, ProductFeatureResource::getFeatureResources));
|
||||
featureResourceCached.putAll(productFeatureResourceMap);
|
||||
}
|
||||
|
||||
private String getKey(Object... params) {
|
||||
return String.format(PRODUCT_SAAS_FEATURE_RESOURCE_KEY, params);
|
||||
}
|
||||
}
|
||||
@ -2,14 +2,20 @@ package cn.axzo.tyr.server.service.impl;
|
||||
|
||||
import cn.axzo.foundation.exception.Axssert;
|
||||
import cn.axzo.pokonyan.config.redis.RedisClient;
|
||||
import cn.axzo.tyr.client.model.res.SaasRoleRes;
|
||||
import cn.axzo.tyr.server.event.inner.CacheRolePermissionHandler;
|
||||
import cn.axzo.tyr.server.service.RolePermissionCacheService;
|
||||
import cn.axzo.tyr.server.service.RoleService;
|
||||
import cn.hutool.core.lang.Pair;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
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.lang3.BooleanUtils;
|
||||
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.RedisCallback;
|
||||
import org.springframework.data.redis.core.RedisOperations;
|
||||
@ -20,8 +26,8 @@ import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
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;
|
||||
|
||||
@ -35,23 +41,73 @@ public class RolePermissionCacheServiceImpl implements RolePermissionCacheServic
|
||||
|
||||
@Autowired
|
||||
protected StringRedisTemplate redisTemplate;
|
||||
@Autowired
|
||||
private RoleService roleService;
|
||||
@Autowired
|
||||
private CacheRolePermissionHandler cacheRolePermissionHandler;
|
||||
|
||||
|
||||
/** 角色权限缓存过期时间 **/
|
||||
@Value("${role.permission.expire:180}")
|
||||
private Long expireInDays;
|
||||
|
||||
@Override
|
||||
public List<PermissionDTO> list(ListRolePermissionParam param) {
|
||||
public Map<Long, List<PermissionDTO>> list(ListRolePermissionParam param) {
|
||||
if (CollectionUtils.isEmpty(param.getRoleIds())) {
|
||||
return Collections.emptyList();
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Set<String> redisKeys = param.getRoleIds().stream()
|
||||
.map(this::getKey)
|
||||
.collect(Collectors.toSet());
|
||||
Map<Long, List<PermissionDTO>> permissions = listRolePermissionCached(param);
|
||||
|
||||
// 聚合是因为角色的权限点有重复,网络io压力大
|
||||
Set<String> redisValues = redisTemplate.opsForSet().union(redisKeys);
|
||||
return redisValues.stream()
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.map(value -> JSONObject.parseObject(value, PermissionDTO.class))
|
||||
.collect(Collectors.toList());
|
||||
fillCacheRolePermissions(param, permissions);
|
||||
return permissions;
|
||||
}
|
||||
|
||||
|
||||
private Map<Long, List<PermissionDTO>> listRolePermissionCached(ListRolePermissionParam param) {
|
||||
|
||||
List<Object> redisValues = redisTemplate.executePipelined(new SessionCallback<Object>() {
|
||||
@Override
|
||||
public Object execute(RedisOperations operations) throws DataAccessException {
|
||||
|
||||
for (Long roleId : param.getRoleIds()) {
|
||||
String redisKey = getKey(roleId);
|
||||
if (CollectionUtils.isEmpty(param.getFeatureCodes())) {
|
||||
RedisClient.HashOps.hGetAll(redisKey);
|
||||
} else {
|
||||
RedisClient.HashOps.hMultiGet(redisKey, Lists.newArrayList(param.getFeatureCodes()));
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
return Streams.zip(param.getRoleIds().stream(),
|
||||
redisValues.stream(),
|
||||
(roleId, redisValue) -> {
|
||||
|
||||
if (Objects.isNull(redisValue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(param.getFeatureCodes())) {
|
||||
|
||||
List<PermissionDTO> permissions = (List<PermissionDTO>) ((Map) redisValue).values().stream()
|
||||
.flatMap(e -> JSONArray.parseArray(JSONArray.toJSONString(e), PermissionDTO.class).stream())
|
||||
.collect(Collectors.toList());
|
||||
return Pair.of(roleId, permissions);
|
||||
}
|
||||
|
||||
List<PermissionDTO> permissions = (List<PermissionDTO>) ((List) redisValue).stream()
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(e -> JSONArray.parseArray((String) e, PermissionDTO.class).stream())
|
||||
.collect(Collectors.toList());
|
||||
return Pair.of(roleId, permissions);
|
||||
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(Pair::getKey, Pair::getValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -66,12 +122,16 @@ public class RolePermissionCacheServiceImpl implements RolePermissionCacheServic
|
||||
for (RolePermission rolePermission : param.getRolePermissions()) {
|
||||
String redisKey = getKey(rolePermission.getRoleId());
|
||||
|
||||
String[] redisValues = rolePermission.getPermissions().stream()
|
||||
.map(JSONObject::toJSONString)
|
||||
.toArray(String[]::new);
|
||||
Map<String, String> redisValues = rolePermission.getPermissions().stream()
|
||||
.collect(Collectors.groupingBy(PermissionDTO::getFeatureCode))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue())));
|
||||
|
||||
RedisClient.SetOps.sAdd(redisKey, redisValues);
|
||||
redisTemplate.expire(redisKey, 4, TimeUnit.DAYS);
|
||||
// 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁
|
||||
redisTemplate.delete(redisKey);
|
||||
RedisClient.HashOps.hPutAll(redisKey, redisValues);
|
||||
redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS);
|
||||
log.info("succeed to store role permission: redisKey:{} value:{}", redisKey, redisValues);
|
||||
}
|
||||
return null;
|
||||
@ -100,6 +160,45 @@ public class RolePermissionCacheServiceImpl implements RolePermissionCacheServic
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装在缓存中没有查询到权限的角色权限
|
||||
* @param param
|
||||
* @param permissionCached
|
||||
*/
|
||||
private void fillCacheRolePermissions(ListRolePermissionParam param,
|
||||
Map<Long, List<PermissionDTO>> permissionCached) {
|
||||
|
||||
Sets.SetView<Long> difference = Sets.difference(param.getRoleIds(), permissionCached.keySet());
|
||||
if (difference.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
|
||||
.roleIds(Lists.newArrayList(difference))
|
||||
.needPermissionRelation(true)
|
||||
.build();
|
||||
List<SaasRoleRes> roles = roleService.list(listSaasRoleParam);
|
||||
|
||||
if (CollectionUtils.isEmpty(roles)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<RolePermission> rolePermissions = cacheRolePermissionHandler.resolveRolePermission(roles);
|
||||
|
||||
if (CollectionUtils.isEmpty(rolePermissions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
StoreRolePermissionParam storeRolePermissionParam = StoreRolePermissionParam.builder()
|
||||
.rolePermissions(rolePermissions)
|
||||
.build();
|
||||
store(storeRolePermissionParam);
|
||||
|
||||
Map<Long, List<PermissionDTO>> rolePermissionMap = rolePermissions.stream()
|
||||
.collect(Collectors.toMap(RolePermission::getRoleId, RolePermission::getPermissions));
|
||||
permissionCached.putAll(rolePermissionMap);
|
||||
}
|
||||
|
||||
private String getKey(Object... params) {
|
||||
return String.format(ROLE_PERMISSION_KEY, params);
|
||||
}
|
||||
|
||||
@ -0,0 +1,182 @@
|
||||
package cn.axzo.tyr.server.service.impl;
|
||||
|
||||
import cn.axzo.foundation.exception.Axssert;
|
||||
import cn.axzo.pokonyan.config.redis.RedisClient;
|
||||
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
|
||||
import cn.axzo.tyr.client.model.res.SaasRoleRes;
|
||||
import cn.axzo.tyr.server.event.inner.CacheRoleSaasFeatureResourceHandler;
|
||||
import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService;
|
||||
import cn.axzo.tyr.server.service.RoleService;
|
||||
import cn.hutool.core.lang.Pair;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
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.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.redis.core.RedisCallback;
|
||||
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.util.CollectionUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.tyr.server.config.exception.BizResultCode.REDIS_ROLE_NOT_NULL;
|
||||
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class RoleSaasFeatureResourceCacheServiceImpl implements RoleSaasFeatureResourceCacheService {
|
||||
|
||||
private static final String ROLE_SAAS_FEATURE_RESOURCE_KEY = "role:feature:resource:%s";
|
||||
|
||||
@Autowired
|
||||
protected StringRedisTemplate redisTemplate;
|
||||
@Autowired
|
||||
private RoleService roleService;
|
||||
@Autowired
|
||||
private CacheRoleSaasFeatureResourceHandler cacheRoleSaasFeatureResourceHandler;
|
||||
|
||||
|
||||
/** 角色菜单缓存过期时间 **/
|
||||
@Value("${role.feature.resource.expire:180}")
|
||||
private Long expireInDays;
|
||||
|
||||
@Override
|
||||
public Map<Long, List<SaasFeatureResourceDTO>> list(ListRoleSaasFeatureResourceParam param) {
|
||||
if (CollectionUtils.isEmpty(param.getRoleIds())) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<Long, List<SaasFeatureResourceDTO>> featureResources = listRoleSaasFeatureResourceCached(param);
|
||||
|
||||
fillCacheRoleFeatureResources(param, featureResources);
|
||||
return featureResources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(StoreRoleSaasFeatureResourceParam param) {
|
||||
Axssert.check(param.getRoleSaasFeatureResources().stream().allMatch(e -> Objects.nonNull(e.getRoleId())), REDIS_ROLE_NOT_NULL);
|
||||
|
||||
redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
|
||||
|
||||
connection.openPipeline();
|
||||
|
||||
for (RoleFeatureResource roleFeatureResource : param.getRoleSaasFeatureResources()) {
|
||||
String redisKey = getKey(roleFeatureResource.getRoleId());
|
||||
|
||||
Map<String, String> redisValues = roleFeatureResource.getSaasFeatureResources().stream()
|
||||
.collect(Collectors.groupingBy(SaasFeatureResourceDTO::getUniCode))
|
||||
.entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, e -> JSONObject.toJSONString(e.getValue())));
|
||||
|
||||
// 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁
|
||||
redisTemplate.delete(redisKey);
|
||||
RedisClient.HashOps.hPutAll(redisKey, redisValues);
|
||||
redisTemplate.expire(redisKey, expireInDays, TimeUnit.DAYS);
|
||||
log.info("succeed to store role featureResource: redisKey:{} value:{}", redisKey, redisValues);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private Map<Long, List<SaasFeatureResourceDTO>> listRoleSaasFeatureResourceCached(ListRoleSaasFeatureResourceParam param) {
|
||||
|
||||
List<Object> redisValues = redisTemplate.executePipelined(new SessionCallback<Object>() {
|
||||
@Override
|
||||
public Object execute(RedisOperations operations) throws DataAccessException {
|
||||
|
||||
for (Long roleId : param.getRoleIds()) {
|
||||
String redisKey = getKey(roleId);
|
||||
if (CollectionUtils.isEmpty(param.getUniCodes())) {
|
||||
RedisClient.HashOps.hGetAll(redisKey);
|
||||
} else {
|
||||
RedisClient.HashOps.hMultiGet(redisKey, Lists.newArrayList(param.getUniCodes()));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
return Streams.zip(param.getRoleIds().stream(),
|
||||
redisValues.stream(),
|
||||
(roleId, redisValue) -> {
|
||||
|
||||
if (Objects.isNull(redisValue)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(param.getUniCodes())) {
|
||||
|
||||
List<SaasFeatureResourceDTO> featureResources = (List<SaasFeatureResourceDTO>) ((Map) redisValue).values().stream()
|
||||
.flatMap(e -> JSONArray.parseArray(JSONArray.toJSONString(e), SaasFeatureResourceDTO.class).stream())
|
||||
.collect(Collectors.toList());
|
||||
return Pair.of(roleId, featureResources);
|
||||
}
|
||||
|
||||
List<SaasFeatureResourceDTO> featureResources = (List<SaasFeatureResourceDTO>) ((List) redisValue).stream()
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(e -> JSONArray.parseArray((String) e, SaasFeatureResourceDTO.class).stream())
|
||||
.collect(Collectors.toList());
|
||||
return Pair.of(roleId, featureResources);
|
||||
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(Pair::getKey, Pair::getValue));
|
||||
}
|
||||
|
||||
private void fillCacheRoleFeatureResources(ListRoleSaasFeatureResourceParam param,
|
||||
Map<Long, List<SaasFeatureResourceDTO>> featureResources) {
|
||||
|
||||
Sets.SetView<Long> difference = Sets.difference(param.getRoleIds(), featureResources.keySet());
|
||||
if (difference.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
|
||||
.roleIds(Lists.newArrayList(difference))
|
||||
.needPermissionRelation(true)
|
||||
.type(NEW_FEATURE)
|
||||
.featureResourceTypes(Lists.newArrayList(FeatureResourceType.MENU,
|
||||
FeatureResourceType.PAGE,
|
||||
FeatureResourceType.MENU_PARTITION_GROUP,
|
||||
FeatureResourceType.GROUP,
|
||||
FeatureResourceType.APP_ENTRY))
|
||||
.build();
|
||||
List<SaasRoleRes> roles = roleService.list(listSaasRoleParam);
|
||||
|
||||
if (CollectionUtils.isEmpty(roles)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<RoleSaasFeatureResourceCacheService.RoleFeatureResource> roleFeatureResources = cacheRoleSaasFeatureResourceHandler.resolveRoleFeatureResource(roles);
|
||||
|
||||
if (CollectionUtils.isEmpty(roleFeatureResources)) {
|
||||
return;
|
||||
}
|
||||
|
||||
StoreRoleSaasFeatureResourceParam storeRolePermissionParam = StoreRoleSaasFeatureResourceParam.builder()
|
||||
.roleSaasFeatureResources(roleFeatureResources)
|
||||
.build();
|
||||
store(storeRolePermissionParam);
|
||||
|
||||
Map<Long, List<SaasFeatureResourceDTO>> rolePermissionMap = roleFeatureResources.stream()
|
||||
.collect(Collectors.toMap(RoleSaasFeatureResourceCacheService.RoleFeatureResource::getRoleId, RoleSaasFeatureResourceCacheService.RoleFeatureResource::getSaasFeatureResources));
|
||||
featureResources.putAll(rolePermissionMap);
|
||||
}
|
||||
|
||||
private String getKey(Object... params) {
|
||||
return String.format(ROLE_SAAS_FEATURE_RESOURCE_KEY, params);
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
|
||||
import cn.axzo.foundation.dao.support.converter.PageConverter;
|
||||
import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper;
|
||||
import cn.axzo.framework.domain.page.PageResp;
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import cn.axzo.tyr.client.common.enums.PermissionRelationOperateLogSceneEnum;
|
||||
import cn.axzo.tyr.client.common.enums.RoleResourceTypeEnum;
|
||||
@ -16,6 +17,7 @@ import cn.axzo.tyr.client.model.enums.PermissionGroupType;
|
||||
import cn.axzo.tyr.client.model.req.ChangeGroupLeaderRoleReq;
|
||||
import cn.axzo.tyr.client.model.req.FeatureRoleRelationReq;
|
||||
import cn.axzo.tyr.client.model.req.PagePgroupPermissionRelationReq;
|
||||
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
|
||||
import cn.axzo.tyr.client.model.req.QueryByIdentityIdTypeReq;
|
||||
import cn.axzo.tyr.client.model.req.QueryRoleByNameReq;
|
||||
import cn.axzo.tyr.client.model.req.QuerySaasPermissionGroupReq;
|
||||
@ -27,6 +29,7 @@ import cn.axzo.tyr.client.model.res.IsSuperAdminRes;
|
||||
import cn.axzo.tyr.client.model.res.QueryBatchByIdentityIdTypeRes;
|
||||
import cn.axzo.tyr.client.model.res.QueryRoleByNameResp;
|
||||
import cn.axzo.tyr.client.model.res.RoleWithUserRes;
|
||||
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
|
||||
import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes;
|
||||
import cn.axzo.tyr.client.model.res.SaasPermissionRes;
|
||||
import cn.axzo.tyr.client.model.res.SaasRoleGroupRes;
|
||||
@ -40,6 +43,31 @@ import cn.axzo.tyr.client.model.vo.SaasRoleCategoryVO;
|
||||
import cn.axzo.tyr.client.model.vo.SaasRoleGroupCodeVO;
|
||||
import cn.axzo.tyr.client.model.vo.SaasRoleVO;
|
||||
import cn.axzo.tyr.client.model.vo.SaveOrUpdateRoleVO;
|
||||
import cn.axzo.tyr.server.config.MqProducer;
|
||||
import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload;
|
||||
import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload;
|
||||
import cn.axzo.tyr.server.model.ResourcePermission;
|
||||
import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO;
|
||||
import cn.axzo.tyr.server.model.RoleFeatureRelation;
|
||||
import cn.axzo.tyr.server.model.RoleWithFeature;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPermissionGroupDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPgroupPermissionRelationDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPgroupRoleRelationDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasRoleDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasRoleGroupDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasRoleGroupRelationDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasRoleUserRelationDao;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeature;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPermissionGroup;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPgroupRoleRelation;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasRole;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasRoleGroup;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasRoleGroupRelation;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasRoleWithUser;
|
||||
import cn.axzo.tyr.server.model.*;
|
||||
import cn.axzo.tyr.server.repository.dao.*;
|
||||
import cn.axzo.tyr.server.repository.entity.*;
|
||||
@ -93,6 +121,8 @@ import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static cn.axzo.tyr.server.event.inner.EventTypeEnum.ROLE_PERMISSION_CREATED;
|
||||
import static cn.axzo.tyr.server.event.inner.EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT;
|
||||
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE;
|
||||
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE;
|
||||
|
||||
@ -155,6 +185,11 @@ public class RoleServiceImpl extends ServiceImpl<SaasRoleMapper, SaasRole>
|
||||
@Value("${groupLeader.code:projectTeamGPLeader}")
|
||||
private String groupLeaderCode;
|
||||
|
||||
@Autowired
|
||||
private final MqProducer mqProducer;
|
||||
|
||||
private static final String TARGET_TYPE = "saasFeatureResourceId";
|
||||
|
||||
@Override
|
||||
public List<SaasRoleVO> queryByIdentityIdType(Long identityId, Integer identityType, Long workspaceId, Long ouId, Boolean includePermissionGroup) {
|
||||
// 查询人关联的角色id
|
||||
@ -363,6 +398,15 @@ public class RoleServiceImpl extends ServiceImpl<SaasRoleMapper, SaasRole>
|
||||
// 保存新的菜单资源树权限
|
||||
saveSaasFeatureResourcePermission(saveOrUpdateRole, saasFeatureResources, saasPermissionGroup);
|
||||
|
||||
|
||||
Event event = Event.builder()
|
||||
.targetType(TARGET_TYPE)
|
||||
.eventCode(ROLE_PERMISSION_CREATED.getEventCode())
|
||||
.data(RolePermissionCreatedPayload.builder()
|
||||
.roleIds(Sets.newHashSet(saasRole.getId()))
|
||||
.build())
|
||||
.build();
|
||||
mqProducer.send(event);
|
||||
return saasRole.getId();
|
||||
}
|
||||
|
||||
@ -1128,7 +1172,7 @@ public class RoleServiceImpl extends ServiceImpl<SaasRoleMapper, SaasRole>
|
||||
PageSaasRoleParam pageParam = PageSaasRoleParam.builder().build();
|
||||
BeanUtils.copyProperties(param, pageParam);
|
||||
pageParam.setPage(pageNumber);
|
||||
pageParam.setPageSize(500);
|
||||
pageParam.setPageSize(10000);
|
||||
return page(pageParam);
|
||||
});
|
||||
}
|
||||
@ -1343,6 +1387,30 @@ public class RoleServiceImpl extends ServiceImpl<SaasRoleMapper, SaasRole>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(req)) {
|
||||
return;
|
||||
}
|
||||
// 入参的terminal不是必填,所以根据第一个id查询terminal,目前不会是所有端一起更新
|
||||
PageSaasFeatureResourceReq listSaasFeatureResourceParam = PageSaasFeatureResourceReq.builder()
|
||||
.ids(Lists.newArrayList(req.get(0).getFeatureId()))
|
||||
.build();
|
||||
String terminal = saasFeatureResourceService.list(listSaasFeatureResourceParam).stream()
|
||||
.findFirst()
|
||||
.map(SaasFeatureResourceResp::getTerminal)
|
||||
.orElse(null);
|
||||
if (StringUtils.isBlank(terminal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Event event = Event.builder()
|
||||
.targetType(TARGET_TYPE)
|
||||
.eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode())
|
||||
.data(SaasFeatureResourceUpsertPayload.builder()
|
||||
.terminal(terminal)
|
||||
.build())
|
||||
.build();
|
||||
mqProducer.send(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -8,11 +8,14 @@ import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper;
|
||||
import cn.axzo.foundation.exception.Axssert;
|
||||
import cn.axzo.foundation.page.PageResp;
|
||||
import cn.axzo.framework.domain.web.code.BaseCode;
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import cn.axzo.pokonyan.config.redis.RedisClient;
|
||||
import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType;
|
||||
import cn.axzo.tyr.client.common.enums.FeatureResourceStatus;
|
||||
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
|
||||
import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum;
|
||||
import cn.axzo.tyr.client.model.enums.DelegatedType;
|
||||
import cn.axzo.tyr.client.model.req.DeleteFeatureResourceReq;
|
||||
import cn.axzo.tyr.client.model.req.FeatureComponentSaveReq;
|
||||
import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq;
|
||||
@ -26,10 +29,14 @@ import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode;
|
||||
import cn.axzo.tyr.client.model.res.PageElementBasicDTO;
|
||||
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
|
||||
import cn.axzo.tyr.server.common.util.Throws;
|
||||
import cn.axzo.tyr.server.config.MqProducer;
|
||||
import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload;
|
||||
import cn.axzo.tyr.server.model.ResourcePermission;
|
||||
import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO;
|
||||
import cn.axzo.tyr.server.model.convert.SaasFeatureResourceConvert;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeature;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation;
|
||||
@ -41,24 +48,43 @@ import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService;
|
||||
import cn.azxo.framework.common.utils.StringUtils;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.lang.Pair;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.redis.core.RedisOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.SessionCallback;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
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.FEATURE_RESOURCE_NOT_FOUND;
|
||||
import static cn.axzo.tyr.server.event.inner.EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT;
|
||||
import static cn.axzo.tyr.server.repository.entity.SaasFeatureResource.DEFAULT_WORKSPACE_TYPE;
|
||||
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE;
|
||||
|
||||
@ -83,7 +109,19 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
|
||||
private final SaasPageElementService saasPageElementService;
|
||||
private final SaasPgroupPermissionRelationService saasPgroupPermissionRelationService;
|
||||
private final SaasPageElementFeatureResourceRelationService saasPageElementFeatureResourceRelationService;
|
||||
private final MqProducer mqProducer;
|
||||
private final SaasFeatureDao saasFeatureDao;
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
|
||||
/** 菜单树过期时间 **/
|
||||
@Value("${saas.feature.resource.expire:180}")
|
||||
private Long expireInDays;
|
||||
|
||||
private static final String SAAS_FEATURE_RESOURCE_KEY = "saas:feature:resource:%s";
|
||||
|
||||
private static final String TARGET_TYPE = "saasFeatureResourceId";
|
||||
@Override
|
||||
public List<SaasFeatureResource> listNavByIds(List<Long> featureIds, List<Integer> featureTypes) {
|
||||
//按需扩展要查询的字段
|
||||
@ -257,6 +295,18 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
|
||||
}
|
||||
deleteComponentRecursionById(baseResource.getId(), req.getComponentSaveReqList(), req.getOperatorId());
|
||||
|
||||
// 改不动了,消费MQ时查询子节点信息做逻辑处理,反正mq里面不能带太多的消息内容
|
||||
Set<Long> mqUpsertIds = Sets.newHashSet();
|
||||
mqUpsertIds.add(baseResource.getId());
|
||||
|
||||
Event event = Event.builder()
|
||||
.targetType(TARGET_TYPE)
|
||||
.eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode())
|
||||
.data(SaasFeatureResourceUpsertPayload.builder()
|
||||
.terminal(req.getTerminal())
|
||||
.build())
|
||||
.build();
|
||||
mqProducer.send(event);
|
||||
return baseResource.getId();
|
||||
}
|
||||
|
||||
@ -557,7 +607,9 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
List<String> uniCodes = Lists.transform(saasFeatureResources, SaasFeatureResource::getUniCode);
|
||||
Set<String> uniCodes = saasFeatureResources.stream()
|
||||
.map(SaasFeatureResource::getUniCode)
|
||||
.collect(Collectors.toSet());
|
||||
PageElementFeatureResourceRelationReq pageElementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq.builder()
|
||||
.featureResourceUniCodes(uniCodes)
|
||||
.build();
|
||||
@ -606,6 +658,15 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
deletePermissionRelations(deleteFeatureResource);
|
||||
|
||||
Event event = Event.builder()
|
||||
.targetType(TARGET_TYPE)
|
||||
.eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode())
|
||||
.data(SaasFeatureResourceUpsertPayload.builder()
|
||||
.terminal(featureResource.getTerminal())
|
||||
.build())
|
||||
.build();
|
||||
mqProducer.send(event);
|
||||
}
|
||||
|
||||
private void deletePermissionRelations(List<SaasFeatureResourceResp> deleteFeatureResource) {
|
||||
@ -656,4 +717,133 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
|
||||
recursiveSetPageElement(e.getChildren(), uniCodeElementsMap);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeCache(StoreSaasFeatureResourceCache param) {
|
||||
|
||||
redisTemplate.executePipelined(new SessionCallback<Object>() {
|
||||
@Override
|
||||
public Object execute(RedisOperations operations) throws DataAccessException {
|
||||
|
||||
for (SaasFeatureResourceDTO saasFeatureResource : param.getSaasFeatureResources()) {
|
||||
String redisKey = getKey(saasFeatureResource.getTerminal());
|
||||
String redisValue = JSONObject.toJSONString(saasFeatureResource.getFeatures());
|
||||
RedisClient.StringOps.setEx(redisKey, redisValue,
|
||||
expireInDays, TimeUnit.DAYS);
|
||||
log.info("succeed to store featureResource: redisKey:{} value:{}", redisKey, redisValue);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<SaasFeatureResourceCache>> listCache(ListSaasFeatureResourceCache param) {
|
||||
if (org.springframework.util.CollectionUtils.isEmpty(param.getTerminals())) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, List<SaasFeatureResourceCache>> featureSourceCached = listFeatureSourceCached(param);
|
||||
|
||||
fillCacheFeatureSources(param, featureSourceCached);
|
||||
|
||||
return featureSourceCached;
|
||||
|
||||
}
|
||||
|
||||
private Map<String, List<SaasFeatureResourceCache>> listFeatureSourceCached(ListSaasFeatureResourceCache param) {
|
||||
|
||||
List<Object> redisValues = redisTemplate.executePipelined(new SessionCallback<Object>() {
|
||||
@Override
|
||||
public Object execute(RedisOperations operations) throws DataAccessException {
|
||||
|
||||
for (String terminal : param.getTerminals()) {
|
||||
String redisKey = getKey(terminal);
|
||||
|
||||
RedisClient.StringOps.get(redisKey);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
return Streams.zip(param.getTerminals().stream(),
|
||||
redisValues.stream(),
|
||||
(terminal, redisValue) -> {
|
||||
|
||||
if (Objects.isNull(redisValue)) {
|
||||
return null;
|
||||
}
|
||||
return Pair.of(terminal, JSONArray.parseArray((String) redisValue,
|
||||
SaasFeatureResourceCache.class));
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(Pair::getKey, Pair::getValue));
|
||||
}
|
||||
|
||||
private void fillCacheFeatureSources(ListSaasFeatureResourceCache param,
|
||||
Map<String, List<SaasFeatureResourceCache>> featureSourceCached) {
|
||||
|
||||
Sets.SetView<String> difference = Sets.difference(param.getTerminals(), featureSourceCached.keySet());
|
||||
if (difference.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<SaasFeatureResourceDTO> saasFeatureResources = resolveSaasFeature(difference);
|
||||
|
||||
SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder()
|
||||
.saasFeatureResources(saasFeatureResources)
|
||||
.build();
|
||||
storeCache(storeSaasFeatureResourceCache);
|
||||
|
||||
Map<String, List<SaasFeatureResourceCache>> featureSourceMap = saasFeatureResources.stream()
|
||||
.collect(Collectors.toMap(SaasFeatureResourceDTO::getTerminal, SaasFeatureResourceDTO::getFeatures));
|
||||
featureSourceCached.putAll(featureSourceMap);
|
||||
}
|
||||
|
||||
private List<SaasFeatureResourceDTO> resolveSaasFeature(Set<String> terminals) {
|
||||
Map<String, List<SaasFeatureResourceService.SaasFeatureResourceCache>> saasFeatures = saasFeatureDao.lambdaQuery()
|
||||
.in(SaasFeature::getTerminal, terminals)
|
||||
.list()
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(SaasFeature::getTerminal,
|
||||
Collectors.mapping(e -> SaasFeatureResourceService.SaasFeatureResourceCache
|
||||
.builder()
|
||||
.featureId(e.getId())
|
||||
.notAuth(DelegatedType.notAuth(e.getDelegatedType()))
|
||||
.build(), Collectors.toList())));
|
||||
|
||||
List<SaasFeatureResourceDTO> allFeatureResources = Lists.newArrayList();
|
||||
List<SaasFeatureResourceDTO> featureResources = saasFeatures.entrySet().stream()
|
||||
.map(e -> SaasFeatureResourceDTO.builder()
|
||||
.terminal(e.getKey())
|
||||
.features(e.getValue())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.terminals(terminals)
|
||||
.build();
|
||||
|
||||
List<SaasFeatureResourceDTO> saasFeatureResources = list(pageSaasFeatureResourceReq)
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(SaasFeatureResourceResp::getTerminal,
|
||||
Collectors.mapping(e -> SaasFeatureResourceService.SaasFeatureResourceCache
|
||||
.builder()
|
||||
.featureId(e.getId())
|
||||
.notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType()))
|
||||
.build(), Collectors.toList())))
|
||||
.entrySet().stream()
|
||||
.map(e -> SaasFeatureResourceDTO.builder()
|
||||
.terminal(e.getKey())
|
||||
.features(e.getValue())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
allFeatureResources.addAll(featureResources);
|
||||
allFeatureResources.addAll(saasFeatureResources);
|
||||
return allFeatureResources;
|
||||
}
|
||||
|
||||
private String getKey(Object... params) {
|
||||
return String.format(SAAS_FEATURE_RESOURCE_KEY, params);
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ public class SaasPageElementFeatureResourceRelationServiceImpl extends ServiceIm
|
||||
public List<SaasPageElementFeatureResourceRelation> list(PageElementFeatureResourceRelationReq param) {
|
||||
return PageConverter.drainAll(pageNumber -> {
|
||||
param.setPage(pageNumber);
|
||||
param.setPageSize(500);
|
||||
param.setPageSize(1000);
|
||||
return page(param);
|
||||
});
|
||||
}
|
||||
|
||||
@ -7,21 +7,33 @@ import cn.axzo.basics.profiles.api.UserProfileServiceApi;
|
||||
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
|
||||
import cn.axzo.foundation.exception.BusinessException;
|
||||
import cn.axzo.framework.domain.page.PageResp;
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
|
||||
import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum;
|
||||
import cn.axzo.tyr.client.common.enums.PageElementTypeEnum;
|
||||
import cn.axzo.tyr.client.common.enums.PermissionRelationOperateLogSceneEnum;
|
||||
import cn.axzo.tyr.client.model.req.*;
|
||||
import cn.axzo.tyr.client.model.req.GetPageElementReq;
|
||||
import cn.axzo.tyr.client.model.req.GetUserHasPermissionPageElementReq;
|
||||
import cn.axzo.tyr.client.model.req.IdentityAuthReq;
|
||||
import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO;
|
||||
import cn.axzo.tyr.client.model.req.PageElementReportReq;
|
||||
import cn.axzo.tyr.client.model.req.PageQueryElementReq;
|
||||
import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp;
|
||||
import cn.axzo.tyr.client.model.res.IdentityAuthRes;
|
||||
import cn.axzo.tyr.client.model.res.PageElementBasicDTO;
|
||||
import cn.axzo.tyr.client.model.res.PageElementResp;
|
||||
import cn.axzo.tyr.server.model.RelationOperateLogResourceBindElementDO;
|
||||
import cn.axzo.tyr.server.config.MqProducer;
|
||||
import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPageElementDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPageElementFeatureResourceRelationDao;
|
||||
import cn.axzo.tyr.server.repository.entity.*;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElement;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation;
|
||||
import cn.axzo.tyr.server.service.SaasPageElementService;
|
||||
import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationOperateLogService;
|
||||
import cn.axzo.tyr.server.service.TyrSaasAuthService;
|
||||
@ -45,12 +57,18 @@ import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.tyr.server.event.inner.EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT;
|
||||
|
||||
/**
|
||||
* @author likunpeng
|
||||
* @version 1.0
|
||||
@ -68,6 +86,7 @@ public class SaasPageElementServiceImpl implements SaasPageElementService {
|
||||
private final TyrSaasAuthService tyrSaasAuthService;
|
||||
private final SaasPgroupPermissionRelationOperateLogService saasPgroupPermissionRelationOperateLogService;
|
||||
private final UserProfileServiceApi userProfileServiceApi;
|
||||
private final MqProducer mqProducer;
|
||||
|
||||
@Qualifier("asyncExecutor")
|
||||
@Autowired
|
||||
@ -77,6 +96,8 @@ public class SaasPageElementServiceImpl implements SaasPageElementService {
|
||||
@Value("#{'${pageElement.report.secretKeys:1qaz@WSX}'.split(',')}")
|
||||
private List<String> reportSecretKeys;
|
||||
|
||||
private static final String TARGET_TYPE = "pageElementFeatureResourceId";
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void report(PageElementReportReq request) {
|
||||
@ -185,6 +206,16 @@ public class SaasPageElementServiceImpl implements SaasPageElementService {
|
||||
} catch (Exception e) {
|
||||
log.warn("save operate log error", e);
|
||||
}
|
||||
|
||||
|
||||
Event event = Event.builder()
|
||||
.targetType(TARGET_TYPE)
|
||||
.eventCode(PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode())
|
||||
.data(PageElementFeatureResourceUpsertPayload.builder()
|
||||
.terminal(modifyPageElementRelation.getTerminal())
|
||||
.build())
|
||||
.build();
|
||||
mqProducer.send(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -209,6 +209,8 @@ public class SaasRoleUserRelationServiceImpl extends ServiceImpl<SaasRoleUserRel
|
||||
.realName(Optional.ofNullable(saasRoleUsers.get(saasRoleUserRelation.getNaturalPersonId()))
|
||||
.map(SaasRoleUserV2DTO.SaasRoleUser::getRealName)
|
||||
.orElse(null))
|
||||
.identityType(saasRoleUserRelation.getIdentityType())
|
||||
.identityId(saasRoleUserRelation.getIdentityId())
|
||||
.build();
|
||||
|
||||
return SaasRoleUserV2DTO.builder()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -10,12 +10,13 @@ import cn.axzo.tyr.server.repository.dao.ProductModuleDao;
|
||||
import cn.axzo.tyr.server.repository.entity.ProductFeatureQuery;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation;
|
||||
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
|
||||
import cn.axzo.tyr.server.service.ProductPermissionCacheService;
|
||||
import cn.axzo.tyr.server.service.ProductSaasFeatureResourceCacheService;
|
||||
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;
|
||||
@ -53,7 +54,12 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
|
||||
@Autowired
|
||||
private ProductFeatureRelationService productFeatureRelationService;
|
||||
@Autowired
|
||||
protected StringRedisTemplate redisTemplate;
|
||||
private StringRedisTemplate redisTemplate;
|
||||
@Autowired
|
||||
private ProductPermissionCacheService productPermissionCacheService;
|
||||
@Autowired
|
||||
private ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService;
|
||||
|
||||
|
||||
/** 授权缓存过期时间 **/
|
||||
@Value("${workspace.product.expire:90}")
|
||||
@ -136,13 +142,7 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
ListWorkspaceProductParam listWorkspaceProductParam = ListWorkspaceProductParam.builder()
|
||||
.workspaceIds(param.getWorkspaceIds())
|
||||
.build();
|
||||
Map<Long, Set<Long>> workspaceProducts = listWorkspaceProduct(listWorkspaceProductParam);
|
||||
|
||||
// 存在项目没有在缓存中查询到产品的情况
|
||||
fillCacheWorkspaseProducts(param, workspaceProducts);
|
||||
Map<Long, Set<Long>> workspaceProducts = listWorkspaceProduct(param.getWorkspaceIds());
|
||||
|
||||
Set<Long> productIds = workspaceProducts.values().stream()
|
||||
.flatMap(Collection::stream)
|
||||
@ -152,19 +152,8 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
|
||||
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)
|
||||
.productIds(productIds)
|
||||
.featureResourceTypes(param.getFeatureResourceTypes())
|
||||
.terminal(param.getTerminal())
|
||||
.type(param.getType())
|
||||
@ -238,13 +227,13 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
|
||||
|
||||
/**
|
||||
* 组装在缓存中没有查询到产品的项目
|
||||
* @param param
|
||||
* @param workspaceIds
|
||||
* @param workspaceProducts
|
||||
*/
|
||||
private void fillCacheWorkspaseProducts(WorkspaceProductParam param,
|
||||
private void fillCacheWorkspaceProducts(Set<Long> workspaceIds,
|
||||
Map<Long, Set<Long>> workspaceProducts) {
|
||||
|
||||
Sets.SetView<Long> difference = Sets.difference(param.getWorkspaceIds(), workspaceProducts.keySet());
|
||||
Sets.SetView<Long> difference = Sets.difference(workspaceIds, workspaceProducts.keySet());
|
||||
if (difference.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@ -287,4 +276,124 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
|
||||
private String getKey(Object... params) {
|
||||
return String.format(WORKSPACE_PRODUCT_KEY, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WorkspaceProductPermission> listWorkspaceProductPermissionCached(ListWorkspaceProductPermissionCacheParam param) {
|
||||
Map<Long, Set<Long>> workspaceProducts = listWorkspaceProduct(param.getWorkspaceIds());
|
||||
|
||||
Set<Long> productIds = workspaceProducts.values().stream()
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (CollectionUtils.isEmpty(productIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
ProductPermissionCacheService.ListProductPermissionParam listProductPermissionParam = ProductPermissionCacheService.ListProductPermissionParam.builder()
|
||||
.productIds(productIds)
|
||||
.featureCodes(param.getFeatureCodes())
|
||||
.build();
|
||||
Map<Long, List<ProductPermissionCacheService.PermissionDTO>> productPermissionMap = productPermissionCacheService.list(listProductPermissionParam);
|
||||
|
||||
return workspaceProducts.entrySet().stream()
|
||||
.filter(e -> CollectionUtils.isNotEmpty(e.getValue()))
|
||||
.map(e -> {
|
||||
List<ProductPermission> productPermissions = e.getValue().stream()
|
||||
.map(productId -> {
|
||||
List<ProductPermissionCacheService.PermissionDTO> permissions = productPermissionMap.get(productId);
|
||||
if (CollectionUtils.isEmpty(permissions)) {
|
||||
return null;
|
||||
}
|
||||
return ProductPermission.builder()
|
||||
.productId(productId)
|
||||
.permissions(permissions)
|
||||
.build();
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
return WorkspaceProductPermission.builder()
|
||||
.workspaceId(e.getKey())
|
||||
.productPermissions(productPermissions)
|
||||
.build();
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Map<Long, Set<Long>> listWorkspaceProduct(Set<Long> workspaceIds) {
|
||||
if (CollectionUtils.isEmpty(workspaceIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
ListWorkspaceProductParam listWorkspaceProductParam = ListWorkspaceProductParam.builder()
|
||||
.workspaceIds(workspaceIds)
|
||||
.build();
|
||||
Map<Long, Set<Long>> workspaceProducts = listWorkspaceProduct(listWorkspaceProductParam);
|
||||
|
||||
// 存在项目没有在缓存中查询到产品的情况
|
||||
fillCacheWorkspaceProducts(workspaceIds, workspaceProducts);
|
||||
|
||||
Set<Long> productIds = workspaceProducts.values().stream()
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (CollectionUtils.isEmpty(productIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// 需要过滤掉已经被删除的产品
|
||||
Set<Long> finalProductIds = productModuleDao.listByIds(productIds).stream()
|
||||
.filter(productModule -> Objects.equals(productModule.getIsDelete(),0L))
|
||||
.map(BaseEntity::getId)
|
||||
.collect(Collectors.toSet());
|
||||
workspaceProducts.entrySet().forEach(e -> {
|
||||
Set<Long> effectProductIds = e.getValue().stream()
|
||||
.filter(finalProductIds::contains)
|
||||
.collect(Collectors.toSet());
|
||||
e.setValue(effectProductIds);
|
||||
});
|
||||
|
||||
return workspaceProducts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WorkspaceProductFeatureSource> listWorkspaceProductFeatureResourceCached(ListWorkspaceProductFeatureSourceCacheParam param) {
|
||||
Map<Long, Set<Long>> workspaceProducts = listWorkspaceProduct(param.getWorkspaceIds());
|
||||
|
||||
Set<Long> productIds = workspaceProducts.values().stream()
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (CollectionUtils.isEmpty(productIds)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
ProductSaasFeatureResourceCacheService.ListProductFeatureResourceParam listProductFeatureResourceParam = ProductSaasFeatureResourceCacheService.ListProductFeatureResourceParam.builder()
|
||||
.productIds(productIds)
|
||||
.uniCodes(param.getUniCodes())
|
||||
.build();
|
||||
Map<Long, List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO>> productFeatureResourceMap = productSaasFeatureResourceCacheService.list(listProductFeatureResourceParam);
|
||||
|
||||
return workspaceProducts.entrySet().stream()
|
||||
.filter(e -> CollectionUtils.isNotEmpty(e.getValue()))
|
||||
.map(e -> {
|
||||
List<ProductFeatureSource> productFeatureSources = e.getValue().stream()
|
||||
.map(productId -> {
|
||||
List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> featureResources = productFeatureResourceMap.get(productId);
|
||||
if (CollectionUtils.isEmpty(featureResources)) {
|
||||
return null;
|
||||
}
|
||||
return ProductFeatureSource.builder()
|
||||
.productId(productId)
|
||||
.featureResources(featureResources)
|
||||
.build();
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
return WorkspaceProductFeatureSource.builder()
|
||||
.workspaceId(e.getKey())
|
||||
.productFeatureSources(productFeatureSources)
|
||||
.build();
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,4 +19,16 @@
|
||||
AND natural_person_id = #{param.naturalPersonId}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="listRoleIds" resultType="java.lang.Long">
|
||||
SELECT DISTINCT role_id
|
||||
FROM saas_role_user_relation
|
||||
WHERE is_delete = 0
|
||||
<if test="param.ouId !=0 and param.ouId != null">
|
||||
AND ou_id = #{param.ouId}
|
||||
</if>
|
||||
<if test="param.workspaceId !=0 and param.workspaceId != null">
|
||||
AND workspace_id = #{param.workspaceId}
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
Loading…
Reference in New Issue
Block a user