feat:(REQ-2720) 修改菜单、没有页面元素的权限缓存,key使用uniCode
This commit is contained in:
parent
edc5f944f7
commit
5e847bea8b
@ -64,22 +64,6 @@ public class IdentityAuthReq {
|
|||||||
/** 是否使用缓存 - 默认true **/
|
/** 是否使用缓存 - 默认true **/
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private boolean useCache = true;
|
private boolean useCache = true;
|
||||||
public IdentityAuthRes toEmpty() {
|
|
||||||
IdentityAuthRes result = new IdentityAuthRes();
|
|
||||||
result.setIdentity(this.getIdentityId());
|
|
||||||
result.setIdentityType(this.getIdentityType());
|
|
||||||
result.setPersonId(this.getPersonId());
|
|
||||||
|
|
||||||
List<IdentityAuthRes.WorkspacePermission> permissions = this.getWorkspaceOusPairs().stream()
|
|
||||||
.map(workspaceOuPair -> IdentityAuthRes.WorkspacePermission.builder()
|
|
||||||
.workspaceId(workspaceOuPair.getWorkspaceId())
|
|
||||||
.ouId(workspaceOuPair.getOuId())
|
|
||||||
.build())
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
result.setPermissions(permissions);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void distinctOUWorkspacePair() {
|
public void distinctOUWorkspacePair() {
|
||||||
if (CollectionUtil.isEmpty(this.workspaceOusPairs)) {
|
if (CollectionUtil.isEmpty(this.workspaceOusPairs)) {
|
||||||
|
|||||||
@ -25,5 +25,4 @@ public class ListSaasRoleGroupParam {
|
|||||||
|
|
||||||
@CriteriaField(ignore = true)
|
@CriteriaField(ignore = true)
|
||||||
private Boolean needRole;
|
private Boolean needRole;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package cn.axzo.tyr.client.model.req;
|
|||||||
import cn.axzo.foundation.dao.support.wrapper.CriteriaField;
|
import cn.axzo.foundation.dao.support.wrapper.CriteriaField;
|
||||||
import cn.axzo.foundation.dao.support.wrapper.Operator;
|
import cn.axzo.foundation.dao.support.wrapper.Operator;
|
||||||
import cn.axzo.foundation.page.IPageReq;
|
import cn.axzo.foundation.page.IPageReq;
|
||||||
|
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -40,4 +41,10 @@ public class PageProductFeatureRelationReq implements IPageReq {
|
|||||||
|
|
||||||
@CriteriaField(field = "type", operator = Operator.EQ)
|
@CriteriaField(field = "type", operator = Operator.EQ)
|
||||||
private Integer type;
|
private Integer type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询菜单树节点类型
|
||||||
|
*/
|
||||||
|
@CriteriaField(field = "featureType", operator = Operator.IN)
|
||||||
|
private List<Integer> featureResourceTypes;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,9 @@ import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO;
|
|||||||
import cn.axzo.tyr.client.model.vo.SaveOrUpdateRoleVO;
|
import cn.axzo.tyr.client.model.vo.SaveOrUpdateRoleVO;
|
||||||
import cn.axzo.tyr.server.event.outer.CacheWorkspaceProductHandler;
|
import cn.axzo.tyr.server.event.outer.CacheWorkspaceProductHandler;
|
||||||
import cn.axzo.tyr.server.event.payload.ServicePkgProductCreatedPayload;
|
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.CacheProductPermissionJob;
|
||||||
|
import cn.axzo.tyr.server.job.CacheRoleFeatureResourceJob;
|
||||||
import cn.axzo.tyr.server.job.CacheRolePermissionJob;
|
import cn.axzo.tyr.server.job.CacheRolePermissionJob;
|
||||||
import cn.axzo.tyr.server.job.CacheSaasFeatureJob;
|
import cn.axzo.tyr.server.job.CacheSaasFeatureJob;
|
||||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
|
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
|
||||||
@ -133,6 +135,10 @@ public class PrivateController {
|
|||||||
private CacheRolePermissionJob cacheRolePermissionJob;
|
private CacheRolePermissionJob cacheRolePermissionJob;
|
||||||
@Autowired
|
@Autowired
|
||||||
private CacheSaasFeatureJob cacheSaasFeatureJob;
|
private CacheSaasFeatureJob cacheSaasFeatureJob;
|
||||||
|
@Autowired
|
||||||
|
private CacheProductFeatureResourceJob cacheProductFeatureResourceJob;
|
||||||
|
@Autowired
|
||||||
|
private CacheRoleFeatureResourceJob cacheRoleFeatureResourceJob;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统一层级的roleGroup按照id升序,sort从1递增
|
* 统一层级的roleGroup按照id升序,sort从1递增
|
||||||
@ -673,6 +679,18 @@ public class PrivateController {
|
|||||||
return "ok";
|
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";
|
||||||
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
|
|||||||
@ -0,0 +1,155 @@
|
|||||||
|
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.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 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.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.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class CacheProductSaasFeatureResourceHandler implements EventHandler, InitializingBean {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EventConsumer eventConsumer;
|
||||||
|
@Autowired
|
||||||
|
private ProductFeatureRelationService productFeatureRelationService;
|
||||||
|
@Autowired
|
||||||
|
private ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService;
|
||||||
|
@Autowired
|
||||||
|
private SaasFeatureResourceService saasFeatureResourceService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(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)
|
||||||
|
.featureResourceTypes(Lists.newArrayList(FeatureResourceType.MENU.getCode(),
|
||||||
|
FeatureResourceType.PAGE.getCode(),
|
||||||
|
FeatureResourceType.MENU_PARTITION_GROUP.getCode(),
|
||||||
|
FeatureResourceType.GROUP.getCode(),
|
||||||
|
FeatureResourceType.APP_ENTRY.getCode()))
|
||||||
|
.build();
|
||||||
|
List<SaasProductModuleFeatureRelation> productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
log.info("end cached product featureResource handler rocketmq event: {}", event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
eventConsumer.registerHandler(EventTypeEnum.PRODUCT_PERMISSION_CREATED.getEventCode(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ProductSaasFeatureResourceCacheService.ProductFeatureResource> resolveProductFeatureResources(List<SaasProductModuleFeatureRelation> productPermissions) {
|
||||||
|
if (CollectionUtils.isEmpty(productPermissions)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Long, SaasFeatureResourceResp> featureResources = listSaasFeatureResource(productPermissions);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return ProductSaasFeatureResourceCacheService.FeatureResourceDTO.builder()
|
||||||
|
.featureId(featureResource.getId())
|
||||||
|
.featureType(featureResource.getFeatureType())
|
||||||
|
.terminal(featureResource.getTerminal())
|
||||||
|
.uniCode(featureResource.getUniCode())
|
||||||
|
.cooperateType(relation.getDictCode())
|
||||||
|
.build();
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.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();
|
||||||
|
}
|
||||||
|
|
||||||
|
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||||
|
.ids(featureIds)
|
||||||
|
.build();
|
||||||
|
return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream()
|
||||||
|
.collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,154 @@
|
|||||||
|
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.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.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.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 因为菜单树不一定有权限code
|
||||||
|
* 登录时需要查询菜单树,所以把菜单树缓存起来
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class CacheRoleSaasFeatureResourceHandler implements EventHandler, InitializingBean {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private EventConsumer eventConsumer;
|
||||||
|
@Autowired
|
||||||
|
private RoleService roleService;
|
||||||
|
@Autowired
|
||||||
|
private SaasFeatureResourceService saasFeatureResourceService;
|
||||||
|
@Autowired
|
||||||
|
private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEvent(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)
|
||||||
|
.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> rolePermissions = resolveRoleFeatureResource(roles);
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(rolePermissions)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam storeRoleFeatureResourceParam = RoleSaasFeatureResourceCacheService.StoreRoleSaasFeatureResourceParam.builder()
|
||||||
|
.roleSaasFeatureResources(rolePermissions)
|
||||||
|
.build();
|
||||||
|
roleSaasFeatureResourceCacheService.store(storeRoleFeatureResourceParam);
|
||||||
|
log.info("end cached role saasFeatureResource handler rocketmq event: {}", event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
eventConsumer.registerHandler(EventTypeEnum.ROLE_PERMISSION_CREATED.getEventCode(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<RoleSaasFeatureResourceCacheService.RoleFeatureResource> resolveRoleFeatureResource(List<SaasRoleRes> roles) {
|
||||||
|
|
||||||
|
Map<Long, SaasFeatureResourceResp> featureResources = listSaasFeatureResource(roles);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO.builder()
|
||||||
|
.featureId(featureResource.getId())
|
||||||
|
.featureType(featureResource.getFeatureType())
|
||||||
|
.terminal(featureResource.getTerminal())
|
||||||
|
.uniCode(featureResource.getUniCode())
|
||||||
|
.build();
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.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();
|
||||||
|
}
|
||||||
|
|
||||||
|
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||||
|
.ids(featureIds)
|
||||||
|
.build();
|
||||||
|
return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream()
|
||||||
|
.collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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.onEvent(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -22,7 +22,6 @@ import org.springframework.util.CollectionUtils;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -36,6 +36,26 @@ public interface WorkspaceProductService {
|
|||||||
*/
|
*/
|
||||||
List<WorkspaceProductPermission> listWorkspaceProductPermissionCached(ListWorkspaceProductPermissionCacheParam param);
|
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
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@ -155,5 +175,30 @@ public interface WorkspaceProductService {
|
|||||||
*/
|
*/
|
||||||
private Set<Long> workspaceIds;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,6 @@ import cn.axzo.tyr.client.model.enums.IdentityType;
|
|||||||
import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO;
|
import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO;
|
||||||
import cn.axzo.tyr.client.model.req.IdentityAuthReq;
|
import cn.axzo.tyr.client.model.req.IdentityAuthReq;
|
||||||
import cn.axzo.tyr.client.model.req.NavTreeReq;
|
import cn.axzo.tyr.client.model.req.NavTreeReq;
|
||||||
import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq;
|
|
||||||
import cn.axzo.tyr.client.model.req.PagePermissionReq;
|
import cn.axzo.tyr.client.model.req.PagePermissionReq;
|
||||||
import cn.axzo.tyr.client.model.req.PagePermissionResp;
|
import cn.axzo.tyr.client.model.req.PagePermissionResp;
|
||||||
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
|
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
|
||||||
@ -33,7 +32,6 @@ import cn.axzo.tyr.client.model.res.IdentityAuthRes;
|
|||||||
import cn.axzo.tyr.client.model.res.NavTreeResp;
|
import cn.axzo.tyr.client.model.res.NavTreeResp;
|
||||||
import cn.axzo.tyr.client.model.res.ProductFeatureResourceResp;
|
import cn.axzo.tyr.client.model.res.ProductFeatureResourceResp;
|
||||||
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
|
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
|
||||||
import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes;
|
|
||||||
import cn.axzo.tyr.client.model.res.TreePermissionResp;
|
import cn.axzo.tyr.client.model.res.TreePermissionResp;
|
||||||
import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO;
|
import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO;
|
||||||
import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam;
|
import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam;
|
||||||
@ -47,14 +45,13 @@ import cn.axzo.tyr.server.model.WorkspaceFeatureRelation;
|
|||||||
import cn.axzo.tyr.server.repository.dao.ProductModuleDao;
|
import cn.axzo.tyr.server.repository.dao.ProductModuleDao;
|
||||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
|
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
|
||||||
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
|
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
|
||||||
import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation;
|
|
||||||
import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation;
|
|
||||||
import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation;
|
import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation;
|
||||||
import cn.axzo.tyr.server.service.PermissionQueryService;
|
import cn.axzo.tyr.server.service.PermissionQueryService;
|
||||||
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
|
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.RoleService;
|
||||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||||
import cn.axzo.tyr.server.service.SaasPageElementFeatureResourceRelationService;
|
|
||||||
import cn.axzo.tyr.server.service.SaasRoleUserRelationService;
|
import cn.axzo.tyr.server.service.SaasRoleUserRelationService;
|
||||||
import cn.axzo.tyr.server.service.TyrSaasAuthService;
|
import cn.axzo.tyr.server.service.TyrSaasAuthService;
|
||||||
import cn.axzo.tyr.server.service.WorkspaceProductService;
|
import cn.axzo.tyr.server.service.WorkspaceProductService;
|
||||||
@ -117,7 +114,8 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
|
|||||||
private final SaasFeatureResourceService saasFeatureResourceService;
|
private final SaasFeatureResourceService saasFeatureResourceService;
|
||||||
private final SaasRoleUserRelationService saasRoleUserRelationService;
|
private final SaasRoleUserRelationService saasRoleUserRelationService;
|
||||||
private final WorkspaceProductService workspaceProductService;
|
private final WorkspaceProductService workspaceProductService;
|
||||||
private final SaasPageElementFeatureResourceRelationService saasPageElementFeatureResourceRelationService;
|
private final RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService;
|
||||||
|
private final ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService;
|
||||||
|
|
||||||
@Qualifier("authExecutor")
|
@Qualifier("authExecutor")
|
||||||
@Autowired
|
@Autowired
|
||||||
@ -655,39 +653,15 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
|
|||||||
|
|
||||||
private Set<Long> listUserPermissionFeatureIds(TreePermissionReq treePermissionReq) {
|
private Set<Long> listUserPermissionFeatureIds(TreePermissionReq treePermissionReq) {
|
||||||
|
|
||||||
Set<String> featureCodes = resolveFeatureCodes(treePermissionReq);
|
List<SaasRoleUserV2DTO> saasRoleUserV2DTOS = listUserPermission(treePermissionReq);
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(treePermissionReq.getUniCode()) && CollectionUtils.isEmpty(featureCodes)) {
|
List<WorkspaceProductService.WorkspaceProductFeatureSource> workspaceProductFeatureSources = listWorkspaceProducts(treePermissionReq);
|
||||||
return Collections.emptySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//免授权
|
||||||
|
List<Long> authFreeFeatureIds = listNotAuthFeatures(treePermissionReq);
|
||||||
|
|
||||||
IdentityAuthReq identityAuthReq = IdentityAuthReq.builder()
|
//取交集确定权限
|
||||||
.personId(treePermissionReq.getPersonId())
|
return mixFeatureIds(saasRoleUserV2DTOS, workspaceProductFeatureSources, authFreeFeatureIds, treePermissionReq);
|
||||||
.terminal(Lists.newArrayList(treePermissionReq.getTerminal()))
|
|
||||||
.workspaceOusPairs(treePermissionReq.getWorkspaceOUPairs().stream()
|
|
||||||
.map(e -> IdentityAuthReq.WorkspaceOuPair.builder()
|
|
||||||
.ouId(e.getOuId())
|
|
||||||
.workspaceId(e.getWorkspaceId())
|
|
||||||
.build())
|
|
||||||
.collect(Collectors.toList()))
|
|
||||||
.featureCode(featureCodes)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
Set<Integer> featureTypes = Optional.ofNullable(treePermissionReq.getFeatureResourceTypes())
|
|
||||||
.map(e -> e.stream()
|
|
||||||
.map(FeatureResourceType::getCode)
|
|
||||||
.collect(Collectors.toSet()))
|
|
||||||
.orElse(null);
|
|
||||||
|
|
||||||
return saasAuthService.findIdentityAuthMix(identityAuthReq).getPermissions().stream()
|
|
||||||
.map(IdentityAuthRes.WorkspacePermission::getPermissionPoint)
|
|
||||||
.flatMap(Collection::stream)
|
|
||||||
.filter(e -> CollectionUtils.isEmpty(featureTypes)
|
|
||||||
|| featureTypes.contains(e.getFeatureType()))
|
|
||||||
.map(IdentityAuthRes.PermissionPoint::getFeatureId)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Long> listNotAuthFeatures(TreePermissionReq treePermissionReq) {
|
private List<Long> listNotAuthFeatures(TreePermissionReq treePermissionReq) {
|
||||||
@ -700,22 +674,24 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<WorkspaceProductService.WorkspaceProductPermission> listWorkspaceProducts(TreePermissionReq treePermissionReq,
|
private List<WorkspaceProductService.WorkspaceProductFeatureSource> listWorkspaceProducts(TreePermissionReq treePermissionReq) {
|
||||||
Set<String> featureCodes) {
|
|
||||||
//查询租户产品权限点
|
//查询租户产品权限点
|
||||||
Set<Long> workspaceIds = treePermissionReq.getWorkspaceOUPairs().stream()
|
Set<Long> workspaceIds = treePermissionReq.getWorkspaceOUPairs().stream()
|
||||||
.map(WorkspaceOUPair::getWorkspaceId)
|
.map(WorkspaceOUPair::getWorkspaceId)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
WorkspaceProductService.ListWorkspaceProductPermissionCacheParam listWorkspaceProductPermissionCacheParam = WorkspaceProductService.ListWorkspaceProductPermissionCacheParam
|
WorkspaceProductService.ListWorkspaceProductFeatureSourceCacheParam listWorkspaceProductFeatureSourceCacheParam = WorkspaceProductService.ListWorkspaceProductFeatureSourceCacheParam
|
||||||
.builder()
|
.builder()
|
||||||
.workspaceIds(workspaceIds)
|
.workspaceIds(workspaceIds)
|
||||||
.featureCodes(featureCodes)
|
.uniCodes(Optional.ofNullable(treePermissionReq.getUniCode())
|
||||||
|
.map(Sets::newHashSet)
|
||||||
|
.orElseGet(Sets::newHashSet))
|
||||||
.build();
|
.build();
|
||||||
return workspaceProductService.listWorkspaceProductPermissionCached(listWorkspaceProductPermissionCacheParam);
|
|
||||||
|
return workspaceProductService.listWorkspaceProductFeatureResourceCached(listWorkspaceProductFeatureSourceCacheParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SaasRoleUserV2DTO> listUserPermission(TreePermissionReq treePermissionReq, Set<String> featureCodes) {
|
private List<SaasRoleUserV2DTO> listUserPermission(TreePermissionReq treePermissionReq) {
|
||||||
List<ListRoleUserRelationParam.WorkspaceOuPair> workspaceOuPairs = treePermissionReq.getWorkspaceOUPairs().stream()
|
List<ListRoleUserRelationParam.WorkspaceOuPair> workspaceOuPairs = treePermissionReq.getWorkspaceOUPairs().stream()
|
||||||
.map(e -> ListRoleUserRelationParam.WorkspaceOuPair.builder()
|
.map(e -> ListRoleUserRelationParam.WorkspaceOuPair.builder()
|
||||||
.workspaceId(e.getWorkspaceId())
|
.workspaceId(e.getWorkspaceId())
|
||||||
@ -727,82 +703,130 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
|
|||||||
.personId(treePermissionReq.getPersonId())
|
.personId(treePermissionReq.getPersonId())
|
||||||
.workspaceOuPairs(Lists.newArrayList(workspaceOuPairs))
|
.workspaceOuPairs(Lists.newArrayList(workspaceOuPairs))
|
||||||
.needRole(true)
|
.needRole(true)
|
||||||
.terminal(treePermissionReq.getTerminal())
|
|
||||||
.build();
|
.build();
|
||||||
return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream()
|
return saasRoleUserRelationService.listV2(listRoleUserRelationParam).stream()
|
||||||
.filter(e -> e.getSaasRole() != null)
|
.filter(e -> e.getSaasRole() != null)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> resolveFeatureCodes(TreePermissionReq treePermissionReq) {
|
private Map<Long, List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO>> listRoleFeatureResource(List<SaasRoleUserV2DTO> saasRoleUsers,
|
||||||
if (StringUtils.isBlank(treePermissionReq.getUniCode())) {
|
TreePermissionReq treePermissionReq) {
|
||||||
return Collections.emptySet();
|
|
||||||
|
Set<Long> roleIds = saasRoleUsers.stream()
|
||||||
|
.map(SaasRoleUserV2DTO::getRoleId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(roleIds)) {
|
||||||
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
PageElementFeatureResourceRelationReq pageElementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq.builder()
|
RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam listRoleSaasFeatureResourceParam = RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam.builder()
|
||||||
.featureResourceUniCodes(Sets.newHashSet(treePermissionReq.getUniCode()))
|
.roleIds(roleIds)
|
||||||
|
.uniCodes(Optional.ofNullable(treePermissionReq.getUniCode())
|
||||||
|
.map(Sets::newHashSet)
|
||||||
|
.orElseGet(Sets::newHashSet))
|
||||||
.build();
|
.build();
|
||||||
return saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq)
|
return roleSaasFeatureResourceCacheService.list(listRoleSaasFeatureResourceParam);
|
||||||
.stream()
|
|
||||||
.map(SaasPageElementFeatureResourceRelation::getPageElementCode)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<Long> mixFeatureIds(List<SaasRoleUserV2DTO> saasRoleUsers,
|
private Set<Long> mixFeatureIds(List<SaasRoleUserV2DTO> saasRoleUsers,
|
||||||
List<WorkspaceProductService.WorkspaceProduct> workspaceProducts,
|
List<WorkspaceProductService.WorkspaceProductFeatureSource> workspaceProducts,
|
||||||
List<Long> authFreeFeatureIds) {
|
List<Long> authFreeFeatureIds,
|
||||||
|
TreePermissionReq treePermissionReq) {
|
||||||
|
|
||||||
Map<Long, WorkspaceProductService.WorkspaceProduct> workspaceProductMap = workspaceProducts.stream()
|
Map<Long, List<WorkspaceProductService.ProductFeatureSource>> workspaceProductMap = workspaceProducts.stream()
|
||||||
.collect(Collectors.toMap(WorkspaceProductService.WorkspaceProduct::getWorkspaceId, Function.identity()));
|
.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()
|
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 -> {
|
.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();
|
SaasRoleUserV2DTO.SaasRole saasRole = roleUser.getSaasRole();
|
||||||
if (RoleTypeEnum.isAdmin(saasRole.getRoleType())) {
|
|
||||||
return resolveAdminRole(workspaceProduct, saasRole);
|
Set<Long> adminFeatureIds = resolveAdminRole(productFeatureSources, saasRole);
|
||||||
}
|
Set<Long> notAuthFeatureIds = resolveNotAuthFeatureIds(productFeatureSources, authFreeFeatureIds);
|
||||||
return resolveNormalRole(workspaceProduct, saasRole, 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)
|
.flatMap(Collection::stream)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Long> resolveAdminRole(WorkspaceProductService.WorkspaceProduct workspaceProduct,
|
private Set<Long> resolveAdminRole(List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> productFeatureSources,
|
||||||
SaasRoleUserV2DTO.SaasRole saasRole) {
|
SaasRoleUserV2DTO.SaasRole saasRole) {
|
||||||
|
|
||||||
|
if (!RoleTypeEnum.isAdmin(saasRole.getRoleType())) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
//超管和管理员 直接取和角色类型匹配的租户产品权限
|
//超管和管理员 直接取和角色类型匹配的租户产品权限
|
||||||
return workspaceProduct.getSaasProductModuleFeatureRelations().stream()
|
return productFeatureSources.stream()
|
||||||
.filter(f -> Objects.equals(f.getDictCode(), saasRole.getProductUnitType().toString())
|
.filter(e -> Objects.equals(e.getCooperateType(), saasRole.getProductUnitType().toString())
|
||||||
|| !NumberUtil.isPositiveNumber(saasRole.getProductUnitType()))
|
|| !NumberUtil.isPositiveNumber(saasRole.getProductUnitType()))
|
||||||
.map(SaasProductModuleFeatureRelation::getFeatureId)
|
.map(ProductSaasFeatureResourceCacheService.FeatureResourceDTO::getFeatureId)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Long> resolveNormalRole(WorkspaceProductService.WorkspaceProduct workspaceProduct,
|
private Set<Long> resolveNormalRole(List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> workspaceProduct,
|
||||||
SaasRoleUserV2DTO.SaasRole saasRole,
|
SaasRoleUserV2DTO.SaasRole saasRole,
|
||||||
List<Long> authFreeFeatureIds) {
|
List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO> roleFeatureResources) {
|
||||||
//普通角色:角色同类型的租户产品权限已分配 且角色上已分配 + 免授权
|
|
||||||
Set<Long> roleFeatureIds = Optional.ofNullable(saasRole.getPermissionRelations())
|
|
||||||
.map(e -> e.stream()
|
|
||||||
.map(SaasPermissionRelationRes::getFeatureId)
|
|
||||||
.collect(Collectors.toSet()))
|
|
||||||
.orElseGet(Collections::emptySet);
|
|
||||||
|
|
||||||
return workspaceProduct.getSaasProductModuleFeatureRelations().stream()
|
if (CollectionUtils.isEmpty(roleFeatureResources)) {
|
||||||
.filter(f -> Objects.equals(f.getDictCode(), saasRole.getProductUnitType().toString())
|
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()))
|
|| !NumberUtil.isPositiveNumber(saasRole.getProductUnitType()))
|
||||||
.map(SaasProductModuleFeatureRelation::getFeatureId)
|
.map(ProductSaasFeatureResourceCacheService.FeatureResourceDTO::getFeatureId)
|
||||||
.filter(id -> roleFeatureIds.contains(id) || authFreeFeatureIds.contains(id))
|
.filter(roleFeatureIds::contains)
|
||||||
.collect(Collectors.toList());
|
.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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,174 @@
|
|||||||
|
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())));
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,180 @@
|
|||||||
|
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())));
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,6 +11,7 @@ import cn.axzo.tyr.server.repository.entity.ProductFeatureQuery;
|
|||||||
import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation;
|
import cn.axzo.tyr.server.repository.entity.SaasProductModuleFeatureRelation;
|
||||||
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
|
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
|
||||||
import cn.axzo.tyr.server.service.ProductPermissionCacheService;
|
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.service.WorkspaceProductService;
|
||||||
import cn.axzo.tyr.server.utils.RpcInternalUtil;
|
import cn.axzo.tyr.server.utils.RpcInternalUtil;
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
@ -56,6 +57,8 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
|
|||||||
private StringRedisTemplate redisTemplate;
|
private StringRedisTemplate redisTemplate;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ProductPermissionCacheService productPermissionCacheService;
|
private ProductPermissionCacheService productPermissionCacheService;
|
||||||
|
@Autowired
|
||||||
|
private ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService;
|
||||||
|
|
||||||
|
|
||||||
/** 授权缓存过期时间 **/
|
/** 授权缓存过期时间 **/
|
||||||
@ -351,4 +354,46 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
|
|||||||
|
|
||||||
return workspaceProducts;
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user