Merge branch 'master' into feature/REQ-2750
# Conflicts: # tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java # tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRolePermissionHandler.java # tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/CacheRoleSaasFeatureResourceHandler.java # tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRoleFeatureResourceJob.java # tyr-server/src/main/java/cn/axzo/tyr/server/job/CacheRolePermissionJob.java # tyr-server/src/main/java/cn/axzo/tyr/server/service/RoleService.java # tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RolePermissionCacheServiceImpl.java # tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/RoleSaasFeatureResourceCacheServiceImpl.java
This commit is contained in:
commit
6235f4a801
@ -0,0 +1,16 @@
|
||||
package cn.axzo.tyr.client.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author likunpeng
|
||||
* @version 1.0
|
||||
* @date 2024/9/5
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum PageElementAppTypeEnum {
|
||||
|
||||
PC,H5,APP;
|
||||
}
|
||||
@ -93,6 +93,26 @@ public enum PermissionRelationOperateLogSceneEnum {
|
||||
*/
|
||||
OMS_API_SYNC("OMS_API_SYNC", "oms后台同步API"),
|
||||
|
||||
/**
|
||||
* oms新增、编辑元素类型
|
||||
*/
|
||||
OMS_UPSERT_PAGE_ELEMENT_CATEGORY("OMS_UPSERT_PAGE_ELEMENT_CATEGORY", "oms新增、编辑元素类型"),
|
||||
|
||||
/**
|
||||
* oms删除元素类型
|
||||
*/
|
||||
OMS_DELETE_PAGE_ELEMENT_CATEGORY("OMS_DELETE_PAGE_ELEMENT_CATEGORY", "oms删除元素类型"),
|
||||
|
||||
/**
|
||||
* oms新增、编辑页面元素
|
||||
*/
|
||||
OMS_UPSERT_PAGE_ELEMENT("OMS_UPSERT_PAGE_ELEMENT", "oms新增、编辑页面元素"),
|
||||
|
||||
/**
|
||||
* oms删除页面元素
|
||||
*/
|
||||
OMS_DELETE_PAGE_ELEMENT("OMS_DELETE_PAGE_ELEMENT", "oms删除页面元素"),
|
||||
|
||||
;
|
||||
|
||||
@EnumValue
|
||||
|
||||
@ -5,6 +5,7 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@ -56,4 +57,10 @@ public enum RoleTypeEnum {
|
||||
return Objects.equals(this.value, value);
|
||||
}
|
||||
|
||||
public static List<String> listAdmin() {
|
||||
return Arrays.stream(values())
|
||||
.filter(RoleTypeEnum::isAdminRole)
|
||||
.map(RoleTypeEnum::getValue)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
package cn.axzo.tyr.client.feign;
|
||||
|
||||
import cn.axzo.framework.domain.page.Page;
|
||||
import cn.axzo.framework.domain.web.result.ApiPageResult;
|
||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||
import cn.axzo.tyr.client.model.req.*;
|
||||
import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp;
|
||||
import cn.axzo.tyr.client.model.res.PageElementResp;
|
||||
import cn.axzo.tyr.client.model.res.*;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@ -37,7 +35,7 @@ public interface PageElementApi {
|
||||
|
||||
/** 分页查询页面资源 **/
|
||||
@PostMapping("/api/pageElement/page")
|
||||
ApiPageResult<PageElementResp> page(@RequestBody @Valid PageQueryElementReq req);
|
||||
ApiPageResult<PageElementCategoryAndElementResp> page(@RequestBody @Valid PageQueryElementReq req);
|
||||
|
||||
/** 根据用户传入的页面code,查询用户有权限的元素code **/
|
||||
@PostMapping("/api/pageElement/getUserHasPermissionPageElement")
|
||||
@ -45,4 +43,36 @@ public interface PageElementApi {
|
||||
|
||||
@PostMapping("/api/pageElement/list")
|
||||
ApiResult<List<PageElementResp>> list(PageElementReq param);
|
||||
|
||||
/** 查询页面元素类型(按端分组) **/
|
||||
@PostMapping("/api/pageElementCategory/list")
|
||||
ApiResult<List<ListPageElementCategoryResp>> listPageElementCategory();
|
||||
|
||||
/** 新增、编辑页面元素类型 **/
|
||||
@PostMapping("/api/pageElementCategory/saveOrUpdate")
|
||||
ApiResult<Long> saveOrUpdateCategory(@RequestBody @Valid SaveOrUpdatePageElementCategoryReq req);
|
||||
|
||||
/** 删除页面元素类型 **/
|
||||
@PostMapping("/api/pageElementCategory/delete")
|
||||
ApiResult<Void> deleteCategory(@RequestBody @Valid DeletePageElementCategoryReq req);
|
||||
|
||||
/** 分页查询页面资源V2 **/
|
||||
@PostMapping("/api/pageElement/pageV2")
|
||||
ApiPageResult<PageElementResp> pageV2(@RequestBody @Valid PageQueryElementV2Req req);
|
||||
|
||||
/** 新增、编辑页面元素 **/
|
||||
@PostMapping("/api/pageElement/saveOrUpdate")
|
||||
ApiResult<Void> saveOrUpdate(@RequestBody @Valid SaveOrUpdatePageElementReq req);
|
||||
|
||||
/** 删除页面元素 **/
|
||||
@PostMapping("/api/pageElement/delete")
|
||||
ApiResult<Void> delete(@RequestBody @Valid DeletePageElementReq req);
|
||||
|
||||
/** 查询页面元素关联关系 **/
|
||||
@PostMapping("/api/pageElement/getFeatureResourceRelations")
|
||||
ApiResult<List<PageElementRelationFeatureResourceResp>> getFeatureResourceRelations(@RequestBody @Valid IdReq req);
|
||||
|
||||
/** 查询页面元素关联关系 **/
|
||||
@PostMapping("/api/pageElement/importData")
|
||||
ApiResult<Void> importData(@RequestBody @Valid List<PageElementImportDataReq> req);
|
||||
}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
package cn.axzo.tyr.client.model.req;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author likunpeng
|
||||
* @version 1.0
|
||||
* @date 2024/8/21
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DeletePageElementCategoryReq {
|
||||
|
||||
@NotNull(message = "ID不能为空")
|
||||
@Min(value = 1, message = "ID有误")
|
||||
private Long id;
|
||||
|
||||
/** 操作人personId **/
|
||||
private Long operatorId;
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package cn.axzo.tyr.client.model.req;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author likunpeng
|
||||
* @version 1.0
|
||||
* @date 2024/8/21
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class DeletePageElementReq {
|
||||
|
||||
@NotNull(message = "ID不能为空")
|
||||
@Min(value = 1, message = "ID有误")
|
||||
private Long id;
|
||||
|
||||
/** 操作人personId **/
|
||||
private Long operatorId;
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package cn.axzo.tyr.client.model.req;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author likunpeng
|
||||
* @version 1.0
|
||||
* @date 2024/8/21
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IdReq {
|
||||
|
||||
@NotNull(message = "ID不能为空")
|
||||
@Min(value = 1, message = "ID有误")
|
||||
private Long id;
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
package cn.axzo.tyr.client.model.req;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author likunpeng
|
||||
* @version 1.0
|
||||
* @date 2024/8/29
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PageElementImportDataReq implements Serializable {
|
||||
|
||||
/**
|
||||
* 端
|
||||
*/
|
||||
@NotBlank(message = "端信息不能为空")
|
||||
private String terminal;
|
||||
|
||||
/**
|
||||
* 元素分类
|
||||
*/
|
||||
@NotBlank(message = "元素分类不能为空")
|
||||
private String itemCode;
|
||||
|
||||
/**
|
||||
* 元素组编码
|
||||
*/
|
||||
@NotBlank(message = "元素组编码不能为空")
|
||||
private String groupCode;
|
||||
|
||||
/**
|
||||
* 元素编码
|
||||
*/
|
||||
@NotBlank(message = "元素编码不能为空")
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 元素名称
|
||||
*/
|
||||
@NotBlank(message = "元素名称不能为空")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 元素类型(PAGE:页面,COMPONENT:页面里的组件)
|
||||
*/
|
||||
@NotBlank(message = "元素类型不能为空")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 元素资源类型:APP、H5、PC
|
||||
*/
|
||||
@NotBlank(message = "元素资源类型不能为空")
|
||||
private String appType;
|
||||
|
||||
/**
|
||||
* H5的appId
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* 元素支持的最低版本号
|
||||
*/
|
||||
private Integer version;
|
||||
|
||||
/**
|
||||
* 路由地址
|
||||
*/
|
||||
private String linkUrl;
|
||||
|
||||
/** ios跳转地址 **/
|
||||
private String iosRouterUrl;
|
||||
|
||||
/** android跳转地址 **/
|
||||
private String androidRouterUrl;
|
||||
|
||||
private Long operatorId;
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
package cn.axzo.tyr.client.model.req;
|
||||
|
||||
import cn.axzo.framework.domain.page.PageResp;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author likunpeng
|
||||
* @version 1.0
|
||||
* @date 2024/6/14
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PageQueryElementV2Req {
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 业务编码
|
||||
*/
|
||||
private String itemCode;
|
||||
|
||||
/**
|
||||
* 端
|
||||
*/
|
||||
private String terminal;
|
||||
|
||||
/**
|
||||
* 页面元素组件类型
|
||||
*/
|
||||
private List<String> elementTypes;
|
||||
|
||||
/**
|
||||
* 页面元素名称
|
||||
*/
|
||||
private String pageElementCodeOrName;
|
||||
|
||||
/**
|
||||
* 页面元素名称
|
||||
*/
|
||||
private String pageElementGroupCodeOrName;
|
||||
|
||||
/**
|
||||
* 页码
|
||||
*/
|
||||
@Builder.Default
|
||||
private Long page = 1L;
|
||||
|
||||
/**
|
||||
* 每页大小
|
||||
*/
|
||||
@Builder.Default
|
||||
private Long pageSize = 20L;
|
||||
|
||||
public PageResp toEmpty() {
|
||||
return PageResp.builder()
|
||||
.page(this.getPage())
|
||||
.pageSize(this.getPageSize())
|
||||
.list(Collections.emptyList())
|
||||
.totalCount(0L)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package cn.axzo.tyr.client.model.req;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author likunpeng
|
||||
* @version 1.0
|
||||
* @date 2024/8/21
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SaveOrUpdatePageElementCategoryReq {
|
||||
|
||||
private Long id;
|
||||
|
||||
/** 项目编码 **/
|
||||
private String itemCode;
|
||||
|
||||
/** 项目名称 **/
|
||||
@NotBlank(message = "项目名称不能为空")
|
||||
private String itemName;
|
||||
|
||||
/** 登录端 **/
|
||||
@NotBlank(message = "所属端不能为空")
|
||||
private String terminal;
|
||||
|
||||
/** 操作人personId **/
|
||||
private Long operatorId;
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
package cn.axzo.tyr.client.model.req;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author likunpeng
|
||||
* @version 1.0
|
||||
* @date 2024/8/21
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SaveOrUpdatePageElementReq {
|
||||
|
||||
private Long id;
|
||||
|
||||
/** 项目编码 **/
|
||||
private String itemCode;
|
||||
|
||||
/** 分组ID **/
|
||||
private String groupCode;
|
||||
|
||||
/** 页面元素类型:PAGE/COMPONENT **/
|
||||
@NotBlank(message = "页面元素类型不能为空")
|
||||
private String type;
|
||||
|
||||
/** 项目编码 **/
|
||||
@NotBlank(message = "项目编码不能为空")
|
||||
private String code;
|
||||
|
||||
/** 元素名称 **/
|
||||
@NotBlank(message = "元素名称不能为空")
|
||||
private String name;
|
||||
|
||||
/** app类型(APP:原生,H5:h5页面, PC:web页面) **/
|
||||
private String appType;
|
||||
|
||||
/** H5的appId **/
|
||||
private String appId;
|
||||
|
||||
/** pc/h5路由地址 **/
|
||||
private String linkUrl;
|
||||
|
||||
/** ios跳转地址 **/
|
||||
private String iosRouterUrl;
|
||||
|
||||
/** android跳转地址 **/
|
||||
private String androidRouterUrl;
|
||||
|
||||
/** 版本号 **/
|
||||
private Integer version;
|
||||
|
||||
/** 操作人personId **/
|
||||
private Long operatorId;
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package cn.axzo.tyr.client.model.res;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author likunpeng
|
||||
* @version 1.0
|
||||
* @date 2024/8/20
|
||||
*/
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ListPageElementCategoryResp {
|
||||
|
||||
/** 端 **/
|
||||
private String terminal;
|
||||
/** 页面元素类型列表 **/
|
||||
private List<PageElementCategoryDTO> pageElementCategories;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class PageElementCategoryDTO {
|
||||
/** 主键 **/
|
||||
private Long id;
|
||||
/** 项目编码 **/
|
||||
private String itemCode;
|
||||
/** 项目名称 **/
|
||||
private String itemName;
|
||||
/** 端 **/
|
||||
private String terminal;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package cn.axzo.tyr.client.model.res;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author likunpeng
|
||||
* @version 1.0
|
||||
* @date 2024/8/27
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PageElementCategoryAndElementResp {
|
||||
/** 项目编码 **/
|
||||
private String itemCode;
|
||||
/** 项目名称 **/
|
||||
private String itemName;
|
||||
/** 元素列表 **/
|
||||
private List<PageElementResp> pageElements;
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
package cn.axzo.tyr.client.model.res;
|
||||
|
||||
import cn.axzo.basics.common.model.IBaseTree;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author likunpeng
|
||||
* @date 2024/8/30
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PageElementRelationFeatureResourceResp implements IBaseTree<PageElementRelationFeatureResourceResp, Long> {
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 上级资源ID
|
||||
*/
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 资源编码-权限码
|
||||
*/
|
||||
private String uniCode;
|
||||
|
||||
/**
|
||||
* 资源名称
|
||||
*/
|
||||
private String featureName;
|
||||
|
||||
/**
|
||||
* 资源类型1-菜单 2-页面 3-应用入口 4-组件 5-root 6-分组
|
||||
*/
|
||||
private Integer featureType;
|
||||
|
||||
/**
|
||||
* 子节点
|
||||
*/
|
||||
private List<PageElementRelationFeatureResourceResp> children;
|
||||
|
||||
/**
|
||||
* 是否关联
|
||||
*/
|
||||
private Boolean hasRelation;
|
||||
|
||||
/**
|
||||
* 1:路由页面
|
||||
*/
|
||||
private Integer relationType;
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public Long getNodeCode() {
|
||||
return this.getId();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public Long getParentNodeCode() {
|
||||
return this.getParentId();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public List<PageElementRelationFeatureResourceResp> getNodeChildren() {
|
||||
return this.children;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNodeChildren(List<PageElementRelationFeatureResourceResp> nodeChildren) {
|
||||
this.children = nodeChildren;
|
||||
}
|
||||
}
|
||||
@ -32,6 +32,11 @@ public class PageElementResp {
|
||||
*/
|
||||
private String groupCode;
|
||||
|
||||
/**
|
||||
* 元素的组编码
|
||||
*/
|
||||
private String groupName;
|
||||
|
||||
/**
|
||||
* 元素编码
|
||||
*/
|
||||
@ -67,7 +72,10 @@ public class PageElementResp {
|
||||
*/
|
||||
private Boolean selected;
|
||||
|
||||
/** 业务编码 **/
|
||||
private String itemCode;
|
||||
/** 业务名称 **/
|
||||
private String itemName;
|
||||
|
||||
private String linkExt;
|
||||
|
||||
@ -81,6 +89,11 @@ public class PageElementResp {
|
||||
*/
|
||||
private List<SaasFeatureResourceResp> featureResources;
|
||||
|
||||
/** ios挑战地址 **/
|
||||
private String iosRouterUrl;
|
||||
|
||||
/** android挑战地址 **/
|
||||
private String androidRouterUrl;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
|
||||
@ -9,6 +9,7 @@ import cn.axzo.framework.rocketmq.RocketMQEventProducer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.rocketmq.common.message.MessageExt;
|
||||
import org.apache.rocketmq.spring.annotation.ConsumeMode;
|
||||
import org.apache.rocketmq.spring.annotation.MessageModel;
|
||||
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
|
||||
import org.apache.rocketmq.spring.core.RocketMQListener;
|
||||
import org.apache.rocketmq.spring.core.RocketMQTemplate;
|
||||
@ -69,7 +70,7 @@ public class RocketMQEventConfiguration {
|
||||
@Component
|
||||
@RocketMQMessageListener(topic = "topic_thrones_${spring.profiles.active}",
|
||||
consumerGroup = "GID_topic_thrones_${spring.application.name}_${spring.profiles.active}",
|
||||
consumeMode = ConsumeMode.ORDERLY,
|
||||
messageModel = MessageModel.BROADCASTING,
|
||||
nameServer = "${rocketmq.name-server}"
|
||||
)
|
||||
public static class ThronesListener extends BaseListener implements RocketMQListener<MessageExt> {
|
||||
@ -88,7 +89,7 @@ public class RocketMQEventConfiguration {
|
||||
@Component
|
||||
@RocketMQMessageListener(topic = "topic_tyr_${spring.profiles.active}",
|
||||
consumerGroup = "GID_topic_tyr_${spring.application.name}_${spring.profiles.active}",
|
||||
consumeMode = ConsumeMode.ORDERLY,
|
||||
messageModel = MessageModel.BROADCASTING,
|
||||
nameServer = "${rocketmq.name-server}"
|
||||
)
|
||||
public static class TyrListener extends BaseListener implements RocketMQListener<MessageExt> {
|
||||
@ -107,7 +108,7 @@ public class RocketMQEventConfiguration {
|
||||
@Component
|
||||
@RocketMQMessageListener(topic = "topic_apisix_plat_${spring.profiles.active}",
|
||||
consumerGroup = "GID_topic_apisix_plat_${spring.application.name}_${spring.profiles.active}",
|
||||
consumeMode = ConsumeMode.ORDERLY,
|
||||
messageModel = MessageModel.BROADCASTING,
|
||||
nameServer = "${rocketmq.name-server}"
|
||||
)
|
||||
public static class ApiSixPlatListener extends BaseListener implements RocketMQListener<MessageExt> {
|
||||
|
||||
@ -184,6 +184,8 @@ public class PrivateController {
|
||||
private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService;
|
||||
@Autowired
|
||||
private SendDingTalkHandler sendDingTalkHandler;
|
||||
@Autowired
|
||||
private ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService;
|
||||
|
||||
/**
|
||||
* 统一层级的roleGroup按照id升序,sort从1递增
|
||||
@ -367,22 +369,17 @@ public class PrivateController {
|
||||
});
|
||||
}
|
||||
|
||||
@PostMapping("/api/private/productPermission/add")
|
||||
public Object addProductPermission(@Validated @RequestBody ProductPermissionCacheService.StoreProductPermissionParam request) {
|
||||
productPermissionCacheService.store(request);
|
||||
@PostMapping("/api/private/productPermission/refresh")
|
||||
public Object addProductPermission(@Validated @RequestBody ProductPermissionCacheService.RefreshProductPermissionCacheParam request) {
|
||||
productPermissionCacheService.refreshCache(request);
|
||||
return "ok";
|
||||
}
|
||||
|
||||
@PostMapping("/api/private/productPermission/get")
|
||||
@PostMapping("/api/private/productPermission/list")
|
||||
public Object getProductPermission(@Validated @RequestBody ProductPermissionCacheService.ListProductPermissionParam request) {
|
||||
return productPermissionCacheService.list(request);
|
||||
}
|
||||
|
||||
@PostMapping("/api/private/productPermission/has")
|
||||
public Object hasProductIds(@Validated @RequestBody ProductPermissionCacheService.HasProductPermissionParam request) {
|
||||
return productPermissionCacheService.hasProductIds(request);
|
||||
}
|
||||
|
||||
@PostMapping("/api/private/permission/auth")
|
||||
public Object authPermission(@Validated @RequestBody PermissionCheckReq request) {
|
||||
return tyrSaasAuthService.authPermission(request);
|
||||
@ -638,6 +635,12 @@ public class PrivateController {
|
||||
return featureCodeUtil.resolveFeatureCode(request.getFeatureCodes());
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存产品权限
|
||||
* @param request
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PostMapping("/api/private/productPermission/store")
|
||||
public Object storeProductPermission(@RequestBody ProductSearchListReq request) throws Exception {
|
||||
cacheProductPermissionJob.execute(JSON.toJSONString(request));
|
||||
@ -670,104 +673,109 @@ public class PrivateController {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
@PostMapping("/api/private/role/insert")
|
||||
public Object insertRole(@RequestPart("file") MultipartFile file) throws IOException {
|
||||
|
||||
List<CreateRoleParam> importExcels = EasyExcel.read(file.getInputStream())
|
||||
.head(CreateRoleParam.class)
|
||||
.sheet()
|
||||
.doReadSync();
|
||||
|
||||
importExcels = importExcels.stream()
|
||||
.filter(e -> Objects.equals(e.getType(), "c"))
|
||||
.filter(e -> Objects.nonNull(e.getGroupId()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Set<Long> roleGroupIds = importExcels.stream()
|
||||
.map(CreateRoleParam::getGroupId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Map<Long, SaasRoleGroup> saasRoleGroups = saasRoleGroupDao.listByIds(roleGroupIds).stream()
|
||||
.collect(Collectors.toMap(SaasRoleGroup::getId, Function.identity()));
|
||||
|
||||
importExcels.forEach(e -> {
|
||||
|
||||
SaasRoleGroup saasRoleGroup = saasRoleGroups.get(e.getGroupId());
|
||||
if (saasRoleGroup == null) {
|
||||
log.info("not found saasRoleGroup,{}", e.getGroupId());
|
||||
return;
|
||||
}
|
||||
|
||||
SaveOrUpdateRoleVO.GroupInfoVO groupInfoVO = new SaveOrUpdateRoleVO.GroupInfoVO();
|
||||
groupInfoVO.setId(e.getGroupId());
|
||||
groupInfoVO.setWorkspaceTypeCode(saasRoleGroup.getWorkspaceTypeCode());
|
||||
SaveOrUpdateRoleVO saveOrUpdateRoleVO = SaveOrUpdateRoleVO.builder()
|
||||
.name(e.getRoleName())
|
||||
.roleType("init")
|
||||
.workspaceId(-1L)
|
||||
.ownerOuId(-1L)
|
||||
.operatorId(2007696L)
|
||||
.operatorName("李龙")
|
||||
.groupTree(Lists.newArrayList(groupInfoVO))
|
||||
.permissionGroupName("通用权限")
|
||||
.permissionGroupType("feature")
|
||||
.roleCode(e.getRoleCode())
|
||||
.isDisplay(true)
|
||||
.enabled(true)
|
||||
.build();
|
||||
try {
|
||||
roleService.saveOrUpdate(saveOrUpdateRoleVO);
|
||||
} catch (Exception ex) {
|
||||
log.info("roleName {},ex:", e.getRoleName(), ex);
|
||||
}
|
||||
});
|
||||
return "ok";
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存角色权限
|
||||
* @param request
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PostMapping("/api/private/rolePermission/store")
|
||||
public Object storeRolePermission(@RequestBody PageRoleReq request) throws Exception {
|
||||
public Object storeRolePermission(@RequestBody RoleService.ListSaasRoleParam request) throws Exception {
|
||||
cacheRolePermissionJob.execute(JSON.toJSONString(request));
|
||||
return "ok";
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存菜单
|
||||
* @param request
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PostMapping("/api/private/saasFeature/store")
|
||||
public Object storeSaasFeature(@RequestBody StoreFeatureParam request) throws Exception {
|
||||
cacheSaasFeatureJob.execute(JSON.toJSONString(request));
|
||||
return "ok";
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存产品菜单
|
||||
* @param request
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PostMapping("/api/private/productSaasFeature/store")
|
||||
public Object storeProductSaasFeature(@RequestBody ProductSearchListReq request) throws Exception {
|
||||
cacheProductFeatureResourceJob.execute(JSON.toJSONString(request));
|
||||
return "ok";
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存角色菜单
|
||||
* @param request
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PostMapping("/api/private/roleSaasFeature/store")
|
||||
public Object storeRoleSaasFeature(@RequestBody PageRoleReq request) throws Exception {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询角色权限
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/private/rolePermissionCache/list")
|
||||
public Object rolePermissionCache(@RequestBody RolePermissionCacheService.ListRolePermissionParam request) {
|
||||
return rolePermissionCacheService.list(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询产品权限
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/private/productPermissionCached/list")
|
||||
public Object productPermissionCached(@RequestBody ProductPermissionCacheService.ListProductPermissionParam request) {
|
||||
return productPermissionCacheService.list(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询角色菜单
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/private/roleSaasFeatureResourceCache/list")
|
||||
public Object listRoleSaasFeatureResourceCache(@RequestBody RoleSaasFeatureResourceCacheService.ListRoleSaasFeatureResourceParam request) {
|
||||
return roleSaasFeatureResourceCacheService.list(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询产品菜单
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/private/productFeatureResourceCached/list")
|
||||
public Object listProductSaasFeatureResourceCache(@RequestBody ProductSaasFeatureResourceCacheService.ListProductFeatureResourceParam request) {
|
||||
return productSaasFeatureResourceCacheService.list(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询菜单树
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/private/featureResourceCache/list")
|
||||
public Object listSaasFeatureResourceCache(@RequestBody SaasFeatureResourceService.ListSaasFeatureResourceCache request) {
|
||||
return saasFeatureResourceService.listCache(request);
|
||||
}
|
||||
|
||||
@PostMapping("/api/private/saasPageElement/refreshCmpFeatureResourceLinkUrl")
|
||||
public ApiResult refreshCmpFeatureResourceLinkUrl(@RequestBody RefreshFeatureResourceLinkUrlParam request) {
|
||||
Long startId = 0L;
|
||||
|
||||
@ -10,6 +10,7 @@ import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode;
|
||||
import cn.axzo.tyr.server.service.FeatureResourceSyncService;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@ -52,7 +53,7 @@ public class FeatureResourceController implements FeatureResourceApi {
|
||||
|
||||
@Override
|
||||
public ApiResult<Long> saveMenu(FeatureResourceTreeSaveReq req) {
|
||||
log.info("save feature resource req : " + req.toString());
|
||||
log.info("save feature resource req : " + JSON.toJSONString(req));
|
||||
Long featureId = featureResourceService.saveOrUpdateMenu(req);
|
||||
log.info("save feature resource resp : " + featureId.toString());
|
||||
return ApiResult.ok(featureId);
|
||||
|
||||
@ -3,14 +3,9 @@ package cn.axzo.tyr.server.controller.permission;
|
||||
import cn.axzo.framework.domain.web.result.ApiPageResult;
|
||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||
import cn.axzo.tyr.client.feign.PageElementApi;
|
||||
import cn.axzo.tyr.client.model.req.GetPageElementReq;
|
||||
import cn.axzo.tyr.client.model.req.GetUserHasPermissionPageElementReq;
|
||||
import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO;
|
||||
import cn.axzo.tyr.client.model.req.PageElementReportReq;
|
||||
import cn.axzo.tyr.client.model.req.PageElementReq;
|
||||
import cn.axzo.tyr.client.model.req.PageQueryElementReq;
|
||||
import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp;
|
||||
import cn.axzo.tyr.client.model.res.PageElementResp;
|
||||
import cn.axzo.tyr.client.model.req.*;
|
||||
import cn.axzo.tyr.client.model.res.*;
|
||||
import cn.axzo.tyr.server.service.SaasPageElementCategoryService;
|
||||
import cn.axzo.tyr.server.service.SaasPageElementService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -29,6 +24,7 @@ import java.util.List;
|
||||
public class PageElementController implements PageElementApi {
|
||||
|
||||
private final SaasPageElementService saasPageElementService;
|
||||
private final SaasPageElementCategoryService saasPageElementCategoryService;
|
||||
|
||||
@Override
|
||||
public ApiResult<Void> report(PageElementReportReq req) {
|
||||
@ -48,7 +44,7 @@ public class PageElementController implements PageElementApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiPageResult<PageElementResp> page(PageQueryElementReq req) {
|
||||
public ApiPageResult<PageElementCategoryAndElementResp> page(PageQueryElementReq req) {
|
||||
return ApiPageResult.ok(saasPageElementService.page(req));
|
||||
}
|
||||
|
||||
@ -61,4 +57,48 @@ public class PageElementController implements PageElementApi {
|
||||
public ApiResult<List<PageElementResp>> list(PageElementReq param) {
|
||||
return ApiResult.ok(saasPageElementService.list(param));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<List<ListPageElementCategoryResp>> listPageElementCategory() {
|
||||
return ApiResult.ok(saasPageElementCategoryService.listGroupByTerminal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<Long> saveOrUpdateCategory(SaveOrUpdatePageElementCategoryReq req) {
|
||||
return ApiResult.ok(saasPageElementCategoryService.saveOrUpdate(req));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<Void> deleteCategory(DeletePageElementCategoryReq req) {
|
||||
saasPageElementCategoryService.delete(req);
|
||||
return ApiResult.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiPageResult<PageElementResp> pageV2(PageQueryElementV2Req req) {
|
||||
return ApiPageResult.ok(saasPageElementService.pageV2(req));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<Void> saveOrUpdate(SaveOrUpdatePageElementReq req) {
|
||||
saasPageElementService.saveOrUpdate(req);
|
||||
return ApiResult.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<Void> delete(DeletePageElementReq req) {
|
||||
saasPageElementService.delete(req);
|
||||
return ApiResult.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<List<PageElementRelationFeatureResourceResp>> getFeatureResourceRelations(IdReq req) {
|
||||
return ApiResult.ok(saasPageElementService.getFeatureResourceRelations(req.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<Void> importData(List<PageElementImportDataReq> req) {
|
||||
saasPageElementService.importData(req);
|
||||
return ApiResult.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,18 +2,12 @@ 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.client.model.product.ProductSearchListReq;
|
||||
import cn.axzo.tyr.client.model.product.ProductVO;
|
||||
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 cn.axzo.tyr.server.service.ProductService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
@ -21,18 +15,9 @@ 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.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;
|
||||
|
||||
/**
|
||||
* 缓存产品的权限
|
||||
*/
|
||||
@ -45,29 +30,8 @@ public class CacheProductPermissionHandler implements InitializingBean {
|
||||
@Autowired
|
||||
private ProductPermissionCacheService productPermissionCacheService;
|
||||
@Autowired
|
||||
private ProductFeatureRelationService productFeatureRelationService;
|
||||
@Autowired
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
@Autowired
|
||||
private SaasFeatureDao saasFeatureDao;
|
||||
private ProductService productService;
|
||||
|
||||
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);
|
||||
@ -76,16 +40,11 @@ public class CacheProductPermissionHandler implements InitializingBean {
|
||||
if (CollectionUtils.isEmpty(payload.getProductModuleIds())) {
|
||||
return;
|
||||
}
|
||||
PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder()
|
||||
.productModuleIds(payload.getProductModuleIds())
|
||||
|
||||
ProductPermissionCacheService.RefreshProductPermissionCacheParam param = ProductPermissionCacheService.RefreshProductPermissionCacheParam.builder()
|
||||
.productIds(payload.getProductModuleIds())
|
||||
.build();
|
||||
List<SaasProductModuleFeatureRelation> productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq);
|
||||
|
||||
if (CollectionUtils.isEmpty(productFeatures)) {
|
||||
return;
|
||||
}
|
||||
|
||||
storeProductPermission(productFeatures);
|
||||
productPermissionCacheService.refreshCache(param);
|
||||
log.info("end cached product permission handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
@ -97,14 +56,17 @@ public class CacheProductPermissionHandler implements InitializingBean {
|
||||
return;
|
||||
}
|
||||
|
||||
PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder()
|
||||
.build();
|
||||
List<SaasProductModuleFeatureRelation> productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq);
|
||||
|
||||
if (CollectionUtils.isEmpty(productFeatures)) {
|
||||
Set<Long> productIds = productService.list(new ProductSearchListReq()).getData().stream()
|
||||
.map(ProductVO::getId)
|
||||
.collect(Collectors.toSet());
|
||||
if (CollectionUtils.isEmpty(productIds)) {
|
||||
return;
|
||||
}
|
||||
storeProductPermission(productFeatures);
|
||||
|
||||
ProductPermissionCacheService.RefreshProductPermissionCacheParam param = ProductPermissionCacheService.RefreshProductPermissionCacheParam.builder()
|
||||
.productIds(productIds)
|
||||
.build();
|
||||
productPermissionCacheService.refreshCache(param);
|
||||
log.info("end cached product permission handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
@ -113,216 +75,4 @@ public class CacheProductPermissionHandler implements InitializingBean {
|
||||
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;
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ProductPermissionCacheService.PermissionDTO> permissionDTOS = featureResource.getSaasPageElements().stream()
|
||||
.map(pageElement -> ProductPermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(featureResource.getId())
|
||||
.featureCode(pageElement.getCode())
|
||||
.featureType(featureResource.getFeatureType())
|
||||
.terminal(featureResource.getTerminal())
|
||||
.cooperateType(relation.getDictCode())
|
||||
.itemCode(pageElement.getItemCode())
|
||||
.version(pageElement.getVersion())
|
||||
.appType(pageElement.getAppType())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<ProductPermissionCacheService.PermissionDTO> parentPermissions = featureResource.resolvePath().stream()
|
||||
.map(parentFeatureResources::get)
|
||||
.filter(Objects::nonNull)
|
||||
.map(f -> {
|
||||
if (CollectionUtils.isEmpty(f.getSaasPageElements())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return f.getSaasPageElements().stream()
|
||||
.map(pageElement -> ProductPermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(f.getId())
|
||||
.featureCode(pageElement.getCode())
|
||||
.featureType(f.getFeatureType())
|
||||
.terminal(f.getTerminal())
|
||||
.cooperateType(relation.getDictCode())
|
||||
.itemCode(pageElement.getItemCode())
|
||||
.version(pageElement.getVersion())
|
||||
.appType(pageElement.getAppType())
|
||||
.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)
|
||||
.needPageElement(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();
|
||||
}
|
||||
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.ids(parentIds)
|
||||
.needPageElement(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()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,20 +2,12 @@ package cn.axzo.tyr.server.event.inner;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
|
||||
import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum;
|
||||
import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq;
|
||||
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
|
||||
import cn.axzo.tyr.client.model.res.PageElementResp;
|
||||
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
|
||||
import cn.axzo.tyr.client.model.product.ProductSearchListReq;
|
||||
import cn.axzo.tyr.client.model.product.ProductVO;
|
||||
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 cn.axzo.tyr.server.service.ProductService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
@ -23,18 +15,9 @@ 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;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CacheProductSaasFeatureResourceHandler implements InitializingBean {
|
||||
@ -42,36 +25,9 @@ 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);
|
||||
|
||||
}
|
||||
private ProductService productService;
|
||||
|
||||
public void onProductPermissionUpsert(Event event, EventConsumer.Context context) {
|
||||
log.info("begin cached product featureResource handler rocketmq event: {}", event);
|
||||
@ -81,13 +37,10 @@ public class CacheProductSaasFeatureResourceHandler implements InitializingBean
|
||||
return;
|
||||
}
|
||||
|
||||
PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder()
|
||||
.productModuleIds(payload.getProductModuleIds())
|
||||
.type(NEW_FEATURE)
|
||||
ProductSaasFeatureResourceCacheService.RefreshProductFeatureResourceCacheParam param = ProductSaasFeatureResourceCacheService.RefreshProductFeatureResourceCacheParam.builder()
|
||||
.productIds(payload.getProductModuleIds())
|
||||
.build();
|
||||
List<SaasProductModuleFeatureRelation> productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq);
|
||||
|
||||
storeProductFeatureResource(productFeatures);
|
||||
productSaasFeatureResourceCacheService.refreshCache(param);
|
||||
log.info("end cached product featureResource handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
@ -99,15 +52,17 @@ public class CacheProductSaasFeatureResourceHandler implements InitializingBean
|
||||
return;
|
||||
}
|
||||
|
||||
PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder()
|
||||
.type(NEW_FEATURE)
|
||||
.build();
|
||||
List<SaasProductModuleFeatureRelation> productFeatures = productFeatureRelationService.list(pageProductFeatureRelationReq);
|
||||
|
||||
if (CollectionUtils.isEmpty(productFeatures)) {
|
||||
Set<Long> productIds = productService.list(new ProductSearchListReq()).getData().stream()
|
||||
.map(ProductVO::getId)
|
||||
.collect(Collectors.toSet());
|
||||
if (CollectionUtils.isEmpty(productIds)) {
|
||||
return;
|
||||
}
|
||||
storeProductFeatureResource(productFeatures);
|
||||
|
||||
ProductSaasFeatureResourceCacheService.RefreshProductFeatureResourceCacheParam param = ProductSaasFeatureResourceCacheService.RefreshProductFeatureResourceCacheParam.builder()
|
||||
.productIds(productIds)
|
||||
.build();
|
||||
productSaasFeatureResourceCacheService.refreshCache(param);
|
||||
log.info("end cached product featureResource handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
@ -117,121 +72,4 @@ public class CacheProductSaasFeatureResourceHandler implements InitializingBean
|
||||
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;
|
||||
}
|
||||
|
||||
ProductSaasFeatureResourceCacheService.FeatureResourceDTO featureResourceDTO = from(featureResource, relation);
|
||||
List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> featureResourceDTOS = Lists.newArrayList(featureResourceDTO);
|
||||
|
||||
List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> parentPermissions = featureResource.resolvePath().stream()
|
||||
.map(parentFeatureResources::get)
|
||||
.filter(Objects::nonNull)
|
||||
.map(f -> {
|
||||
|
||||
if (StringUtils.isBlank(f.getUniCode())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return from(featureResource, relation);
|
||||
})
|
||||
.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 ProductSaasFeatureResourceCacheService.FeatureResourceDTO from(SaasFeatureResourceResp featureResource,
|
||||
SaasProductModuleFeatureRelation relation) {
|
||||
return ProductSaasFeatureResourceCacheService.FeatureResourceDTO.builder()
|
||||
.featureId(featureResource.getId())
|
||||
.featureType(featureResource.getFeatureType())
|
||||
.terminal(featureResource.getTerminal())
|
||||
.uniCode(featureResource.getUniCode())
|
||||
.cooperateType(relation.getDictCode())
|
||||
.build();
|
||||
}
|
||||
|
||||
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)
|
||||
.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)
|
||||
.build();
|
||||
return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream()
|
||||
.collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,18 +2,12 @@ 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.ListRoleReq;
|
||||
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.common.enums.RoleTypeEnum;
|
||||
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.service.RolePermissionCacheService;
|
||||
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;
|
||||
@ -22,19 +16,10 @@ 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;
|
||||
|
||||
/**
|
||||
* 缓存角色的权限
|
||||
*/
|
||||
@ -48,28 +33,6 @@ public class CacheRolePermissionHandler implements InitializingBean {
|
||||
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);
|
||||
@ -81,15 +44,24 @@ public class CacheRolePermissionHandler implements InitializingBean {
|
||||
// return;
|
||||
// }
|
||||
|
||||
ListRoleReq listSaasRoleParam = ListRoleReq.builder()
|
||||
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
|
||||
.roleIds(Optional.ofNullable(payload.getRoleIds())
|
||||
.map(Lists::newArrayList)
|
||||
.orElse(null))
|
||||
.needPermissionRelation(true)
|
||||
.roleTypesNotIn(RoleTypeEnum.listAdmin())
|
||||
.build();
|
||||
List<SaasRoleRes> roles = roleService.list(listSaasRoleParam);
|
||||
Set<Long> roleIds = roleService.list(listSaasRoleParam).stream()
|
||||
.map(SaasRoleRes::getId)
|
||||
.collect(Collectors.toSet());
|
||||
if (CollectionUtils.isEmpty(roleIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RolePermissionCacheService.RefreshRolePermissionCacheParam refreshRolePermissionCacheParam = RolePermissionCacheService.RefreshRolePermissionCacheParam.builder()
|
||||
.roleIds(roleIds)
|
||||
.build();
|
||||
rolePermissionCacheService.refreshCache(refreshRolePermissionCacheParam);
|
||||
|
||||
storeRolePermission(roles);
|
||||
log.info("end cached role permission handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
@ -100,12 +72,20 @@ public class CacheRolePermissionHandler implements InitializingBean {
|
||||
return;
|
||||
}
|
||||
|
||||
ListRoleReq listSaasRoleParam = ListRoleReq.builder()
|
||||
.needPermissionRelation(true)
|
||||
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
|
||||
.roleTypesNotIn(RoleTypeEnum.listAdmin())
|
||||
.build();
|
||||
List<SaasRoleRes> roles = roleService.list(listSaasRoleParam);
|
||||
Set<Long> roleIds = roleService.list(listSaasRoleParam).stream()
|
||||
.map(SaasRoleRes::getId)
|
||||
.collect(Collectors.toSet());
|
||||
if (CollectionUtils.isEmpty(roleIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
storeRolePermission(roles);
|
||||
RolePermissionCacheService.RefreshRolePermissionCacheParam refreshRolePermissionCacheParam = RolePermissionCacheService.RefreshRolePermissionCacheParam.builder()
|
||||
.roleIds(roleIds)
|
||||
.build();
|
||||
rolePermissionCacheService.refreshCache(refreshRolePermissionCacheParam);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -113,209 +93,4 @@ public class CacheRolePermissionHandler implements InitializingBean {
|
||||
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;
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<RolePermissionCacheService.PermissionDTO> permissionDTOS = featureResource.getSaasPageElements().stream()
|
||||
.map(pageElement -> RolePermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(featureResource.getId())
|
||||
.featureCode(pageElement.getCode())
|
||||
.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 -> {
|
||||
|
||||
if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return featureResource.getSaasPageElements().stream()
|
||||
.map(pageElement -> RolePermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(f.getId())
|
||||
.featureCode(pageElement.getCode())
|
||||
.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)
|
||||
.needPageElement(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)
|
||||
.needPageElement(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()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,16 +2,12 @@ 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.ListRoleReq;
|
||||
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.common.enums.RoleTypeEnum;
|
||||
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;
|
||||
@ -20,18 +16,10 @@ 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.function.Function;
|
||||
import java.util.Set;
|
||||
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
|
||||
* 登录时需要查询菜单树,所以把菜单树缓存起来
|
||||
@ -45,27 +33,8 @@ public class CacheRoleSaasFeatureResourceHandler implements InitializingBean {
|
||||
@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);
|
||||
@ -76,16 +45,23 @@ public class CacheRoleSaasFeatureResourceHandler implements InitializingBean {
|
||||
// return;
|
||||
// }
|
||||
|
||||
ListRoleReq listSaasRoleParam = ListRoleReq.builder()
|
||||
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
|
||||
.roleIds(Optional.ofNullable(payload.getRoleIds())
|
||||
.map(Lists::newArrayList)
|
||||
.orElse(null))
|
||||
.needPermissionRelation(true)
|
||||
.type(NEW_FEATURE)
|
||||
.roleTypesNotIn(RoleTypeEnum.listAdmin())
|
||||
.build();
|
||||
List<SaasRoleRes> roles = roleService.list(listSaasRoleParam);
|
||||
Set<Long> roleIds = roleService.list(listSaasRoleParam).stream()
|
||||
.map(SaasRoleRes::getId)
|
||||
.collect(Collectors.toSet());
|
||||
if (CollectionUtils.isEmpty(roleIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
storeRoleFeatureResource(roles);
|
||||
RoleSaasFeatureResourceCacheService.RefreshRoleFeatureResourceCacheParam param = RoleSaasFeatureResourceCacheService.RefreshRoleFeatureResourceCacheParam.builder()
|
||||
.roleIds(roleIds)
|
||||
.build();
|
||||
roleSaasFeatureResourceCacheService.refreshCache(param);
|
||||
|
||||
log.info("end cached role saasFeatureResource handler rocketmq event: {}", event);
|
||||
}
|
||||
@ -97,13 +73,21 @@ public class CacheRoleSaasFeatureResourceHandler implements InitializingBean {
|
||||
return;
|
||||
}
|
||||
|
||||
ListRoleReq listSaasRoleParam = ListRoleReq.builder()
|
||||
.needPermissionRelation(true)
|
||||
.type(NEW_FEATURE)
|
||||
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
|
||||
.roleTypesNotIn(RoleTypeEnum.listAdmin())
|
||||
.build();
|
||||
List<SaasRoleRes> roles = roleService.list(listSaasRoleParam);
|
||||
|
||||
storeRoleFeatureResource(roles);
|
||||
Set<Long> roleIds = roleService.list(listSaasRoleParam).stream()
|
||||
.map(SaasRoleRes::getId)
|
||||
.collect(Collectors.toSet());
|
||||
if (CollectionUtils.isEmpty(roleIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
RoleSaasFeatureResourceCacheService.RefreshRoleFeatureResourceCacheParam param = RoleSaasFeatureResourceCacheService.RefreshRoleFeatureResourceCacheParam.builder()
|
||||
.roleIds(roleIds)
|
||||
.build();
|
||||
roleSaasFeatureResourceCacheService.refreshCache(param);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -112,116 +96,4 @@ public class CacheRoleSaasFeatureResourceHandler implements InitializingBean {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.framework.rocketmq.EventHandler;
|
||||
import cn.axzo.tyr.server.event.payload.SaasFeatureUpsertPayload;
|
||||
import cn.axzo.tyr.server.job.CacheSaasFeatureJob;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -22,7 +22,7 @@ public class CacheSaasFeatureHandler implements EventHandler, InitializingBean {
|
||||
@Autowired
|
||||
private EventConsumer eventConsumer;
|
||||
@Autowired
|
||||
private CacheSaasFeatureJob cacheSaasFeatureJob;
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event, EventConsumer.Context context) {
|
||||
@ -33,7 +33,10 @@ public class CacheSaasFeatureHandler implements EventHandler, InitializingBean {
|
||||
return;
|
||||
}
|
||||
|
||||
cacheSaasFeatureJob.cacheSaasFeature(Sets.newHashSet(payload.getTerminal()));
|
||||
SaasFeatureResourceService.RefreshFeatureResourceCacheParam param = SaasFeatureResourceService.RefreshFeatureResourceCacheParam.builder()
|
||||
.terminals(Sets.newHashSet(payload.getTerminal()))
|
||||
.build();
|
||||
saasFeatureResourceService.refreshCache(param);
|
||||
log.info("end cached saasFeature handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.framework.rocketmq.EventHandler;
|
||||
import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload;
|
||||
import cn.axzo.tyr.server.job.CacheSaasFeatureJob;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
@ -21,7 +21,7 @@ public class CacheSaasFeatureResourceHandler implements EventHandler, Initializi
|
||||
@Autowired
|
||||
private EventConsumer eventConsumer;
|
||||
@Autowired
|
||||
private CacheSaasFeatureJob cacheSaasFeatureJob;
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event, EventConsumer.Context context) {
|
||||
@ -32,7 +32,10 @@ public class CacheSaasFeatureResourceHandler implements EventHandler, Initializi
|
||||
return;
|
||||
}
|
||||
|
||||
cacheSaasFeatureJob.cacheSaasFeatureResource(payload.getTerminals());
|
||||
SaasFeatureResourceService.RefreshFeatureResourceCacheParam param = SaasFeatureResourceService.RefreshFeatureResourceCacheParam.builder()
|
||||
.terminals(payload.getTerminals())
|
||||
.build();
|
||||
saasFeatureResourceService.refreshCache(param);
|
||||
log.info("end cached saasFeatureResource handler rocketmq event: {}", event);
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
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.ProductSaasFeatureResourceCacheService;
|
||||
import cn.axzo.tyr.server.service.ProductService;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
@ -13,6 +11,7 @@ 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.Optional;
|
||||
import java.util.Set;
|
||||
@ -23,7 +22,7 @@ import java.util.stream.Collectors;
|
||||
public class CacheProductFeatureResourceJob extends IJobHandler {
|
||||
|
||||
@Autowired
|
||||
private CacheProductSaasFeatureResourceHandler cacheProductSaasFeatureResourceHandler;
|
||||
private ProductSaasFeatureResourceCacheService productSaasFeatureResourceCacheService;
|
||||
@Autowired
|
||||
private ProductService productService;
|
||||
|
||||
@ -41,14 +40,14 @@ public class CacheProductFeatureResourceJob extends IJobHandler {
|
||||
.map(ProductVO::getId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
ProductPermissionCreatedPayload payload = ProductPermissionCreatedPayload.builder()
|
||||
.productModuleIds(productIds)
|
||||
.build();
|
||||
if (CollectionUtils.isEmpty(productIds)) {
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
Event event = Event.builder()
|
||||
.data(payload)
|
||||
ProductSaasFeatureResourceCacheService.RefreshProductFeatureResourceCacheParam param = ProductSaasFeatureResourceCacheService.RefreshProductFeatureResourceCacheParam.builder()
|
||||
.productIds(productIds)
|
||||
.build();
|
||||
cacheProductSaasFeatureResourceHandler.onProductPermissionUpsert(event, null);
|
||||
productSaasFeatureResourceCacheService.refreshCache(param);
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
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.ProductPermissionCacheService;
|
||||
import cn.axzo.tyr.server.service.ProductService;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
@ -13,6 +11,7 @@ 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.Optional;
|
||||
import java.util.Set;
|
||||
@ -23,7 +22,7 @@ import java.util.stream.Collectors;
|
||||
public class CacheProductPermissionJob extends IJobHandler {
|
||||
|
||||
@Autowired
|
||||
private CacheProductPermissionHandler cacheProductPermissionHandler;
|
||||
private ProductPermissionCacheService productPermissionCacheService;
|
||||
@Autowired
|
||||
private ProductService productService;
|
||||
|
||||
@ -40,15 +39,14 @@ public class CacheProductPermissionJob extends IJobHandler {
|
||||
.stream()
|
||||
.map(ProductVO::getId)
|
||||
.collect(Collectors.toSet());
|
||||
if (CollectionUtils.isEmpty(productIds)) {
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
ProductPermissionCreatedPayload payload = ProductPermissionCreatedPayload.builder()
|
||||
.productModuleIds(productIds)
|
||||
ProductPermissionCacheService.RefreshProductPermissionCacheParam param = ProductPermissionCacheService.RefreshProductPermissionCacheParam.builder()
|
||||
.productIds(productIds)
|
||||
.build();
|
||||
|
||||
Event event = Event.builder()
|
||||
.data(payload)
|
||||
.build();
|
||||
cacheProductPermissionHandler.onProductPermissionUpsert(event, null);
|
||||
productPermissionCacheService.refreshCache(param);
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,16 +1,9 @@
|
||||
package cn.axzo.tyr.server.job;
|
||||
|
||||
import cn.axzo.foundation.page.PageResp;
|
||||
import cn.axzo.tyr.client.model.req.PageRoleReq;
|
||||
import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes;
|
||||
import cn.axzo.tyr.client.common.enums.RoleTypeEnum;
|
||||
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;
|
||||
@ -20,9 +13,6 @@ 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;
|
||||
@ -31,102 +21,33 @@ import java.util.stream.Collectors;
|
||||
@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);
|
||||
PageRoleReq pageSaasRoleParam = Optional.ofNullable(s)
|
||||
.map(e -> JSONObject.parseObject(e, PageRoleReq.class))
|
||||
.orElseGet(() -> PageRoleReq.builder().build());
|
||||
RoleService.ListSaasRoleParam listSaasRoleParam = Optional.ofNullable(s)
|
||||
.map(e -> JSONObject.parseObject(e, RoleService.ListSaasRoleParam.class))
|
||||
.orElseGet(() -> RoleService.ListSaasRoleParam.builder().build());
|
||||
listSaasRoleParam.setRoleTypesNotIn(RoleTypeEnum.listAdmin());
|
||||
|
||||
// 因为角色权限集是重复使用,通过角色找权限集数据量太大,直接查询所有权限集的权限,比较快
|
||||
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;
|
||||
}
|
||||
Set<Long> roleIds = roleService.list(listSaasRoleParam).stream()
|
||||
.map(SaasRoleRes::getId)
|
||||
.collect(Collectors.toSet());
|
||||
if (CollectionUtils.isEmpty(roleIds)) {
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
RoleSaasFeatureResourceCacheService.RefreshRoleFeatureResourceCacheParam param = RoleSaasFeatureResourceCacheService.RefreshRoleFeatureResourceCacheParam.builder()
|
||||
.roleIds(roleIds)
|
||||
.build();
|
||||
roleSaasFeatureResourceCacheService.refreshCache(param);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,16 +1,9 @@
|
||||
package cn.axzo.tyr.server.job;
|
||||
|
||||
import cn.axzo.foundation.page.PageResp;
|
||||
import cn.axzo.tyr.client.model.req.PageRoleReq;
|
||||
import cn.axzo.tyr.client.model.res.SaasPermissionRelationRes;
|
||||
import cn.axzo.tyr.client.common.enums.RoleTypeEnum;
|
||||
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;
|
||||
@ -20,9 +13,6 @@ 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;
|
||||
@ -31,102 +21,35 @@ import java.util.stream.Collectors;
|
||||
@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);
|
||||
PageRoleReq pageSaasRoleParam = Optional.ofNullable(s)
|
||||
.map(e -> JSONObject.parseObject(e, PageRoleReq.class))
|
||||
.orElseGet(() -> PageRoleReq.builder().build());
|
||||
RoleService.ListSaasRoleParam listSaasRoleParam = Optional.ofNullable(s)
|
||||
.map(e -> JSONObject.parseObject(e, RoleService.ListSaasRoleParam.class))
|
||||
.orElseGet(() -> RoleService.ListSaasRoleParam.builder().build());
|
||||
|
||||
// 因为角色权限集是重复使用,通过角色找权限集数据量太大,直接查询所有权限集的权限,比较快
|
||||
Map<Long, List<SaasPermissionRelationRes>> permissionRelations = listPgroupPermissionRelation();
|
||||
listSaasRoleParam.setRoleTypesNotIn(RoleTypeEnum.listAdmin());
|
||||
|
||||
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;
|
||||
}
|
||||
Set<Long> roleIds = roleService.list(listSaasRoleParam).stream()
|
||||
.map(SaasRoleRes::getId)
|
||||
.collect(Collectors.toSet());
|
||||
if (CollectionUtils.isEmpty(roleIds)) {
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
RolePermissionCacheService.RefreshRolePermissionCacheParam refreshRolePermissionCacheParam = RolePermissionCacheService.RefreshRolePermissionCacheParam.builder()
|
||||
.roleIds(roleIds)
|
||||
.build();
|
||||
rolePermissionCacheService.refreshCache(refreshRolePermissionCacheParam);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
package cn.axzo.tyr.server.job;
|
||||
|
||||
import cn.axzo.tyr.client.common.enums.FeatureResourceStatus;
|
||||
import cn.axzo.tyr.client.model.enums.DelegatedType;
|
||||
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
|
||||
import cn.axzo.tyr.client.model.res.PageElementResp;
|
||||
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.alibaba.fastjson.JSONObject;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
@ -22,8 +18,6 @@ import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
@ -37,11 +31,6 @@ public class CacheSaasFeatureJob extends IJobHandler {
|
||||
@Autowired
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
|
||||
/**
|
||||
* 分组这些菜单节点没有版本号,默认为0,方便权限过滤
|
||||
*/
|
||||
private static final int DEFAULT_VERSION = 0;
|
||||
|
||||
@Override
|
||||
@XxlJob("CacheSaasFeatureJob")
|
||||
public ReturnT<String> execute(String s) throws Exception {
|
||||
@ -50,6 +39,7 @@ public class CacheSaasFeatureJob extends IJobHandler {
|
||||
StoreSaasFeatureParam req = Optional.ofNullable(s)
|
||||
.map(e -> JSONObject.parseObject(e, StoreSaasFeatureParam.class))
|
||||
.orElseGet(() -> StoreSaasFeatureParam.builder().build());
|
||||
|
||||
cacheSaasFeature(req.getTerminals());
|
||||
|
||||
cacheSaasFeatureResource(req.getTerminals());
|
||||
@ -57,66 +47,42 @@ public class CacheSaasFeatureJob extends IJobHandler {
|
||||
}
|
||||
|
||||
public void cacheSaasFeature(Set<String> terminals) {
|
||||
Map<String, List<SaasFeatureResourceService.SaasFeatureResourceCache>> saasFeatures = saasFeatureDao.lambdaQuery()
|
||||
// 没有办法只有所有端,除非写sql去重,菜单数量不多
|
||||
Set<String> updateTerminals = saasFeatureDao.lambdaQuery()
|
||||
.in(CollectionUtils.isNotEmpty(terminals), SaasFeature::getTerminal, terminals)
|
||||
.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())));
|
||||
.map(SaasFeature::getTerminal)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
List<SaasFeatureResourceService.SaasFeatureResourceDTO> saasFeatureResources = saasFeatures.entrySet().stream()
|
||||
.map(e -> SaasFeatureResourceService.SaasFeatureResourceDTO.builder()
|
||||
.terminal(e.getKey())
|
||||
.features(e.getValue())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(updateTerminals)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder()
|
||||
.saasFeatureResources(saasFeatureResources)
|
||||
SaasFeatureResourceService.RefreshFeatureResourceCacheParam param = SaasFeatureResourceService.RefreshFeatureResourceCacheParam.builder()
|
||||
.terminals(updateTerminals)
|
||||
.build();
|
||||
saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache);
|
||||
saasFeatureResourceService.refreshCache(param);
|
||||
}
|
||||
|
||||
public void cacheSaasFeatureResource(Set<String> terminals) {
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.needPageElement(true)
|
||||
.terminals(terminals)
|
||||
.build();
|
||||
|
||||
Map<String, List<SaasFeatureResourceService.SaasFeatureResourceCache>> saasFeatureResources = saasFeatureResourceService.list(pageSaasFeatureResourceReq)
|
||||
Set<String> updateTerminals = 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())
|
||||
.uniCode(e.getUniCode())
|
||||
.status(e.getStatus())
|
||||
.version(Optional.ofNullable(e.getSaasPageElements())
|
||||
.map(pageElement -> pageElement.stream()
|
||||
.findFirst()
|
||||
.map(PageElementResp::getVersion)
|
||||
.orElse(DEFAULT_VERSION))
|
||||
.orElse(DEFAULT_VERSION))
|
||||
.build(), Collectors.toList())));
|
||||
.map(SaasFeatureResourceResp::getTerminal)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
List<SaasFeatureResourceService.SaasFeatureResourceDTO> featureResources = saasFeatureResources.entrySet().stream()
|
||||
.map(e -> SaasFeatureResourceService.SaasFeatureResourceDTO.builder()
|
||||
.terminal(e.getKey())
|
||||
.features(e.getValue())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(updateTerminals)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder()
|
||||
.saasFeatureResources(featureResources)
|
||||
SaasFeatureResourceService.RefreshFeatureResourceCacheParam param = SaasFeatureResourceService.RefreshFeatureResourceCacheParam.builder()
|
||||
.terminals(updateTerminals)
|
||||
.build();
|
||||
saasFeatureResourceService.storeCache(storeSaasFeatureResourceCache);
|
||||
saasFeatureResourceService.refreshCache(param);
|
||||
}
|
||||
|
||||
@Data
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
package cn.axzo.tyr.server.repository.dao;
|
||||
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElementCategory;
|
||||
import cn.axzo.tyr.server.repository.mapper.SaasPageElementCategoryMapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* @author likunpeng
|
||||
* @version 1.0
|
||||
* @date 2024/8/20
|
||||
*/
|
||||
@Repository
|
||||
public class SaasPageElementCategoryDao extends ServiceImpl<SaasPageElementCategoryMapper, SaasPageElementCategory> {
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
package cn.axzo.tyr.server.repository.dao;
|
||||
|
||||
import cn.axzo.basics.common.constant.enums.DeleteEnum;
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import cn.axzo.tyr.client.common.enums.PageElementTypeEnum;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElement;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation;
|
||||
import cn.axzo.tyr.server.repository.mapper.SaasPageElementMapper;
|
||||
@ -41,4 +43,42 @@ public class SaasPageElementDao extends ServiceImpl<SaasPageElementMapper, SaasP
|
||||
.notIn(CollectionUtils.isNotEmpty(excludeIds), SaasPageElement::getId, excludeIds)
|
||||
.list();
|
||||
}
|
||||
|
||||
public void updateItemNameByItemCode(String itemCode, String itemName, String terminal) {
|
||||
lambdaUpdate()
|
||||
.eq(SaasPageElement::getIsDelete, DeleteEnum.NORMAL.getValue())
|
||||
.eq(SaasPageElement::getItemCode, itemCode)
|
||||
.eq(SaasPageElement::getTerminal, terminal)
|
||||
.set(SaasPageElement::getItemName, itemName)
|
||||
.update();
|
||||
}
|
||||
|
||||
public List<SaasPageElement> listByItemCodeAndTerminal(String itemCode, String terminal) {
|
||||
return lambdaQuery()
|
||||
.eq(SaasPageElement::getIsDelete, DeleteEnum.NORMAL.getValue())
|
||||
.eq(SaasPageElement::getTerminal, terminal)
|
||||
.eq(SaasPageElement::getItemCode, itemCode)
|
||||
.list();
|
||||
}
|
||||
|
||||
public void deleteIdsByTerminal(List<Long> ids, String terminal) {
|
||||
if (CollectionUtils.isEmpty(ids)) {
|
||||
return;
|
||||
}
|
||||
lambdaUpdate()
|
||||
.eq(SaasPageElement::getTerminal, terminal)
|
||||
.in(BaseEntity::getId, ids)
|
||||
.set(SaasPageElement::getIsDelete, DeleteEnum.DELETE.getValue())
|
||||
.update();
|
||||
}
|
||||
|
||||
public void updateComponentsGroupCode(String oldGroupCode, String newGroupCode, String terminal) {
|
||||
lambdaUpdate()
|
||||
.eq(SaasPageElement::getIsDelete, DeleteEnum.NORMAL.getValue())
|
||||
.eq(SaasPageElement::getTerminal, terminal)
|
||||
.eq(SaasPageElement::getType, PageElementTypeEnum.COMPONENT.getCode())
|
||||
.eq(SaasPageElement::getGroupCode, oldGroupCode)
|
||||
.set(SaasPageElement::getGroupCode, newGroupCode)
|
||||
.update();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@ package cn.axzo.tyr.server.repository.dao;
|
||||
|
||||
import cn.axzo.basics.common.constant.enums.DeleteEnum;
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import cn.axzo.tyr.client.common.enums.PageElementTypeEnum;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElement;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation;
|
||||
import cn.axzo.tyr.server.repository.mapper.SaasPageElementFeatureResourceRelationMapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
@ -46,4 +48,23 @@ public class SaasPageElementFeatureResourceRelationDao extends ServiceImpl<SaasP
|
||||
.set(Objects.nonNull(operatorId), SaasPageElementFeatureResourceRelation::getUpdateBy, operatorId)
|
||||
.update();
|
||||
}
|
||||
|
||||
public void deleteByTerminalAndPageElementCodes(String terminal, List<String> pageElementCodes, Long operatorId) {
|
||||
lambdaUpdate()
|
||||
.eq(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.NORMAL.getValue())
|
||||
.eq(SaasPageElementFeatureResourceRelation::getTerminal, terminal)
|
||||
.in(SaasPageElementFeatureResourceRelation::getPageElementCode, pageElementCodes)
|
||||
.set(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.DELETE.getValue())
|
||||
.set(Objects.nonNull(operatorId), SaasPageElementFeatureResourceRelation::getUpdateBy, operatorId)
|
||||
.update();
|
||||
}
|
||||
|
||||
public void updateGroupCode(String oldGroupCode, String newGroupCode, String terminal) {
|
||||
lambdaUpdate()
|
||||
.eq(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.NORMAL.getValue())
|
||||
.eq(SaasPageElementFeatureResourceRelation::getTerminal, terminal)
|
||||
.eq(SaasPageElementFeatureResourceRelation::getPageElementCode, oldGroupCode)
|
||||
.set(SaasPageElementFeatureResourceRelation::getPageElementCode, newGroupCode)
|
||||
.update();
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
package cn.axzo.tyr.server.repository.entity;
|
||||
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* 页面元素表
|
||||
*
|
||||
* @author likunpeng
|
||||
* @version 1.0
|
||||
* @date 2024/6/18
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Builder
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName(value = "saas_page_element_category", autoResultMap = true)
|
||||
public class SaasPageElementCategory extends BaseEntity<SaasPageElementCategory> {
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 更新人
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 项目code(H5会拉取项目下所有的元素)
|
||||
*/
|
||||
private String itemCode;
|
||||
|
||||
/**
|
||||
* 项目名称
|
||||
*/
|
||||
private String itemName;
|
||||
|
||||
/**
|
||||
* 所属端
|
||||
*/
|
||||
private String terminal;
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package cn.axzo.tyr.server.repository.mapper;
|
||||
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElementCategory;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
public interface SaasPageElementCategoryMapper extends BaseMapper<SaasPageElementCategory> {
|
||||
|
||||
}
|
||||
|
||||
@ -18,18 +18,15 @@ public interface ProductPermissionCacheService {
|
||||
*/
|
||||
Map<Long, List<PermissionDTO>> list(ListProductPermissionParam param);
|
||||
|
||||
/**
|
||||
* 存储产品的权限信息
|
||||
* @param param
|
||||
*/
|
||||
void store(StoreProductPermissionParam param);
|
||||
void refreshCache(RefreshProductPermissionCacheParam param);
|
||||
|
||||
/**
|
||||
* 产品是否有缓存权限
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
List<Long> hasProductIds(HasProductPermissionParam param);
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class RefreshProductPermissionCacheParam {
|
||||
private Set<Long> productIds;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
|
||||
@ -13,7 +13,15 @@ public interface ProductSaasFeatureResourceCacheService {
|
||||
|
||||
Map<Long, List<FeatureResourceDTO>> list(ListProductFeatureResourceParam param);
|
||||
|
||||
void store(StoreProductFeatureResourceParam param);
|
||||
void refreshCache(RefreshProductFeatureResourceCacheParam param);
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class RefreshProductFeatureResourceCacheParam {
|
||||
private Set<Long> productIds;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
|
||||
@ -14,29 +14,14 @@ public interface RolePermissionCacheService {
|
||||
|
||||
Map<Long, List<PermissionDTO>> list(ListRolePermissionParam param);
|
||||
|
||||
/**
|
||||
* redisKey:roleId
|
||||
* redisValue:permission
|
||||
* @param param
|
||||
*/
|
||||
void store(StoreRolePermissionParam param);
|
||||
|
||||
List<Long> hasRoleIds(HasRolePermissionParam param);
|
||||
void refreshCache(RefreshRolePermissionCacheParam param);
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class HasRolePermissionParam {
|
||||
private List<Long> roleIds;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class StoreRolePermissionParam {
|
||||
private List<RolePermission> rolePermissions;
|
||||
class RefreshRolePermissionCacheParam {
|
||||
private Set<Long> roleIds;
|
||||
}
|
||||
|
||||
@Data
|
||||
|
||||
@ -13,8 +13,15 @@ public interface RoleSaasFeatureResourceCacheService {
|
||||
|
||||
Map<Long, List<SaasFeatureResourceDTO>> list(ListRoleSaasFeatureResourceParam param);
|
||||
|
||||
void store(StoreRoleSaasFeatureResourceParam param);
|
||||
void refreshCache(RefreshRoleFeatureResourceCacheParam param);
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class RefreshRoleFeatureResourceCacheParam {
|
||||
private Set<Long> roleIds;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
|
||||
@ -64,10 +64,18 @@ public interface SaasFeatureResourceService extends IService<SaasFeatureResource
|
||||
|
||||
void deleteFeatureResource(DeleteFeatureResourceReq param);
|
||||
|
||||
void storeCache(StoreSaasFeatureResourceCache param);
|
||||
|
||||
Map<String, List<SaasFeatureResourceCache>> listCache(ListSaasFeatureResourceCache param);
|
||||
|
||||
void refreshCache(RefreshFeatureResourceCacheParam param);
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
class RefreshFeatureResourceCacheParam {
|
||||
private Set<String> terminals;
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
package cn.axzo.tyr.server.service;
|
||||
|
||||
import cn.axzo.tyr.client.model.req.DeletePageElementCategoryReq;
|
||||
import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementCategoryReq;
|
||||
import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author likunpeng
|
||||
* @version 1.0
|
||||
* @date 2024/8/20
|
||||
*/
|
||||
public interface SaasPageElementCategoryService {
|
||||
|
||||
List<ListPageElementCategoryResp> listGroupByTerminal();
|
||||
|
||||
Long saveOrUpdate(SaveOrUpdatePageElementCategoryReq req);
|
||||
|
||||
void delete(DeletePageElementCategoryReq req);
|
||||
}
|
||||
@ -1,15 +1,8 @@
|
||||
package cn.axzo.tyr.server.service;
|
||||
|
||||
import cn.axzo.framework.domain.page.PageResp;
|
||||
import cn.axzo.tyr.client.model.req.GetPageElementReq;
|
||||
import cn.axzo.tyr.client.model.req.GetUserHasPermissionPageElementReq;
|
||||
import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO;
|
||||
import cn.axzo.tyr.client.model.req.PageElementReportReq;
|
||||
import cn.axzo.tyr.client.model.req.PageElementReq;
|
||||
import cn.axzo.tyr.client.model.req.PageQueryElementReq;
|
||||
import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp;
|
||||
import cn.axzo.tyr.client.model.res.PageElementBasicDTO;
|
||||
import cn.axzo.tyr.client.model.res.PageElementResp;
|
||||
import cn.axzo.tyr.client.model.req.*;
|
||||
import cn.axzo.tyr.client.model.res.*;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElement;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
@ -68,7 +61,7 @@ public interface SaasPageElementService extends IService<SaasPageElement> {
|
||||
* @param request 查询条件
|
||||
* @return
|
||||
*/
|
||||
PageResp<PageElementResp> page(PageQueryElementReq request);
|
||||
PageResp<PageElementCategoryAndElementResp> page(PageQueryElementReq request);
|
||||
|
||||
/**
|
||||
* 根据用户传入的页面code,查询用户有权限的元素code
|
||||
@ -82,4 +75,14 @@ public interface SaasPageElementService extends IService<SaasPageElement> {
|
||||
List<PageElementResp> list(PageElementReq param);
|
||||
|
||||
cn.axzo.foundation.page.PageResp<PageElementResp> page(PageElementReq param);
|
||||
|
||||
PageResp<PageElementResp> pageV2(PageQueryElementV2Req req);
|
||||
|
||||
Long saveOrUpdate(SaveOrUpdatePageElementReq req);
|
||||
|
||||
void delete(DeletePageElementReq req);
|
||||
|
||||
List<PageElementRelationFeatureResourceResp> getFeatureResourceRelations(Long pageElementId);
|
||||
|
||||
void importData(List<PageElementImportDataReq> req);
|
||||
}
|
||||
|
||||
@ -992,11 +992,14 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
|
||||
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());
|
||||
|
||||
List<RoleSaasFeatureResourceCacheService.SaasFeatureResourceDTO> roleFeatureResources = Optional.ofNullable(roleFeatureResourceMap.get(saasRole.getId()))
|
||||
.map(role -> role.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()))
|
||||
.orElseGet(Lists::newArrayList);
|
||||
|
||||
Set<Long> normalFeatureIds = resolveNormalRole(productFeatureSources, saasRole, roleFeatureResources);
|
||||
|
||||
|
||||
@ -1,60 +1,76 @@
|
||||
package cn.axzo.tyr.server.service.impl;
|
||||
|
||||
import cn.axzo.foundation.exception.Axssert;
|
||||
import cn.axzo.pokonyan.config.redis.RedisClient;
|
||||
import cn.axzo.basics.common.exception.ServiceException;
|
||||
import cn.axzo.tyr.client.model.req.PageProductFeatureRelationReq;
|
||||
import cn.axzo.tyr.server.event.inner.CacheProductPermissionHandler;
|
||||
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.SaasProductModuleFeatureRelation;
|
||||
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
|
||||
import cn.axzo.tyr.server.service.ProductPermissionCacheService;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import cn.hutool.core.lang.Pair;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
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.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
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.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.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
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;
|
||||
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RefreshScope
|
||||
public class ProductPermissionCacheServiceImpl implements ProductPermissionCacheService {
|
||||
|
||||
private static final String PRODUCT_PERMISSION_KEY = "product:permission:%s";
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
@Autowired
|
||||
private ProductFeatureRelationService productFeatureRelationService;
|
||||
@Autowired
|
||||
private CacheProductPermissionHandler cacheProductPermissionHandler;
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
@Autowired
|
||||
private SaasFeatureDao saasFeatureDao;
|
||||
|
||||
/** 产品权限缓存过期时间 **/
|
||||
@Value("${product.permission.expire.minutes:14}")
|
||||
private Long expireInMinutes;
|
||||
private LoadingCache<Long, Optional<List<PermissionDTO>>> productPermissionCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.DAYS)
|
||||
.maximumSize(5000)
|
||||
.build(new CacheLoader<Long, Optional<List<PermissionDTO>>>() {
|
||||
@Override
|
||||
public Optional<List<PermissionDTO>> load(Long productId) {
|
||||
return listProductPermissions(Lists.newArrayList(productId))
|
||||
.values()
|
||||
.stream()
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, Optional<List<PermissionDTO>>> loadAll(Iterable keys) throws Exception {
|
||||
List<Long> productIds = Lists.newArrayList(keys);
|
||||
|
||||
Map<Long, List<PermissionDTO>> productPermissions = listProductPermissions(productIds);
|
||||
|
||||
return Maps.toMap(productIds, productId -> Optional.ofNullable(productPermissions.get(productId)));
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public Map<Long, List<PermissionDTO>> list(ListProductPermissionParam param) {
|
||||
@ -62,167 +78,266 @@ public class ProductPermissionCacheServiceImpl implements ProductPermissionCache
|
||||
if (CollectionUtils.isEmpty(param.getProductIds())) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<Long, List<PermissionDTO>> permissionCached = listProductPermissionCached(param);
|
||||
Map<Long, List<PermissionDTO>> productPermissions;
|
||||
try {
|
||||
productPermissions = productPermissionCache.getAll(param.getProductIds()).entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().orElseGet(Lists::newArrayList)));
|
||||
} catch (ExecutionException ex) {
|
||||
log.error("list product cache permission error:{} error", param.getProductIds(), ex);
|
||||
// 外面有做降级
|
||||
throw new ServiceException("查询产品权限缓存异常");
|
||||
}
|
||||
|
||||
fillCacheProductPermissions(param, permissionCached);
|
||||
if (CollectionUtils.isEmpty(param.getFeatureCodes())) {
|
||||
return productPermissions;
|
||||
}
|
||||
|
||||
return permissionCached;
|
||||
}
|
||||
|
||||
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)
|
||||
return productPermissions.entrySet()
|
||||
.stream()
|
||||
.map(e -> Pair.of(e.getKey(), e.getValue().stream()
|
||||
.filter(permission -> param.getFeatureCodes().contains(permission.getFeatureCode()))
|
||||
.collect(Collectors.toList()))
|
||||
)
|
||||
.filter(e -> !CollectionUtils.isEmpty(e.getValue()))
|
||||
.collect(Collectors.toMap(Pair::getKey, Pair::getValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(StoreProductPermissionParam param) {
|
||||
|
||||
Axssert.check(param.getProductPermissions().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 (ProductPermission productPermission : param.getProductPermissions()) {
|
||||
String redisKey = getKey(productPermission.getProductId());
|
||||
|
||||
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())));
|
||||
|
||||
// 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁
|
||||
redisTemplate.delete(redisKey);
|
||||
RedisClient.HashOps.hPutAll(redisKey, redisValues);
|
||||
redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES);
|
||||
log.info("succeed to store product permission: redisKey:{} value:{}", redisKey, redisValues);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hasProductIds(HasProductPermissionParam 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);
|
||||
operations.hasKey(redisKey);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
return Streams.zip(param.getProductIds().stream(),
|
||||
redisValues.stream(),
|
||||
(productId, redisValue) -> Pair.of(productId, redisValue))
|
||||
.filter(e -> BooleanUtils.isTrue((Boolean) e.getValue()))
|
||||
.map(Pair::getKey)
|
||||
.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()) {
|
||||
public void refreshCache(RefreshProductPermissionCacheParam param) {
|
||||
if (CollectionUtils.isEmpty(param.getProductIds())) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Long, List<PermissionDTO>> productPermissions = listProductPermissions(Lists.newArrayList(param.getProductIds()));
|
||||
|
||||
productPermissionCache.putAll(Maps.toMap(param.getProductIds(), productId -> Optional.ofNullable(productPermissions.get(productId))));
|
||||
}
|
||||
|
||||
private Map<Long, List<PermissionDTO>> listProductPermissions(List<Long> productIds) {
|
||||
|
||||
if (CollectionUtils.isEmpty(productIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder()
|
||||
.productModuleIds(difference)
|
||||
.productModuleIds(Sets.newHashSet(productIds))
|
||||
.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()
|
||||
return resolveProductPermissions(productPermissions).stream()
|
||||
.collect(Collectors.toMap(ProductPermission::getProductId, ProductPermission::getPermissions));
|
||||
permissionCached.putAll(productPermissionMap);
|
||||
}
|
||||
|
||||
private String getKey(Object... params) {
|
||||
return String.format(PRODUCT_PERMISSION_KEY, params);
|
||||
private 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());
|
||||
}
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
static class PermissionWrapper {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 协同关系类型
|
||||
* 原saas_product_module_feature_relation.dictCode
|
||||
*/
|
||||
private String cooperateType;
|
||||
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());
|
||||
|
||||
private Long featureId;
|
||||
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());
|
||||
|
||||
private String featureCode;
|
||||
permissionDTOS.addAll(parentPermissions);
|
||||
return permissionDTOS;
|
||||
}
|
||||
|
||||
private String terminal;
|
||||
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;
|
||||
}
|
||||
|
||||
private Integer featureType;
|
||||
if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Long productId;
|
||||
List<ProductPermissionCacheService.PermissionDTO> permissionDTOS = featureResource.getSaasPageElements().stream()
|
||||
.map(pageElement -> ProductPermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(featureResource.getId())
|
||||
.featureCode(pageElement.getCode())
|
||||
.featureType(featureResource.getFeatureType())
|
||||
.terminal(featureResource.getTerminal())
|
||||
.cooperateType(relation.getDictCode())
|
||||
.itemCode(pageElement.getItemCode())
|
||||
.version(pageElement.getVersion())
|
||||
.appType(pageElement.getAppType())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<ProductPermissionCacheService.PermissionDTO> parentPermissions = featureResource.resolvePath().stream()
|
||||
.map(parentFeatureResources::get)
|
||||
.filter(Objects::nonNull)
|
||||
.map(f -> {
|
||||
if (CollectionUtils.isEmpty(f.getSaasPageElements())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return f.getSaasPageElements().stream()
|
||||
.map(pageElement -> ProductPermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(f.getId())
|
||||
.featureCode(pageElement.getCode())
|
||||
.featureType(f.getFeatureType())
|
||||
.terminal(f.getTerminal())
|
||||
.cooperateType(relation.getDictCode())
|
||||
.itemCode(pageElement.getItemCode())
|
||||
.version(pageElement.getVersion())
|
||||
.appType(pageElement.getAppType())
|
||||
.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)
|
||||
.needPageElement(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();
|
||||
}
|
||||
|
||||
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
|
||||
.ids(parentIds)
|
||||
.needPageElement(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()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,38 +1,40 @@
|
||||
package cn.axzo.tyr.server.service.impl;
|
||||
|
||||
import cn.axzo.foundation.exception.Axssert;
|
||||
import cn.axzo.pokonyan.config.redis.RedisClient;
|
||||
import cn.axzo.basics.common.exception.ServiceException;
|
||||
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.client.model.req.PageSaasFeatureResourceReq;
|
||||
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
|
||||
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 cn.hutool.core.lang.Pair;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
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.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.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.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
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
|
||||
@ -40,139 +42,210 @@ import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.
|
||||
@RefreshScope
|
||||
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;
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
|
||||
@Value("${product.feature.resouce.expire.minutes:14}")
|
||||
private Long expireInMinutes;
|
||||
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 LoadingCache<Long, Optional<List<FeatureResourceDTO>>> productFeatureResourceCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.DAYS)
|
||||
.maximumSize(5000)
|
||||
.build(new CacheLoader<Long, Optional<List<FeatureResourceDTO>>>() {
|
||||
@Override
|
||||
public Optional<List<FeatureResourceDTO>> load(Long productId) {
|
||||
return listProductFeatureResource(Lists.newArrayList(productId))
|
||||
.values()
|
||||
.stream()
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, Optional<List<FeatureResourceDTO>>> loadAll(Iterable keys) throws Exception {
|
||||
List<Long> productIds = Lists.newArrayList(keys);
|
||||
|
||||
Map<Long, List<FeatureResourceDTO>> productPermissions = listProductFeatureResource(productIds);
|
||||
|
||||
return Maps.toMap(productIds, productId -> Optional.ofNullable(productPermissions.get(productId)));
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public Map<Long, List<FeatureResourceDTO>> list(ListProductFeatureResourceParam param) {
|
||||
if (CollectionUtils.isEmpty(param.getProductIds())) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<Long, List<FeatureResourceDTO>> featureResourceCached = listProductFeatureResourceCached(param);
|
||||
Map<Long, List<FeatureResourceDTO>> productFeatureResources;
|
||||
try {
|
||||
productFeatureResources = productFeatureResourceCache.getAll(param.getProductIds()).entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().orElseGet(Lists::newArrayList)));
|
||||
} catch (ExecutionException ex) {
|
||||
log.error("list product cache featureResource error:{} error", param.getProductIds(), ex);
|
||||
// 外面有做降级
|
||||
throw new ServiceException("查询产品菜单缓存异常");
|
||||
}
|
||||
|
||||
fillCacheProductFeatureResource(param, featureResourceCached);
|
||||
if (CollectionUtils.isEmpty(param.getUniCodes())) {
|
||||
return productFeatureResources;
|
||||
}
|
||||
|
||||
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, expireInMinutes, TimeUnit.MINUTES);
|
||||
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)
|
||||
return productFeatureResources.entrySet()
|
||||
.stream()
|
||||
.map(e -> Pair.of(e.getKey(), e.getValue().stream()
|
||||
.filter(permission -> param.getUniCodes().contains(permission.getUniCode()))
|
||||
.collect(Collectors.toList()))
|
||||
)
|
||||
.filter(e -> !CollectionUtils.isEmpty(e.getValue()))
|
||||
.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()) {
|
||||
@Override
|
||||
public void refreshCache(RefreshProductFeatureResourceCacheParam param) {
|
||||
if (CollectionUtils.isEmpty(param.getProductIds())) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Long, List<FeatureResourceDTO>> productPermissions = listProductFeatureResource(Lists.newArrayList(param.getProductIds()));
|
||||
|
||||
productFeatureResourceCache.putAll(Maps.toMap(param.getProductIds(), productId -> Optional.ofNullable(productPermissions.get(productId))));
|
||||
}
|
||||
|
||||
private Map<Long, List<FeatureResourceDTO>> listProductFeatureResource(List<Long> productIds) {
|
||||
|
||||
if (CollectionUtils.isEmpty(productIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
PageProductFeatureRelationReq pageProductFeatureRelationReq = PageProductFeatureRelationReq.builder()
|
||||
.productModuleIds(difference)
|
||||
.productModuleIds(Sets.newHashSet(productIds))
|
||||
.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()
|
||||
return resolveProductFeatureResources(productPermissions).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);
|
||||
private 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;
|
||||
}
|
||||
|
||||
ProductSaasFeatureResourceCacheService.FeatureResourceDTO featureResourceDTO = from(featureResource, relation);
|
||||
List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> featureResourceDTOS = Lists.newArrayList(featureResourceDTO);
|
||||
|
||||
List<ProductSaasFeatureResourceCacheService.FeatureResourceDTO> parentPermissions = featureResource.resolvePath().stream()
|
||||
.map(parentFeatureResources::get)
|
||||
.filter(Objects::nonNull)
|
||||
.map(f -> {
|
||||
|
||||
if (StringUtils.isBlank(f.getUniCode())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return from(featureResource, relation);
|
||||
})
|
||||
.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 ProductSaasFeatureResourceCacheService.FeatureResourceDTO from(SaasFeatureResourceResp featureResource,
|
||||
SaasProductModuleFeatureRelation relation) {
|
||||
return ProductSaasFeatureResourceCacheService.FeatureResourceDTO.builder()
|
||||
.featureId(featureResource.getId())
|
||||
.featureType(featureResource.getFeatureType())
|
||||
.terminal(featureResource.getTerminal())
|
||||
.uniCode(featureResource.getUniCode())
|
||||
.cooperateType(relation.getDictCode())
|
||||
.build();
|
||||
}
|
||||
|
||||
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)
|
||||
.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)
|
||||
.build();
|
||||
return saasFeatureResourceService.list(pageSaasFeatureResourceReq).stream()
|
||||
.collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity(), (f, s) -> s));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,208 +1,333 @@
|
||||
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.ListRoleReq;
|
||||
import cn.axzo.basics.common.exception.ServiceException;
|
||||
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.inner.CacheRolePermissionHandler;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeature;
|
||||
import cn.axzo.tyr.server.service.RolePermissionCacheService;
|
||||
import cn.axzo.tyr.server.service.RoleService;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import cn.hutool.core.lang.Pair;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
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.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.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.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
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;
|
||||
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.OLD_FEATURE;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RefreshScope
|
||||
public class RolePermissionCacheServiceImpl implements RolePermissionCacheService {
|
||||
|
||||
private static final String ROLE_PERMISSION_KEY = "role:permission:%s";
|
||||
|
||||
@Autowired
|
||||
protected StringRedisTemplate redisTemplate;
|
||||
@Autowired
|
||||
private RoleService roleService;
|
||||
@Autowired
|
||||
private CacheRolePermissionHandler cacheRolePermissionHandler;
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
@Autowired
|
||||
private SaasFeatureDao saasFeatureDao;
|
||||
|
||||
private LoadingCache<Long, Optional<List<PermissionDTO>>> rolePermissionCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.DAYS)
|
||||
.maximumSize(5000)
|
||||
.build(new CacheLoader<Long, Optional<List<PermissionDTO>>>() {
|
||||
@Override
|
||||
public Optional<List<PermissionDTO>> load(Long roleId) {
|
||||
return listRolePermission(Lists.newArrayList(roleId))
|
||||
.values()
|
||||
.stream()
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
/** 角色权限缓存过期时间 **/
|
||||
@Value("${role.permission.expire.minutes:14}")
|
||||
private Long expireInMinutes;
|
||||
@Override
|
||||
public Map<Long, Optional<List<PermissionDTO>>> loadAll(Iterable keys) throws Exception {
|
||||
List<Long> roleIds = Lists.newArrayList(keys);
|
||||
|
||||
Map<Long, List<PermissionDTO>> rolePermissions = listRolePermission(roleIds);
|
||||
|
||||
return Maps.toMap(roleIds, roleId -> Optional.ofNullable(rolePermissions.get(roleId)));
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public Map<Long, List<PermissionDTO>> list(ListRolePermissionParam param) {
|
||||
if (CollectionUtils.isEmpty(param.getRoleIds())) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<Long, List<PermissionDTO>> rolePermissions;
|
||||
try {
|
||||
rolePermissions = rolePermissionCache.getAll(param.getRoleIds()).entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().orElseGet(Lists::newArrayList)));
|
||||
} catch (ExecutionException ex) {
|
||||
log.error("list role cache permission error:{} error", param.getRoleIds(), ex);
|
||||
// 外面有做降级
|
||||
throw new ServiceException("查询角色权限缓存异常");
|
||||
}
|
||||
|
||||
Map<Long, List<PermissionDTO>> permissions = listRolePermissionCached(param);
|
||||
if (CollectionUtils.isEmpty(param.getFeatureCodes())) {
|
||||
return rolePermissions;
|
||||
}
|
||||
|
||||
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)
|
||||
return rolePermissions.entrySet()
|
||||
.stream()
|
||||
.map(e -> Pair.of(e.getKey(), e.getValue().stream()
|
||||
.filter(permission -> param.getFeatureCodes().contains(permission.getFeatureCode()))
|
||||
.collect(Collectors.toList()))
|
||||
)
|
||||
.filter(e -> !CollectionUtils.isEmpty(e.getValue()))
|
||||
.collect(Collectors.toMap(Pair::getKey, Pair::getValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void store(StoreRolePermissionParam param) {
|
||||
|
||||
Axssert.check(param.getRolePermissions().stream().allMatch(e -> Objects.nonNull(e.getRoleId())), REDIS_ROLE_NOT_NULL);
|
||||
|
||||
redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
|
||||
|
||||
connection.openPipeline();
|
||||
|
||||
for (RolePermission rolePermission : param.getRolePermissions()) {
|
||||
String redisKey = getKey(rolePermission.getRoleId());
|
||||
|
||||
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())));
|
||||
|
||||
// 存在hash中部分key移除,为了处理快,直接把redisKey删除掉,修改不频繁
|
||||
redisTemplate.delete(redisKey);
|
||||
RedisClient.HashOps.hPutAll(redisKey, redisValues);
|
||||
redisTemplate.expire(redisKey, expireInMinutes, TimeUnit.MINUTES);
|
||||
log.info("succeed to store role permission: redisKey:{} value:{}", redisKey, redisValues);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Long> hasRoleIds(HasRolePermissionParam 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);
|
||||
operations.hasKey(redisKey);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
return Streams.zip(param.getRoleIds().stream(),
|
||||
redisValues.stream(),
|
||||
(roleId, redisValue) -> Pair.of(roleId, redisValue))
|
||||
.filter(e -> BooleanUtils.isTrue((Boolean) e.getValue()))
|
||||
.map(Pair::getKey)
|
||||
.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()) {
|
||||
public void refreshCache(RefreshRolePermissionCacheParam param) {
|
||||
if (CollectionUtils.isEmpty(param.getRoleIds())) {
|
||||
return;
|
||||
}
|
||||
Map<Long, List<PermissionDTO>> rolePermissions = listRolePermission(Lists.newArrayList(param.getRoleIds()));
|
||||
rolePermissionCache.putAll(Maps.toMap(param.getRoleIds(), roleId -> Optional.ofNullable(rolePermissions.get(roleId))));
|
||||
}
|
||||
|
||||
ListRoleReq listSaasRoleParam = ListRoleReq.builder()
|
||||
.roleIds(Lists.newArrayList(difference))
|
||||
private Map<Long, List<PermissionDTO>> listRolePermission(List<Long> roleIds) {
|
||||
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
|
||||
.roleIds(roleIds)
|
||||
.needPermissionRelation(true)
|
||||
.build();
|
||||
List<SaasRoleRes> roles = roleService.list(listSaasRoleParam);
|
||||
|
||||
if (CollectionUtils.isEmpty(roles)) {
|
||||
return;
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
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);
|
||||
return resolveRolePermission(roles).stream()
|
||||
.collect(Collectors.toMap(RolePermissionCacheService.RolePermission::getRoleId,
|
||||
RolePermissionCacheService.RolePermission::getPermissions));
|
||||
}
|
||||
|
||||
private String getKey(Object... params) {
|
||||
return String.format(ROLE_PERMISSION_KEY, params);
|
||||
private 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;
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<RolePermissionCacheService.PermissionDTO> permissionDTOS = featureResource.getSaasPageElements().stream()
|
||||
.map(pageElement -> RolePermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(featureResource.getId())
|
||||
.featureCode(pageElement.getCode())
|
||||
.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 -> {
|
||||
|
||||
if (CollectionUtils.isEmpty(featureResource.getSaasPageElements())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return featureResource.getSaasPageElements().stream()
|
||||
.map(pageElement -> RolePermissionCacheService.PermissionDTO.builder()
|
||||
.featureId(f.getId())
|
||||
.featureCode(pageElement.getCode())
|
||||
.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)
|
||||
.needPageElement(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)
|
||||
.needPageElement(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()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,59 +1,73 @@
|
||||
package cn.axzo.tyr.server.service.impl;
|
||||
|
||||
import cn.axzo.foundation.exception.Axssert;
|
||||
import cn.axzo.pokonyan.config.redis.RedisClient;
|
||||
import cn.axzo.basics.common.exception.ServiceException;
|
||||
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
|
||||
import cn.axzo.tyr.client.model.req.ListRoleReq;
|
||||
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.inner.CacheRoleSaasFeatureResourceHandler;
|
||||
import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService;
|
||||
import cn.axzo.tyr.server.service.RoleService;
|
||||
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
|
||||
import cn.hutool.core.lang.Pair;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
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.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.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
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;
|
||||
import static cn.axzo.tyr.server.service.impl.ProductSaasFeatureResourceCacheServiceImpl.FEATURE_RESOURCE_TYPES;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RefreshScope
|
||||
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;
|
||||
private SaasFeatureResourceService saasFeatureResourceService;
|
||||
|
||||
|
||||
/** 角色菜单缓存过期时间 **/
|
||||
@Value("${role.feature.resource.expire.minutes:14}")
|
||||
private Long expireInMinutes;
|
||||
private LoadingCache<Long, Optional<List<SaasFeatureResourceDTO>>> roleFeatureResourceCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.DAYS)
|
||||
.maximumSize(5000)
|
||||
.build(new CacheLoader<Long, Optional<List<SaasFeatureResourceDTO>>>() {
|
||||
@Override
|
||||
public Optional<List<SaasFeatureResourceDTO>> load(Long roleId) {
|
||||
return listRoleFeatureResource(Lists.newArrayList(roleId))
|
||||
.values()
|
||||
.stream()
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, Optional<List<SaasFeatureResourceDTO>>> loadAll(Iterable keys) throws Exception {
|
||||
List<Long> roleIds = Lists.newArrayList(keys);
|
||||
|
||||
Map<Long, List<SaasFeatureResourceDTO>> roleFeatureResources = listRoleFeatureResource(roleIds);
|
||||
|
||||
return Maps.toMap(roleIds, roleId -> Optional.ofNullable(roleFeatureResources.get(roleId)));
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public Map<Long, List<SaasFeatureResourceDTO>> list(ListRoleSaasFeatureResourceParam param) {
|
||||
@ -61,94 +75,49 @@ public class RoleSaasFeatureResourceCacheServiceImpl implements RoleSaasFeatureR
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<Long, List<SaasFeatureResourceDTO>> featureResources = listRoleSaasFeatureResourceCached(param);
|
||||
Map<Long, List<SaasFeatureResourceDTO>> roleFeatureResources;
|
||||
try {
|
||||
roleFeatureResources = roleFeatureResourceCache.getAll(param.getRoleIds()).entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().orElseGet(Lists::newArrayList)));
|
||||
} catch (ExecutionException ex) {
|
||||
log.error("list role cache featureResource error:{} error", param.getRoleIds(), ex);
|
||||
// 外面有做降级
|
||||
throw new ServiceException("查询角色菜单缓存异常");
|
||||
}
|
||||
|
||||
fillCacheRoleFeatureResources(param, featureResources);
|
||||
return featureResources;
|
||||
}
|
||||
if (CollectionUtils.isEmpty(param.getUniCodes())) {
|
||||
return roleFeatureResources;
|
||||
}
|
||||
|
||||
@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, expireInMinutes, TimeUnit.MINUTES);
|
||||
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)
|
||||
return roleFeatureResources.entrySet()
|
||||
.stream()
|
||||
.map(e -> Pair.of(e.getKey(), e.getValue().stream()
|
||||
.filter(permission -> param.getUniCodes().contains(permission.getUniCode()))
|
||||
.collect(Collectors.toList()))
|
||||
)
|
||||
.filter(e -> !CollectionUtils.isEmpty(e.getValue()))
|
||||
.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()) {
|
||||
@Override
|
||||
public void refreshCache(RefreshRoleFeatureResourceCacheParam param) {
|
||||
if (CollectionUtils.isEmpty(param.getRoleIds())) {
|
||||
return;
|
||||
}
|
||||
Map<Long, List<SaasFeatureResourceDTO>> roleFeatureResources = listRoleFeatureResource(Lists.newArrayList(param.getRoleIds()));
|
||||
|
||||
ListRoleReq listSaasRoleParam = ListRoleReq.builder()
|
||||
.roleIds(Lists.newArrayList(difference))
|
||||
roleFeatureResourceCache.putAll(Maps.toMap(param.getRoleIds(), roleId -> Optional.ofNullable(roleFeatureResources.get(roleId))));
|
||||
}
|
||||
|
||||
private Map<Long, List<SaasFeatureResourceDTO>> listRoleFeatureResource(List<Long> roleIds) {
|
||||
|
||||
if (CollectionUtils.isEmpty(roleIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
RoleService.ListSaasRoleParam listSaasRoleParam = RoleService.ListSaasRoleParam.builder()
|
||||
.roleIds(roleIds)
|
||||
.needPermissionRelation(true)
|
||||
.type(NEW_FEATURE)
|
||||
.featureResourceTypes(Lists.newArrayList(FeatureResourceType.MENU,
|
||||
@ -160,26 +129,122 @@ public class RoleSaasFeatureResourceCacheServiceImpl implements RoleSaasFeatureR
|
||||
List<SaasRoleRes> roles = roleService.list(listSaasRoleParam);
|
||||
|
||||
if (CollectionUtils.isEmpty(roles)) {
|
||||
return;
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
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()
|
||||
return resolveRoleFeatureResource(roles).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);
|
||||
private 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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package cn.axzo.tyr.server.service.impl;
|
||||
|
||||
import cn.axzo.basics.common.BeanMapper;
|
||||
import cn.axzo.basics.common.exception.ServiceException;
|
||||
import cn.axzo.basics.common.util.StopWatchUtil;
|
||||
import cn.axzo.basics.common.util.TreeUtil;
|
||||
import cn.axzo.foundation.dao.support.converter.PageConverter;
|
||||
@ -10,7 +11,6 @@ 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;
|
||||
@ -50,29 +50,23 @@ 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.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
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.cloud.context.config.annotation.RefreshScope;
|
||||
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;
|
||||
|
||||
@ -82,7 +76,9 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
@ -117,16 +113,34 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
|
||||
private final MqProducer mqProducer;
|
||||
private final SaasFeatureDao saasFeatureDao;
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate<String, String> redisTemplate;
|
||||
|
||||
/** 菜单树过期时间 **/
|
||||
@Value("${saas.feature.resource.expire.minutes:14}")
|
||||
private Long expireInMinutes;
|
||||
|
||||
private static final String SAAS_FEATURE_RESOURCE_KEY = "saas:feature:resource:%s";
|
||||
|
||||
private static final String TARGET_TYPE = "saasFeatureResourceId";
|
||||
/**
|
||||
* 分组这些菜单节点没有版本号,默认为0,方便权限过滤
|
||||
*/
|
||||
private static final int DEFAULT_VERSION = 0;
|
||||
|
||||
private LoadingCache<String, Optional<List<SaasFeatureResourceCache>>> featureResourceCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(1, TimeUnit.DAYS)
|
||||
.maximumSize(5000)
|
||||
.build(new CacheLoader<String, Optional<List<SaasFeatureResourceCache>>>() {
|
||||
@Override
|
||||
public Optional<List<SaasFeatureResourceCache>> load(String terminal) {
|
||||
return listFeatureSources(Lists.newArrayList(terminal))
|
||||
.values()
|
||||
.stream()
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Optional<List<SaasFeatureResourceCache>>> loadAll(Iterable keys) throws Exception {
|
||||
List<String> terminals = Lists.newArrayList(keys);
|
||||
|
||||
Map<String, List<SaasFeatureResourceCache>> featureResources = listFeatureSources(terminals);
|
||||
|
||||
return Maps.toMap(terminals, terminal -> Optional.ofNullable(featureResources.get(terminal)));
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public List<SaasFeatureResource> listNavByIds(List<Long> featureIds, List<Integer> featureTypes) {
|
||||
//按需扩展要查询的字段
|
||||
@ -283,8 +297,13 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
|
||||
} else {
|
||||
//补充path
|
||||
SaasFeatureResource newValue = featureResourceDao.getById(baseResource.getId());
|
||||
SaasFeatureResource dbResource = featureResourceDao.getById(req.getId());
|
||||
baseResource.setPath(dbResource.getPath());
|
||||
if (Objects.nonNull(req.getParentId())) {
|
||||
SaasFeatureResource parent = featureResourceDao.lambdaQuery().eq(SaasFeatureResource::getId,req.getParentId()).one();
|
||||
baseResource.setPath(StringUtils.isBlank(parent.getPath()) ? baseResource.getId().toString() + "," : parent.getPath() + baseResource.getId() + ",");
|
||||
} else {
|
||||
SaasFeatureResource dbResource = featureResourceDao.getById(req.getId());
|
||||
baseResource.setPath(dbResource.getPath());
|
||||
}
|
||||
baseResource.setFeatureCode(req.getUniCode());
|
||||
featureResourceDao.updateById(baseResource);
|
||||
|
||||
@ -368,7 +387,8 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
|
||||
validFeatureName(saasFeatureResource);
|
||||
if (saasFeatureResource.getId() != null) {
|
||||
SaasFeatureResource dbResource = featureResourceDao.getById(saasFeatureResource.getId());
|
||||
saasFeatureResource.setPath(dbResource.getPath());
|
||||
// saasFeatureResource.setPath(dbResource.getPath());
|
||||
saasFeatureResource.setPath(StringUtils.isBlank(parentPath) ? dbResource.getPath() : parentPath + dbResource.getId() + ",");
|
||||
saasFeatureResource.setFeatureCode(featureComponentSaveReq.getUniCode());
|
||||
featureResourceDao.updateById(saasFeatureResource);
|
||||
} else {
|
||||
@ -791,85 +811,44 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
|
||||
});
|
||||
}
|
||||
|
||||
@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,
|
||||
expireInMinutes, TimeUnit.MINUTES);
|
||||
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;
|
||||
|
||||
Map<String, List<SaasFeatureResourceCache>> terminalFeatureResources;
|
||||
try {
|
||||
terminalFeatureResources = featureResourceCache.getAll(param.getTerminals()).entrySet()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().orElseGet(Lists::newArrayList)));
|
||||
} catch (ExecutionException ex) {
|
||||
log.error("list terminal cache featureResource error:{} error", param.getTerminals(), ex);
|
||||
// 外面有做降级
|
||||
throw new ServiceException("查询端的菜单缓存异常");
|
||||
}
|
||||
return terminalFeatureResources;
|
||||
}
|
||||
|
||||
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()) {
|
||||
@Override
|
||||
public void refreshCache(RefreshFeatureResourceCacheParam param) {
|
||||
if (org.springframework.util.CollectionUtils.isEmpty(param.getTerminals())) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<SaasFeatureResourceDTO> saasFeatureResources = resolveSaasFeature(difference);
|
||||
Map<String, List<SaasFeatureResourceCache>> featureResources = listFeatureSources(Lists.newArrayList(param.getTerminals()));
|
||||
|
||||
SaasFeatureResourceService.StoreSaasFeatureResourceCache storeSaasFeatureResourceCache = SaasFeatureResourceService.StoreSaasFeatureResourceCache.builder()
|
||||
.saasFeatureResources(saasFeatureResources)
|
||||
.build();
|
||||
storeCache(storeSaasFeatureResourceCache);
|
||||
featureResourceCache.putAll(Maps.toMap(param.getTerminals(), terminal -> Optional.ofNullable(featureResources.get(terminal))));
|
||||
}
|
||||
|
||||
Map<String, List<SaasFeatureResourceCache>> featureSourceMap = saasFeatureResources.stream()
|
||||
private Map<String, List<SaasFeatureResourceCache>> listFeatureSources(List<String> terminals) {
|
||||
|
||||
if (CollectionUtils.isEmpty(terminals)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
return resolveSaasFeature(Sets.newHashSet(terminals)).stream()
|
||||
.collect(Collectors.toMap(SaasFeatureResourceDTO::getTerminal, SaasFeatureResourceDTO::getFeatures));
|
||||
featureSourceCached.putAll(featureSourceMap);
|
||||
}
|
||||
|
||||
private List<SaasFeatureResourceDTO> resolveSaasFeature(Set<String> terminals) {
|
||||
@ -882,6 +861,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
|
||||
.builder()
|
||||
.featureId(e.getId())
|
||||
.notAuth(DelegatedType.notAuth(e.getDelegatedType()))
|
||||
.parentIds(e.splitPath())
|
||||
.build(), Collectors.toList())));
|
||||
|
||||
List<SaasFeatureResourceDTO> allFeatureResources = Lists.newArrayList();
|
||||
@ -903,6 +883,15 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
|
||||
.builder()
|
||||
.featureId(e.getId())
|
||||
.notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType()))
|
||||
.parentIds(e.resolvePath())
|
||||
.uniCode(e.getUniCode())
|
||||
.status(e.getStatus())
|
||||
.version(Optional.ofNullable(e.getSaasPageElements())
|
||||
.map(pageElement -> pageElement.stream()
|
||||
.findFirst()
|
||||
.map(PageElementResp::getVersion)
|
||||
.orElse(DEFAULT_VERSION))
|
||||
.orElse(DEFAULT_VERSION))
|
||||
.build(), Collectors.toList())))
|
||||
.entrySet().stream()
|
||||
.map(e -> SaasFeatureResourceDTO.builder()
|
||||
@ -915,8 +904,4 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
|
||||
allFeatureResources.addAll(saasFeatureResources);
|
||||
return allFeatureResources;
|
||||
}
|
||||
|
||||
private String getKey(Object... params) {
|
||||
return String.format(SAAS_FEATURE_RESOURCE_KEY, params);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,191 @@
|
||||
package cn.axzo.tyr.server.service.impl;
|
||||
|
||||
import cn.axzo.basics.common.constant.enums.DeleteEnum;
|
||||
import cn.axzo.basics.common.util.AssertUtil;
|
||||
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.model.req.DeletePageElementCategoryReq;
|
||||
import cn.axzo.tyr.client.model.req.PermissionOperateLogReq;
|
||||
import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementCategoryReq;
|
||||
import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp;
|
||||
import cn.axzo.tyr.server.config.MqProducer;
|
||||
import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPageElementCategoryDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPageElementDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPageElementFeatureResourceRelationDao;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElement;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElementCategory;
|
||||
import cn.axzo.tyr.server.service.SaasPageElementCategoryService;
|
||||
import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationOperateLogService;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.axzo.tyr.server.event.inner.EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT;
|
||||
|
||||
/**
|
||||
* @author likunpeng
|
||||
* @version 1.0
|
||||
* @date 2024/8/20
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class SaasPageElementCategoryServiceImpl implements SaasPageElementCategoryService {
|
||||
|
||||
public static final String PAGE_ELEMENT_CATEGORY_TABLE_NAME = "saas_page_element_category";
|
||||
private static final String TARGET_TYPE = "pageElementFeatureResourceId";
|
||||
|
||||
private final SaasPageElementCategoryDao saasPageElementCategoryDao;
|
||||
private final SaasPageElementDao saasPageElementDao;
|
||||
private final SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao;
|
||||
private final SaasPgroupPermissionRelationOperateLogService saasPgroupPermissionRelationOperateLogService;
|
||||
private final MqProducer mqProducer;
|
||||
|
||||
@Override
|
||||
public List<ListPageElementCategoryResp> listGroupByTerminal() {
|
||||
List<ListPageElementCategoryResp> categoryResps = Lists.newArrayList();
|
||||
List<SaasPageElementCategory> categories = saasPageElementCategoryDao.lambdaQuery()
|
||||
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.value)
|
||||
.list();
|
||||
if (CollectionUtils.isEmpty(categories)) {
|
||||
return categoryResps;
|
||||
}
|
||||
Map<String, List<SaasPageElementCategory>> categoryMap = categories.stream().collect(Collectors.groupingBy(SaasPageElementCategory::getTerminal));
|
||||
categoryMap.forEach((key, value) -> {
|
||||
categoryResps.add(ListPageElementCategoryResp.builder().terminal(key)
|
||||
.pageElementCategories(value.stream().map(c -> ListPageElementCategoryResp.PageElementCategoryDTO
|
||||
.builder()
|
||||
.id(c.getId())
|
||||
.itemCode(c.getItemCode())
|
||||
.itemName(c.getItemName())
|
||||
.terminal(c.getTerminal())
|
||||
.build()).collect(Collectors.toList())).build());
|
||||
});
|
||||
return categoryResps;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long saveOrUpdate(SaveOrUpdatePageElementCategoryReq req) {
|
||||
SaasPageElementCategory baseCategory = SaasPageElementCategory.builder()
|
||||
.itemName(req.getItemName())
|
||||
.createBy(req.getOperatorId())
|
||||
.updateBy(req.getOperatorId())
|
||||
.build();
|
||||
validItemName(req.getItemName(), req.getId());
|
||||
|
||||
if (Objects.nonNull(req.getId())) {
|
||||
// 不允许编辑itemCoe,不然端上查询权限点出问题
|
||||
SaasPageElementCategory dbCategory = saasPageElementCategoryDao.getById(req.getId());
|
||||
AssertUtil.notNull(dbCategory, "页面元素分类不存在");
|
||||
baseCategory.setId(req.getId());
|
||||
if (!dbCategory.getItemName().equals(req.getItemName())) {
|
||||
// 更新saas_page_element的item_name
|
||||
saasPageElementDao.updateItemNameByItemCode(dbCategory.getItemCode(), req.getItemName(), dbCategory.getTerminal());
|
||||
}
|
||||
saasPageElementCategoryDao.updateById(baseCategory);
|
||||
} else {
|
||||
AssertUtil.notEmpty(req.getItemCode(), "项目编码不能为空");
|
||||
validItemCode(req.getItemCode());
|
||||
baseCategory.setItemCode(req.getItemCode());
|
||||
baseCategory.setTerminal(req.getTerminal());
|
||||
saasPageElementCategoryDao.save(baseCategory);
|
||||
}
|
||||
|
||||
try {
|
||||
saveOrUpdateOperateLog(req, baseCategory);
|
||||
} catch (Exception e) {
|
||||
log.warn("save operate log error", e);
|
||||
}
|
||||
|
||||
return baseCategory.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(DeletePageElementCategoryReq req) {
|
||||
SaasPageElementCategory dbCategory = saasPageElementCategoryDao.getById(req.getId());
|
||||
AssertUtil.notNull(dbCategory, "页面元素分类不存在");
|
||||
saasPageElementCategoryDao.lambdaUpdate()
|
||||
.eq(BaseEntity::getId, req.getId())
|
||||
.set(SaasPageElementCategory::getIsDelete, DeleteEnum.DELETE.getValue())
|
||||
.set(SaasPageElementCategory::getUpdateBy, req.getOperatorId())
|
||||
.update();
|
||||
|
||||
// 删除页面元素
|
||||
List<SaasPageElement> pageElements = saasPageElementDao.listByItemCodeAndTerminal(dbCategory.getItemCode(), dbCategory.getTerminal());
|
||||
if (CollectionUtils.isEmpty(pageElements)) {
|
||||
return;
|
||||
}
|
||||
List<Long> pageElementIds = pageElements.stream().map(BaseEntity::getId).collect(Collectors.toList());
|
||||
saasPageElementDao.deleteIdsByTerminal(pageElementIds, dbCategory.getTerminal());
|
||||
|
||||
// 删除页面元素绑定关系
|
||||
List<String> pageElementCodes = pageElements.stream().map(SaasPageElement::getCode).collect(Collectors.toList());
|
||||
saasPageElementFeatureResourceRelationDao.deleteByTerminalAndPageElementCodes(dbCategory.getTerminal(), pageElementCodes, req.getOperatorId());
|
||||
|
||||
try {
|
||||
saveDeleteOperateLog(req, dbCategory);
|
||||
} 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(dbCategory.getTerminal())
|
||||
.build())
|
||||
.build();
|
||||
mqProducer.send(event);
|
||||
}
|
||||
|
||||
private void validItemCode(String itemCode) {
|
||||
List<SaasPageElementCategory> categories = saasPageElementCategoryDao.lambdaQuery()
|
||||
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.value)
|
||||
.eq(SaasPageElementCategory::getItemCode, itemCode)
|
||||
.list();
|
||||
AssertUtil.isEmpty(categories, "项目编码已存在");
|
||||
}
|
||||
|
||||
private void validItemName(String itemName, Long categoryId) {
|
||||
List<SaasPageElementCategory> categories = saasPageElementCategoryDao.lambdaQuery()
|
||||
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.value)
|
||||
.eq(SaasPageElementCategory::getItemName, itemName)
|
||||
.ne(Objects.nonNull(categoryId), BaseEntity::getId, categoryId)
|
||||
.list();
|
||||
AssertUtil.isEmpty(categories, "项目名称已存在");
|
||||
}
|
||||
|
||||
private void saveOrUpdateOperateLog(SaveOrUpdatePageElementCategoryReq req, SaasPageElementCategory baseCategory) {
|
||||
saasPgroupPermissionRelationOperateLogService.save(PermissionOperateLogReq.builder()
|
||||
.tableName(PAGE_ELEMENT_CATEGORY_TABLE_NAME)
|
||||
.operatorId(req.getOperatorId())
|
||||
.scene(PermissionRelationOperateLogSceneEnum.OMS_UPSERT_PAGE_ELEMENT_CATEGORY.getValue())
|
||||
.sceneId(baseCategory.getId().toString())
|
||||
.requestData(req)
|
||||
.operateData(baseCategory)
|
||||
.build());
|
||||
}
|
||||
|
||||
private void saveDeleteOperateLog(DeletePageElementCategoryReq req, SaasPageElementCategory baseCategory) {
|
||||
saasPgroupPermissionRelationOperateLogService.save(PermissionOperateLogReq.builder()
|
||||
.tableName(PAGE_ELEMENT_CATEGORY_TABLE_NAME)
|
||||
.operatorId(req.getOperatorId())
|
||||
.scene(PermissionRelationOperateLogSceneEnum.OMS_DELETE_PAGE_ELEMENT_CATEGORY.getValue())
|
||||
.sceneId(baseCategory.getId().toString())
|
||||
.requestData(req)
|
||||
.operateData(baseCategory)
|
||||
.build());
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,10 @@
|
||||
package cn.axzo.tyr.server.service.impl;
|
||||
|
||||
import cn.axzo.basics.common.BeanMapper;
|
||||
import cn.axzo.basics.common.constant.enums.DeleteEnum;
|
||||
import cn.axzo.basics.common.util.AssertUtil;
|
||||
import cn.axzo.basics.common.util.StopWatchUtil;
|
||||
import cn.axzo.basics.common.util.TreeUtil;
|
||||
import cn.axzo.basics.profiles.api.UserProfileServiceApi;
|
||||
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
|
||||
import cn.axzo.foundation.dao.support.converter.PageConverter;
|
||||
@ -12,31 +14,41 @@ 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.PageElementAppTypeEnum;
|
||||
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.DeletePageElementReq;
|
||||
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.PageElementFeatureResourceRelationReq;
|
||||
import cn.axzo.tyr.client.model.req.PageElementImportDataReq;
|
||||
import cn.axzo.tyr.client.model.req.PageElementReportReq;
|
||||
import cn.axzo.tyr.client.model.req.PageElementReq;
|
||||
import cn.axzo.tyr.client.model.req.PageQueryElementReq;
|
||||
import cn.axzo.tyr.client.model.req.PageQueryElementV2Req;
|
||||
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
|
||||
import cn.axzo.tyr.client.model.req.PermissionOperateLogReq;
|
||||
import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementReq;
|
||||
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.PageElementCategoryAndElementResp;
|
||||
import cn.axzo.tyr.client.model.res.PageElementRelationFeatureResourceResp;
|
||||
import cn.axzo.tyr.client.model.res.PageElementResp;
|
||||
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
|
||||
import cn.axzo.tyr.server.config.MqProducer;
|
||||
import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload;
|
||||
import cn.axzo.tyr.server.model.RelationOperateLogResourceBindElementDO;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPageElementCategoryDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPageElementDao;
|
||||
import cn.axzo.tyr.server.repository.dao.SaasPageElementFeatureResourceRelationDao;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElement;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElementCategory;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation;
|
||||
import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelationOperateLog;
|
||||
import cn.axzo.tyr.server.repository.mapper.SaasPageElementMapper;
|
||||
@ -51,10 +63,13 @@ import cn.hutool.json.JSONUtil;
|
||||
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.conditions.query.LambdaQueryChainWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
@ -69,10 +84,12 @@ import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Arrays;
|
||||
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.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
@ -97,11 +114,12 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
|
||||
private final SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao;
|
||||
private final SaasFeatureResourceDao saasFeatureResourceDao;
|
||||
private final TyrSaasAuthService tyrSaasAuthService;
|
||||
private final MqProducer mqProducer;
|
||||
private final SaasPgroupPermissionRelationOperateLogService saasPgroupPermissionRelationOperateLogService;
|
||||
private final UserProfileServiceApi userProfileServiceApi;
|
||||
private final MqProducer mqProducer;
|
||||
private final SaasFeatureResourceService saasFeatureResourceService;
|
||||
private final SaasPageElementFeatureResourceRelationService saasPageElementFeatureResourceRelationService;
|
||||
private final SaasPageElementCategoryDao saasPageElementCategoryDao;
|
||||
|
||||
@Qualifier("asyncExecutor")
|
||||
@Autowired
|
||||
@ -112,6 +130,7 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
|
||||
private List<String> reportSecretKeys;
|
||||
|
||||
private static final String TARGET_TYPE = "pageElementFeatureResourceId";
|
||||
public static final String PAGE_ELEMENT_TABLE_NAME = "saas_page_element";
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@ -243,17 +262,21 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResp<PageElementResp> page(PageQueryElementReq request) {
|
||||
public PageResp<PageElementCategoryAndElementResp> page(PageQueryElementReq request) {
|
||||
IPage<SaasPageElement> page = saasPageElementDao.lambdaQuery()
|
||||
.eq(SaasPageElement::getTerminal, request.getTerminal())
|
||||
.in(CollectionUtils.isNotEmpty(request.getElementTypes()), SaasPageElement::getType, request.getElementTypes())
|
||||
.and(StringUtils.isNotBlank(request.getSearchKey()), w -> w.like(SaasPageElement::getCode, request.getSearchKey())
|
||||
.or().like(SaasPageElement::getName, request.getSearchKey())
|
||||
.or().like(SaasPageElement::getLinkUrl, request.getSearchKey()))
|
||||
.or().like(SaasPageElement::getLinkUrl, request.getSearchKey())
|
||||
.or().like(SaasPageElement::getItemCode, request.getSearchKey())
|
||||
.or().like(SaasPageElement::getItemName, request.getSearchKey()))
|
||||
.page(new Page<>(request.getPage(), request.getPageSize()));
|
||||
List<PageElementResp> list = BeanMapper.copyList(page.getRecords(), PageElementResp.class);
|
||||
addComponentElement2Page(request.getTerminal(), list);
|
||||
return PageResp.list(page.getCurrent(), page.getSize(), page.getTotal(), list);
|
||||
|
||||
List<PageElementCategoryAndElementResp> categoryAndElementResps = changeElementWithCategories(list);
|
||||
return PageResp.list(page.getCurrent(), page.getSize(), page.getTotal(), categoryAndElementResps);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -326,6 +349,9 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
|
||||
.name(pageElement.getName())
|
||||
.linkUrl(pageElement.getLinkUrl())
|
||||
.createName(request.getCreateName())
|
||||
.appType(PageElementAppTypeEnum.PC.name())
|
||||
.itemCode("CMS_COMMON")
|
||||
.itemName("单位组织")
|
||||
.build());
|
||||
|
||||
if (CollectionUtils.isNotEmpty(pageElement.getChildren())) {
|
||||
@ -336,6 +362,9 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
|
||||
.type(e.getType())
|
||||
.name(e.getName())
|
||||
.createName(request.getCreateName())
|
||||
.appType(PageElementAppTypeEnum.PC.name())
|
||||
.itemCode("CMS_COMMON")
|
||||
.itemName("单位组织")
|
||||
.build()).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
@ -378,6 +407,8 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
|
||||
List<PageElementResp> pageTypeElements = pageElements.stream().filter(e -> PageElementTypeEnum.PAGE.getCode().equals(e.getType()))
|
||||
.map(e -> PageElementResp.builder()
|
||||
.id(e.getId())
|
||||
.groupCode(e.getGroupCode())
|
||||
.groupName(e.getName())
|
||||
.code(e.getCode())
|
||||
.name(e.getName())
|
||||
.type(e.getType())
|
||||
@ -395,6 +426,8 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
|
||||
if (Objects.nonNull(pageTypeElement)) {
|
||||
pageTypeElement.getChildren().add(PageElementResp.builder()
|
||||
.id(e.getId())
|
||||
.groupCode(pageTypeElement.getGroupCode())
|
||||
.groupName(pageTypeElement.getGroupName())
|
||||
.code(e.getCode())
|
||||
.name(e.getName())
|
||||
.type(e.getType())
|
||||
@ -503,6 +536,252 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
|
||||
return PageConverter.toResp(page, e -> from(e, featureResources));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResp<PageElementResp> pageV2(PageQueryElementV2Req request) {
|
||||
LambdaQueryChainWrapper<SaasPageElement> wrapper = saasPageElementDao.lambdaQuery()
|
||||
.eq(Objects.nonNull(request.getId()), SaasPageElement::getId, request.getId())
|
||||
.eq(StringUtils.isNotBlank(request.getTerminal()), SaasPageElement::getTerminal, request.getTerminal())
|
||||
.eq(StringUtils.isNotBlank(request.getItemCode()), SaasPageElement::getItemCode, request.getItemCode())
|
||||
.in(CollectionUtils.isNotEmpty(request.getElementTypes()), SaasPageElement::getType, request.getElementTypes())
|
||||
.and(StringUtils.isNotBlank(request.getPageElementCodeOrName()), w -> w.like(SaasPageElement::getCode, request.getPageElementCodeOrName())
|
||||
.or().like(SaasPageElement::getName, request.getPageElementCodeOrName()));
|
||||
|
||||
|
||||
// 待切换写法,收口page,pageV2查询
|
||||
// 因为页面名字没有每条记录冗余,查询条件可能是页面名字或者code,所以需要根据入参找到对应的页面code,然后作为页面code查询
|
||||
if (StringUtils.isNotBlank(request.getPageElementGroupCodeOrName())) {
|
||||
List<SaasPageElement> groupPageElements = saasPageElementDao.lambdaQuery()
|
||||
.eq(SaasPageElement::getType, PageElementTypeEnum.PAGE.getCode())
|
||||
.and(w -> w.like(SaasPageElement::getGroupCode, request.getPageElementGroupCodeOrName())
|
||||
.or()
|
||||
.like(SaasPageElement::getName, request.getPageElementGroupCodeOrName()))
|
||||
.list();
|
||||
if (CollectionUtils.isEmpty(groupPageElements)) {
|
||||
return request.toEmpty();
|
||||
}
|
||||
|
||||
wrapper.in(SaasPageElement::getGroupCode, groupPageElements.stream().map(SaasPageElement::getGroupCode).collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
IPage<SaasPageElement> page = wrapper.orderByDesc(BaseEntity::getId)
|
||||
.page(new Page<>(request.getPage(), request.getPageSize()));
|
||||
|
||||
List<PageElementResp> list = BeanMapper.copyList(page.getRecords(), PageElementResp.class);
|
||||
// 补充元素组名
|
||||
fillGroupName(list);
|
||||
// 补充元素ios、android路由地址
|
||||
fillIosAndAndroidRouteUrl(list);
|
||||
return PageResp.list(page.getCurrent(), page.getSize(), page.getTotal(), list);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long saveOrUpdate(SaveOrUpdatePageElementReq req) {
|
||||
SaasPageElement basePageElement = SaasPageElement.builder()
|
||||
.version(req.getVersion())
|
||||
.groupCode(req.getCode())
|
||||
.code(req.getCode())
|
||||
.name(req.getName())
|
||||
.type(req.getType())
|
||||
.linkUrl(req.getLinkUrl())
|
||||
.linkExt(getLinkExtStr(req.getIosRouterUrl(), req.getAndroidRouterUrl()))
|
||||
.appType(req.getAppType())
|
||||
.appId(req.getAppId())
|
||||
.itemCode(req.getItemCode())
|
||||
.build();
|
||||
|
||||
if (Objects.nonNull(req.getId())) {
|
||||
SaasPageElement dbPageElement = saasPageElementDao.getById(req.getId());
|
||||
AssertUtil.notNull(dbPageElement, "页面元素资源不存在");
|
||||
basePageElement.setId(dbPageElement.getId());
|
||||
if (!dbPageElement.getCode().equals(basePageElement.getCode())) {
|
||||
// 校验code唯一
|
||||
validCode(basePageElement.getCode());
|
||||
if (PageElementTypeEnum.PAGE.getCode().equals(req.getType())) {
|
||||
// 更新子元素的group_code
|
||||
saasPageElementDao.updateComponentsGroupCode(dbPageElement.getCode(), basePageElement.getCode(), dbPageElement.getTerminal());
|
||||
}
|
||||
// 更新关联关系的page_element_code
|
||||
saasPageElementFeatureResourceRelationDao.updateGroupCode(dbPageElement.getCode(), basePageElement.getCode(), dbPageElement.getTerminal());
|
||||
}
|
||||
saasPageElementDao.updateById(basePageElement);
|
||||
} else {
|
||||
if (PageElementTypeEnum.PAGE.getCode().equals(req.getType())) {
|
||||
AssertUtil.isTrue(StringUtils.isNotBlank(req.getItemCode()), "页面元素不存在");
|
||||
List<SaasPageElementCategory> categories = saasPageElementCategoryDao.lambdaQuery()
|
||||
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue())
|
||||
.eq(SaasPageElementCategory::getItemCode, req.getItemCode()).list();
|
||||
AssertUtil.notEmpty(categories, "元素分类不存在。");
|
||||
SaasPageElementCategory category = categories.get(0);
|
||||
basePageElement.setTerminal(category.getTerminal());
|
||||
basePageElement.setItemName(category.getItemName());
|
||||
} else if (PageElementTypeEnum.COMPONENT.getCode().equals(req.getType())) {
|
||||
AssertUtil.isTrue(StringUtils.isNotBlank(req.getGroupCode()), "页面元素不存在");
|
||||
List<SaasPageElement> pageElements = saasPageElementDao.lambdaQuery()
|
||||
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue())
|
||||
.eq(SaasPageElement::getCode, req.getGroupCode()).list();
|
||||
AssertUtil.notEmpty(pageElements, "父级元素不存在。");
|
||||
|
||||
SaasPageElement pageElement = pageElements.get(0);
|
||||
basePageElement.setVersion(pageElement.getVersion());
|
||||
basePageElement.setGroupCode(pageElement.getCode());
|
||||
basePageElement.setTerminal(pageElement.getTerminal());
|
||||
basePageElement.setAppType(pageElement.getAppType());
|
||||
basePageElement.setAppId(pageElement.getAppId());
|
||||
basePageElement.setItemCode(pageElement.getItemCode());
|
||||
basePageElement.setItemName(pageElement.getItemName());
|
||||
}
|
||||
// 校验code唯一
|
||||
validCode(basePageElement.getCode());
|
||||
saasPageElementDao.save(basePageElement);
|
||||
}
|
||||
|
||||
// 记录操作日志
|
||||
try {
|
||||
saveOrUpdateOperateLog(req, basePageElement);
|
||||
} catch (Exception e) {
|
||||
log.warn("save operate log error", e);
|
||||
}
|
||||
|
||||
return basePageElement.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(DeletePageElementReq req) {
|
||||
SaasPageElement dbPageElement = saasPageElementDao.getById(req.getId());
|
||||
AssertUtil.notNull(dbPageElement, "页面元素资源不存在");
|
||||
Set<String> codes = Sets.newHashSet(dbPageElement.getCode());
|
||||
|
||||
if (PageElementTypeEnum.PAGE.getCode().equals(dbPageElement.getType())) {
|
||||
// 删除页面的子元素
|
||||
List<SaasPageElement> pageElements = saasPageElementDao.listByGroupCodesAndExcludeIds(Lists.newArrayList(dbPageElement.getGroupCode()), null, dbPageElement.getTerminal(), null);
|
||||
saasPageElementDao.deleteIdsByTerminal(pageElements.stream().map(BaseEntity::getId).collect(Collectors.toList()), dbPageElement.getTerminal());
|
||||
codes.addAll(pageElements.stream().map(SaasPageElement::getCode).collect(Collectors.toSet()));
|
||||
} else {
|
||||
saasPageElementDao.deleteIdsByTerminal(Lists.newArrayList(req.getId()), dbPageElement.getTerminal());
|
||||
}
|
||||
|
||||
// 删除绑定关系
|
||||
if (CollectionUtils.isNotEmpty(codes)) {
|
||||
saasPageElementFeatureResourceRelationDao.deleteByTerminalAndPageElementCodes(dbPageElement.getTerminal(), Lists.newArrayList(codes), req.getOperatorId());
|
||||
}
|
||||
|
||||
// 记录操作日志
|
||||
try {
|
||||
saveDeleteOperateLog(req, dbPageElement);
|
||||
} 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(dbPageElement.getTerminal())
|
||||
.build())
|
||||
.build();
|
||||
mqProducer.send(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PageElementRelationFeatureResourceResp> getFeatureResourceRelations(Long pageElementId) {
|
||||
SaasPageElement dbPageElement = saasPageElementDao.getById(pageElementId);
|
||||
AssertUtil.notNull(dbPageElement, "页面元素资源不存在");
|
||||
|
||||
List<SaasPageElementFeatureResourceRelation> relations = saasPageElementFeatureResourceRelationDao.lambdaQuery()
|
||||
.eq(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.NORMAL.getValue())
|
||||
.eq(SaasPageElementFeatureResourceRelation::getPageElementCode, dbPageElement.getCode())
|
||||
.eq(SaasPageElementFeatureResourceRelation::getTerminal, dbPageElement.getTerminal())
|
||||
.list();
|
||||
if (CollectionUtils.isEmpty(relations)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<SaasFeatureResource> pageFeatureResources = getPageFeatureResources(dbPageElement.getTerminal(), relations.stream().map(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode).collect(Collectors.toList()));
|
||||
if (CollectionUtils.isEmpty(pageFeatureResources)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<SaasFeatureResource> pageParentFeatureResources = saasFeatureResourceDao.lambdaQuery()
|
||||
.eq(SaasFeatureResource::getTerminal, dbPageElement.getTerminal())
|
||||
.in(SaasFeatureResource::getId, pageFeatureResources.stream().map(SaasFeatureResource::getParentId).collect(Collectors.toSet()))
|
||||
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue())
|
||||
.list();
|
||||
List<SaasFeatureResource> pageChildrenFeatureResources = saasFeatureResourceDao.lambdaQuery()
|
||||
.eq(BaseEntity::getIsDelete,0)
|
||||
.and(i -> pageFeatureResources.forEach(f -> i.or().likeRight(SaasFeatureResource::getPath, f.getPath())))
|
||||
.list();
|
||||
List<SaasFeatureResource> allFeatureResources = Lists.newArrayList(pageFeatureResources);
|
||||
if (CollectionUtils.isNotEmpty(pageParentFeatureResources)) {
|
||||
allFeatureResources.addAll(pageParentFeatureResources);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(pageChildrenFeatureResources)) {
|
||||
allFeatureResources.addAll(pageChildrenFeatureResources);
|
||||
}
|
||||
|
||||
Map<String, SaasPageElementFeatureResourceRelation> uniCodeRelationMap = Maps.newHashMap();
|
||||
List<String> pageRouteUniCodes = Lists.newArrayList();
|
||||
for(SaasPageElementFeatureResourceRelation relation : relations) {
|
||||
if (pageRouteUniCodes.contains(relation.getFeatureResourceUniCode())) {
|
||||
continue;
|
||||
}
|
||||
uniCodeRelationMap.put(relation.getFeatureResourceUniCode(), relation);
|
||||
if (PageElementFeatureResourceRelationTypeEnum.PAGE_ROUTE.getValue().equals(relation.getType())) {
|
||||
pageRouteUniCodes.add(relation.getFeatureResourceUniCode());
|
||||
}
|
||||
}
|
||||
|
||||
List<PageElementRelationFeatureResourceResp> reps = allFeatureResources.stream().map(e -> PageElementRelationFeatureResourceResp.builder()
|
||||
.id(e.getId())
|
||||
.parentId(e.getParentId())
|
||||
.uniCode(e.getUniCode())
|
||||
.featureName(e.getFeatureName())
|
||||
.featureType(e.getFeatureType())
|
||||
.hasRelation(uniCodeRelationMap.containsKey(e.getUniCode()))
|
||||
.relationType(Optional.ofNullable(uniCodeRelationMap.get(e.getUniCode())).map(SaasPageElementFeatureResourceRelation::getType).orElse(null))
|
||||
.build()).distinct().collect(Collectors.toList());
|
||||
|
||||
return TreeUtil.buildTree(reps);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void importData(List<PageElementImportDataReq> req) {
|
||||
log.info("导入资源的数量:{}", req.size());
|
||||
Integer codeCount = saasPageElementDao.lambdaQuery()
|
||||
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue())
|
||||
.in(SaasPageElement::getCode, req.stream().map(PageElementImportDataReq::getCode).collect(Collectors.toList()))
|
||||
.count();
|
||||
AssertUtil.isTrue(codeCount <= 0, "导入的资源编码已存在。");
|
||||
|
||||
Set<String> itemCodes = req.stream().map(PageElementImportDataReq::getItemCode).collect(Collectors.toSet());
|
||||
List<SaasPageElementCategory> categories = saasPageElementCategoryDao.lambdaQuery()
|
||||
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue())
|
||||
.in(SaasPageElementCategory::getItemCode, itemCodes)
|
||||
.list();
|
||||
// AssertUtil.isTrue(itemCodes.size() == categories.size(), "元素分类编码系统中有未存在的。");
|
||||
Map<String, SaasPageElementCategory> categoryMap = categories.stream().collect(Collectors.toMap(SaasPageElementCategory::getItemCode, Function.identity(), (v1, v2) -> v1));
|
||||
List<SaasPageElement> elements = req.stream().map(e -> {
|
||||
SaasPageElementCategory category = categoryMap.get(e.getItemCode());
|
||||
AssertUtil.notNull(category, e.getItemCode() + "不存在。");
|
||||
return SaasPageElement.builder()
|
||||
.version(e.getVersion())
|
||||
.groupCode(e.getGroupCode())
|
||||
.code(e.getCode())
|
||||
.name(e.getName())
|
||||
.type(e.getType())
|
||||
.linkUrl(e.getLinkUrl())
|
||||
.terminal(e.getTerminal())
|
||||
.appType(e.getAppType())
|
||||
.itemCode(e.getItemCode())
|
||||
.itemName(category.getItemName())
|
||||
.createName(Optional.ofNullable(e.getOperatorId()).map(Objects::toString).orElse(StringUtils.EMPTY))
|
||||
.appId(e.getAppId())
|
||||
.build();
|
||||
}).collect(Collectors.toList());
|
||||
Lists.partition(elements,500).forEach(saasPageElementDao::saveBatch);
|
||||
}
|
||||
|
||||
private PageElementResp from(SaasPageElement saasPageElement,
|
||||
Map<String, List<SaasFeatureResourceResp>> featureResources) {
|
||||
PageElementResp pageElementResp = PageElementResp.builder().build();
|
||||
@ -549,4 +828,106 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
|
||||
.collect(Collectors.groupingBy(SaasPageElementFeatureResourceRelation::getPageElementCode,
|
||||
Collectors.mapping(e -> featureResources.get(e.getFeatureResourceUniCode()), Collectors.toList())));
|
||||
}
|
||||
|
||||
private void fillGroupName(List<PageElementResp> list) {
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, SaasPageElement> elementMap = saasPageElementDao.lambdaQuery()
|
||||
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue())
|
||||
.in(SaasPageElement::getCode, list.stream().map(PageElementResp::getGroupCode).distinct().collect(Collectors.toList()))
|
||||
.list().stream().collect(Collectors.toMap(SaasPageElement::getCode, Function.identity(), (v1, v2) -> v1));
|
||||
list.forEach(e -> e.setGroupName(Optional.ofNullable(elementMap.get(e.getGroupCode())).map(SaasPageElement::getName).orElse(StringUtils.EMPTY)));
|
||||
}
|
||||
|
||||
private void validCode(String code) {
|
||||
List<SaasPageElement> pageElements = saasPageElementDao.lambdaQuery()
|
||||
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.value)
|
||||
.eq(SaasPageElement::getCode, code)
|
||||
.list();
|
||||
AssertUtil.isEmpty(pageElements, "featureCode已存在");
|
||||
}
|
||||
|
||||
private String getLinkExtStr(String iosRouterUrl, String androidRouterUrl) {
|
||||
if (StringUtils.isBlank(iosRouterUrl) && StringUtils.isBlank(androidRouterUrl)) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
List<PageElementResp.LinkExt> exts = Lists.newArrayList(PageElementResp.LinkExt.builder().system("ios").routerUrl(Strings.nullToEmpty(iosRouterUrl)).build(),
|
||||
PageElementResp.LinkExt.builder().system("android").routerUrl(Strings.nullToEmpty(androidRouterUrl)).build());
|
||||
return JSONObject.toJSONString(exts);
|
||||
}
|
||||
|
||||
private void fillIosAndAndroidRouteUrl(List<PageElementResp> list) {
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return;
|
||||
}
|
||||
for (PageElementResp resp : list) {
|
||||
if (StringUtils.isBlank(resp.getLinkExt())) {
|
||||
continue;
|
||||
}
|
||||
resp.setIosRouterUrl(resp.resolveIosRouterUrl());
|
||||
resp.setAndroidRouterUrl(resp.resolveAndroidRouterUrl());
|
||||
}
|
||||
}
|
||||
|
||||
private void saveOrUpdateOperateLog(SaveOrUpdatePageElementReq req, SaasPageElement basePageElement) {
|
||||
saasPgroupPermissionRelationOperateLogService.save(PermissionOperateLogReq.builder()
|
||||
.tableName(PAGE_ELEMENT_TABLE_NAME)
|
||||
.operatorId(req.getOperatorId())
|
||||
.scene(PermissionRelationOperateLogSceneEnum.OMS_UPSERT_PAGE_ELEMENT.getValue())
|
||||
.sceneId(basePageElement.getId().toString())
|
||||
.requestData(req)
|
||||
.operateData(basePageElement)
|
||||
.build());
|
||||
}
|
||||
|
||||
private void saveDeleteOperateLog(DeletePageElementReq req, SaasPageElement basePageElement) {
|
||||
saasPgroupPermissionRelationOperateLogService.save(PermissionOperateLogReq.builder()
|
||||
.tableName(PAGE_ELEMENT_TABLE_NAME)
|
||||
.operatorId(req.getOperatorId())
|
||||
.scene(PermissionRelationOperateLogSceneEnum.OMS_DELETE_PAGE_ELEMENT.getValue())
|
||||
.sceneId(basePageElement.getId().toString())
|
||||
.requestData(req)
|
||||
.operateData(basePageElement)
|
||||
.build());
|
||||
}
|
||||
|
||||
private List<PageElementCategoryAndElementResp> changeElementWithCategories(List<PageElementResp> list) {
|
||||
List<PageElementCategoryAndElementResp> resps = Lists.newArrayList();
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return resps;
|
||||
}
|
||||
Map<String, PageElementResp> itemCodeAndElementMap = list.stream().collect(Collectors.toMap(PageElementResp::getItemCode, Function.identity(), (v1, v2) -> v1));
|
||||
Map<String, List<PageElementResp>> groupingByItemCodes = list.stream().collect(Collectors.groupingBy(PageElementResp::getItemCode));
|
||||
groupingByItemCodes.forEach((k, v) -> {
|
||||
PageElementResp resp = itemCodeAndElementMap.get(k);
|
||||
resps.add(PageElementCategoryAndElementResp.builder()
|
||||
.itemCode(k)
|
||||
.itemName(resp.getItemName())
|
||||
.pageElements(v)
|
||||
.build());
|
||||
});
|
||||
|
||||
return resps;
|
||||
}
|
||||
|
||||
private List<SaasFeatureResource> getPageFeatureResources(String terminal, List<String> uniCodes) {
|
||||
List<SaasFeatureResource> pageFeatureResources = saasFeatureResourceDao.lambdaQuery()
|
||||
.eq(SaasFeatureResource::getTerminal, terminal)
|
||||
.in(SaasFeatureResource::getUniCode, uniCodes)
|
||||
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue())
|
||||
.list();
|
||||
|
||||
List<Long> allIds = pageFeatureResources.stream().map(e -> Arrays.stream(e.getPath().split(",")).filter(StringUtils::isNotBlank).map(Long::valueOf)
|
||||
.collect(Collectors.toList())).flatMap(List::stream).distinct().collect(Collectors.toList());
|
||||
|
||||
return saasFeatureResourceDao.lambdaQuery()
|
||||
.eq(SaasFeatureResource::getTerminal, terminal)
|
||||
.in(SaasFeatureResource::getId, allIds)
|
||||
.in(SaasFeatureResource::getFeatureType, Lists.newArrayList(FeatureResourceType.PAGE.getCode(), FeatureResourceType.APP_ENTRY.getCode()))
|
||||
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue())
|
||||
.list();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -240,9 +240,11 @@ public class WorkspaceProductServiceImpl implements WorkspaceProductService {
|
||||
List<WorkspaceProductDTO> workspaceProductDTOS = Lists.newArrayList();
|
||||
|
||||
servicePkgDetailRes.forEach(e -> {
|
||||
Set<Long> workpsaceProductIds = e.getProducts().stream()
|
||||
.map(ServicePkgProduct::getProductId)
|
||||
.collect(Collectors.toSet());
|
||||
Set<Long> workpsaceProductIds = Optional.ofNullable(e.getProducts())
|
||||
.map(products -> products.stream()
|
||||
.map(ServicePkgProduct::getProductId)
|
||||
.collect(Collectors.toSet()))
|
||||
.orElse(null);
|
||||
if (CollectionUtils.isEmpty(workpsaceProductIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user