From 152ebc182f98ee7081b92aeedf5df33cd7153b20 Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 9 Apr 2024 21:12:47 +0800 Subject: [PATCH 1/7] =?UTF-8?q?feat:(REQ-2227)=20=E6=8F=90=E4=BE=9B?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E5=88=86=E7=BB=84=E7=9B=B8=E5=85=B3=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/feign/SaasRoleGroupApi.java | 12 +++- .../model/req/QuerySaasRoleGroupReq.java | 2 + .../model/req/UpdateRoleGroupOffsetReq.java | 27 ++++++++ .../role/SaasRoleGroupController.java | 63 +++++++++++++++++++ .../repository/dao/SaasRoleGroupDao.java | 2 + .../impl/SaasRoleGroupServiceImpl.java | 45 ++++++++++++- 6 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/UpdateRoleGroupOffsetReq.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/SaasRoleGroupApi.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/SaasRoleGroupApi.java index c261b38e..8adf14bb 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/SaasRoleGroupApi.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/SaasRoleGroupApi.java @@ -2,6 +2,7 @@ package cn.axzo.tyr.client.feign; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.model.req.QuerySaasRoleGroupReq; +import cn.axzo.tyr.client.model.req.UpdateRoleGroupOffsetReq; import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; @@ -9,6 +10,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; +import javax.validation.Valid; import javax.validation.constraints.NotEmpty; import java.util.List; @@ -61,5 +63,13 @@ public interface SaasRoleGroupApi { @GetMapping("/api/saasRoleGroup/listByCategoryCode") ApiResult> listByCategoryCode(@RequestParam("categoryCode") List categoryCodes); - + /** + * 更新角色分组的位置 + * 向下移动,则找到后面位置的分组,替换sort + * 向上移动,则找到前面位置的分组,替换sort + * @param request + * @return + */ + @PostMapping("/role/group/offset/update") + ApiResult updateRoleGroupOffset(@Valid @RequestBody UpdateRoleGroupOffsetReq request); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/QuerySaasRoleGroupReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/QuerySaasRoleGroupReq.java index 2e6cab57..6c732293 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/QuerySaasRoleGroupReq.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/QuerySaasRoleGroupReq.java @@ -44,4 +44,6 @@ public class QuerySaasRoleGroupReq { * 被那些角色使用到的分组 */ private List roleIds; + + private Long parentId; } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/UpdateRoleGroupOffsetReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/UpdateRoleGroupOffsetReq.java new file mode 100644 index 00000000..203eef0c --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/UpdateRoleGroupOffsetReq.java @@ -0,0 +1,27 @@ +package cn.axzo.tyr.client.model.req; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UpdateRoleGroupOffsetReq { + + /** + * 角色分组id + */ + @NotNull(message = "id不能为空") + private Long id; + + /** + * 偏移量:向上移就是负数,例如上移一位:-1,向下移就是正数,例如下移一位:1 + */ + @NotNull(message = "offset不能为空") + private Integer offset; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/role/SaasRoleGroupController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/role/SaasRoleGroupController.java index 994e8e52..6e507ce3 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/role/SaasRoleGroupController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/role/SaasRoleGroupController.java @@ -4,6 +4,7 @@ import cn.axzo.basics.common.exception.ServiceException; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.feign.SaasRoleGroupApi; import cn.axzo.tyr.client.model.req.QuerySaasRoleGroupReq; +import cn.axzo.tyr.client.model.req.UpdateRoleGroupOffsetReq; import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO; import cn.axzo.tyr.server.service.SaasRoleGroupService; import com.google.common.collect.Lists; @@ -12,7 +13,9 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; import org.springframework.web.bind.annotation.RestController; +import java.util.Comparator; import java.util.List; +import java.util.stream.Collectors; @Slf4j @RestController @@ -56,4 +59,64 @@ public class SaasRoleGroupController implements SaasRoleGroupApi { return ApiResult.ok(saasRoleGroupService.listByCategoryCode(categoryCode)); } + @Override + public ApiResult updateRoleGroupOffset(UpdateRoleGroupOffsetReq request) { + if (request.getOffset() != 1 && request.getOffset() != -1) { + throw new ServiceException("暂时只支持移动一个位置"); + } + SaasRoleGroupVO saasRoleGroup = getById(request.getId()).getData(); + + List roleGroupList = saasRoleGroupService.getRoleGroupList(QuerySaasRoleGroupReq.builder() + .parentId(saasRoleGroup.getParentId()) + .workspaceTypeCode(Lists.newArrayList(saasRoleGroup.getWorkspaceTypeCode())) + .build()) + .stream() + .sorted(Comparator.comparing(SaasRoleGroupVO::getSort)) + .collect(Collectors.toList()); + + SaasRoleGroupVO exchangeRoleGroup = findExchangeRoleGroup(request, saasRoleGroup, roleGroupList); + if (exchangeRoleGroup == null) { + throw new ServiceException("未找到可以移动的位置"); + } + saasRoleGroupService.saveOrUpdate(SaasRoleGroupVO.builder() + .id(saasRoleGroup.getId()) + .sort(exchangeRoleGroup.getSort()) + .build()); + + saasRoleGroupService.saveOrUpdate(SaasRoleGroupVO.builder() + .id(exchangeRoleGroup.getId()) + .sort(saasRoleGroup.getSort()) + .build()); + return ApiResult.ok(); + } + + /** + * 只支持移动一位 + * @param request + * @param saasRoleGroup + * @param roleGroupList + * @return + */ + private SaasRoleGroupVO findExchangeRoleGroup(UpdateRoleGroupOffsetReq request, + SaasRoleGroupVO saasRoleGroup, + List roleGroupList) { + List ids = roleGroupList.stream() + .map(SaasRoleGroupVO::getId) + .collect(Collectors.toList()); + int currentIndex = ids.indexOf(request.getId()); + // 下移一位 + if (request.getOffset() == 1) { + int exchangeIndex = currentIndex + 1; + if (roleGroupList.size() > exchangeIndex) { + return roleGroupList.get(exchangeIndex); + } + } else if (request.getOffset() == -1) { + if (currentIndex == 0) { + return null; + } + int exchangeIndex = currentIndex - 1; + return roleGroupList.get(exchangeIndex); + } + return null; + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasRoleGroupDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasRoleGroupDao.java index 8d5c7128..ffcd7dd6 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasRoleGroupDao.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasRoleGroupDao.java @@ -13,6 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import java.util.List; +import java.util.Objects; @Repository public class SaasRoleGroupDao extends ServiceImpl { @@ -37,6 +38,7 @@ public class SaasRoleGroupDao extends ServiceImpl listByCategoryCode(List categoryCode) { return BeanUtil.copyToList(saasRoleGroupDao.listByCategoryCode(categoryCode), SaasRoleGroupVO.class); } + + private void assembleSort(SaasRoleGroup saasRoleGroup) { + if (saasRoleGroup.getSort() == null || saasRoleGroup.getId() != null || saasRoleGroup.getParentId() == null) { + return; + } + + Optional last = saasRoleGroupDao.lambdaQuery() + .eq(SaasRoleGroup::getParentId, saasRoleGroup.getParentId()) + .eq(SaasRoleGroup::getIsDelete, TableIsDeleteEnum.NORMAL.value) + .orderByDesc(SaasRoleGroup::getSort) + .last("limit 1") + .list() + .stream() + .findFirst(); + saasRoleGroup.setSort(last.map(e -> e.getSort() == null ? 1 : e.getSort() + 1).orElse(1)); + } + + private void checkAdd(SaasRoleGroupVO req) { + // 只有新增的时候才会提交code + if (req.getId() != null) { + return; + } + + if (StringUtils.isNotBlank(req.getCode())) { + Integer count = saasRoleGroupDao.lambdaQuery() + .eq(SaasRoleGroup::getCode, req.getCode()) + .eq(SaasRoleGroup::getIsDelete, TableIsDeleteEnum.NORMAL.value) + .count(); + if (count > 0) { + throw new ServiceException("角色分组编码已经存在"); + } + } + } } From 25b870eda69a7b84578e9f654c550edc0fe5c2e1 Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 9 Apr 2024 21:49:19 +0800 Subject: [PATCH 2/7] =?UTF-8?q?feat:(REQ-2227)=20=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E5=88=86=E7=BB=84=E6=97=B6=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java index 973f5b6d..26ac10ac 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java @@ -164,7 +164,7 @@ public class SaasRoleGroupServiceImpl implements SaasRoleGroupService { saasRoleGroup.setWorkspaceId(req.getWorkspaceId() != null ? req.getWorkspaceId() : -1L); saasRoleGroup.setOuId(req.getOuId() != null ? req.getOuId() : -1L); saasRoleGroup.setParentId(req.getParentId()); - + saasRoleGroup.setCode(req.getCode()); // 新增的时候,没有指定sort,sort放在同层级的最后 assembleSort(saasRoleGroup); return saasRoleGroup; From bc4736d49436795fd2d296b81c682595a86b052a Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 9 Apr 2024 22:14:59 +0800 Subject: [PATCH 3/7] =?UTF-8?q?feat:(REQ-2227)=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E5=88=86=E7=BB=84=E6=97=B6=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?sort=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java index 26ac10ac..978e34ea 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java @@ -176,7 +176,7 @@ public class SaasRoleGroupServiceImpl implements SaasRoleGroupService { } private void assembleSort(SaasRoleGroup saasRoleGroup) { - if (saasRoleGroup.getSort() == null || saasRoleGroup.getId() != null || saasRoleGroup.getParentId() == null) { + if (saasRoleGroup.getSort() != null || saasRoleGroup.getId() != null || saasRoleGroup.getParentId() == null) { return; } From 793f34c67bf7a2248d45b1fd608e79c22b04b482 Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 9 Apr 2024 22:29:10 +0800 Subject: [PATCH 4/7] =?UTF-8?q?feat:(REQ-2227)=20=E5=A2=9E=E5=8A=A0api?= =?UTF-8?q?=E5=89=8D=E7=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/axzo/tyr/client/feign/SaasRoleGroupApi.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/SaasRoleGroupApi.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/SaasRoleGroupApi.java index 8adf14bb..0df9e9c7 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/SaasRoleGroupApi.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/SaasRoleGroupApi.java @@ -70,6 +70,6 @@ public interface SaasRoleGroupApi { * @param request * @return */ - @PostMapping("/role/group/offset/update") + @PostMapping("/api/role/group/offset/update") ApiResult updateRoleGroupOffset(@Valid @RequestBody UpdateRoleGroupOffsetReq request); } From ed3ac9e5f88dc33f5fa8a31312e9a43b3cee1f44 Mon Sep 17 00:00:00 2001 From: lilong Date: Tue, 9 Apr 2024 22:40:28 +0800 Subject: [PATCH 5/7] =?UTF-8?q?feat:(REQ-2227)=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E5=88=86=E7=BB=84=E6=97=B6=EF=BC=8Csort?= =?UTF-8?q?=E5=8F=96=E5=90=8C=E4=B8=80=E4=B8=AAworkspaceTypeCode=E7=9A=84?= =?UTF-8?q?=E6=9C=80=E5=A4=A7=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java index 978e34ea..7ccc9388 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasRoleGroupServiceImpl.java @@ -182,6 +182,7 @@ public class SaasRoleGroupServiceImpl implements SaasRoleGroupService { Optional last = saasRoleGroupDao.lambdaQuery() .eq(SaasRoleGroup::getParentId, saasRoleGroup.getParentId()) + .eq(SaasRoleGroup::getWorkspaceTypeCode, saasRoleGroup.getWorkspaceTypeCode()) .eq(SaasRoleGroup::getIsDelete, TableIsDeleteEnum.NORMAL.value) .orderByDesc(SaasRoleGroup::getSort) .last("limit 1") From c61a03ba2acf38061413468ada9e57b6b2518886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Wed, 10 Apr 2024 09:10:05 +0800 Subject: [PATCH 6/7] =?UTF-8?q?feat(2227-featureResource):=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=8A=9F=E8=83=BD=E8=B5=84=E6=BA=90=E6=A0=91=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=8E=A5=E5=8F=A3=E5=8F=8A=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tyr/client/feign/FeatureResourceApi.java | 5 + .../model/req/GetFeatureResourceTreeReq.java | 30 +++++ .../cn/axzo/tyr/server/TyrApplication.java | 2 + .../permission/FeatureResourceController.java | 6 + .../dao/SaasFeatureResourceDao.java | 20 ++++ .../service/SaasFeatureResourceService.java | 5 + .../impl/SaasFeatureResourceCacheService.java | 31 +++++ .../impl/SaasFeatureResourceServiceImpl.java | 108 +++++++++++++++++- tyr-server/src/main/resources/bootstrap.yml | 2 + 9 files changed, 204 insertions(+), 5 deletions(-) create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetFeatureResourceTreeReq.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceCacheService.java diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/FeatureResourceApi.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/FeatureResourceApi.java index bd9abd36..41c228c0 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/FeatureResourceApi.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/FeatureResourceApi.java @@ -1,6 +1,7 @@ package cn.axzo.tyr.client.feign; import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; import cn.axzo.tyr.client.model.req.ResourceSyncReq; import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; @@ -35,6 +36,10 @@ public interface FeatureResourceApi { @PostMapping("/api/featureResource/saveOrUpdate") ApiResult saveMenu(@RequestBody FeatureResourceTreeSaveReq req); + /** 查询功能资源树 **/ + @PostMapping("/api/featureResource/getTree") + ApiResult> getTree(@RequestBody @Valid GetFeatureResourceTreeReq req); + /** 删除菜单/页面/组件 **/ @PostMapping("/api/featureResource/delete") ApiResult deleteFeatureResource(@RequestParam Long featureId, @RequestParam Long operatorId); diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetFeatureResourceTreeReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetFeatureResourceTreeReq.java new file mode 100644 index 00000000..2c2438d3 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/GetFeatureResourceTreeReq.java @@ -0,0 +1,30 @@ +package cn.axzo.tyr.client.model.req; + +import lombok.*; + +import java.util.List; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/4/9 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class GetFeatureResourceTreeReq { + + /** 查询搜索关键字 **/ + private String keyword; + + /** 端 **/ + private String terminal; + + /** 展示状态 默认不传返回全部 0-隐藏 1-显示 **/ + private Integer status; + + /** feature类型列表 **/ + private List featureTypes; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/TyrApplication.java b/tyr-server/src/main/java/cn/axzo/tyr/server/TyrApplication.java index e07a81da..9df76d7a 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/TyrApplication.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/TyrApplication.java @@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.Environment; @@ -11,6 +12,7 @@ import org.springframework.scheduling.annotation.EnableAsync; @Slf4j @EnableAsync +@EnableCaching @EnableDiscoveryClient @MapperScan(value = {"cn.axzo.tyr.server.repository.mapper"}) @SpringBootApplication(scanBasePackages = "cn.axzo") diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/FeatureResourceController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/FeatureResourceController.java index 7c551a11..d9971be9 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/FeatureResourceController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/permission/FeatureResourceController.java @@ -3,6 +3,7 @@ package cn.axzo.tyr.server.controller.permission; import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.tyr.client.feign.FeatureResourceApi; import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; +import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; import cn.axzo.tyr.client.model.req.ResourceSyncReq; import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; import cn.axzo.tyr.server.service.FeatureResourceSyncService; @@ -72,4 +73,9 @@ public class FeatureResourceController implements FeatureResourceApi { return null; } + + @Override + public ApiResult> getTree(GetFeatureResourceTreeReq req) { + return ApiResult.ok(featureResourceService.getTree(req)); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java index e421cdc0..89382aa8 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/dao/SaasFeatureResourceDao.java @@ -1,10 +1,17 @@ package cn.axzo.tyr.server.repository.dao; +import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum; +import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import cn.axzo.tyr.server.repository.mapper.SaasFeatureResourceMapper; +import cn.azxo.framework.common.utils.StringUtils; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Repository; +import java.util.List; +import java.util.Objects; + /** *

* 功能资源表 服务实现类 @@ -23,4 +30,17 @@ public class SaasFeatureResourceDao extends ServiceImpl getByResourceTreeParam(GetFeatureResourceTreeReq req) { + return this.lambdaQuery().select(SaasFeatureResource::getId, SaasFeatureResource::getFeatureCode, + SaasFeatureResource::getFeatureName, SaasFeatureResource::getFeatureType, + SaasFeatureResource::getTerminal, SaasFeatureResource::getParentId, + SaasFeatureResource::getDisplayOrder) + .eq(SaasFeatureResource::getIsDelete, TableIsDeleteEnum.NORMAL.value) + .eq(StringUtils.isNotBlank(req.getTerminal()), SaasFeatureResource::getTerminal, req.getTerminal()) + .eq(Objects.nonNull(req.getStatus()), SaasFeatureResource::getStatus, req.getStatus()) + .in(CollectionUtils.isNotEmpty(req.getFeatureTypes()), SaasFeatureResource::getFeatureType, req.getFeatureTypes()) + .list(); + } + } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java index ffa14802..f14a04c0 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java @@ -1,5 +1,7 @@ package cn.axzo.tyr.server.service; +import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; +import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; import cn.axzo.tyr.server.model.ResourcePermission; import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; @@ -36,5 +38,8 @@ public interface SaasFeatureResourceService { /** 是否免授权 **/ boolean isAuthFree(Long featureId); + /** 查询资源树 **/ + List getTree(GetFeatureResourceTreeReq req); + SaasFeatureResource getByCode(String featureCode); } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceCacheService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceCacheService.java new file mode 100644 index 00000000..e57bbb5d --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceCacheService.java @@ -0,0 +1,31 @@ +package cn.axzo.tyr.server.service.impl; + +import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; +import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; +import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author likunpeng + * @version 1.0 + * @date 2024/4/9 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class SaasFeatureResourceCacheService { + public static final String CACHE_FEATURE_RESOURCE_TREE = "featureResource:tree"; + + private final SaasFeatureResourceDao featureResourceDao; + + @Cacheable(value = CACHE_FEATURE_RESOURCE_TREE, key = "#req.keyword + '_' + #req.terminal+ '_' + #req.featureTypes", unless = "#result.isEmpty()") + public List getByResourceTreeParam (GetFeatureResourceTreeReq req) { + log.info("get feature resource tree has not user cache!"); + return featureResourceDao.getByResourceTreeParam(req); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java index 3429c952..cd30454e 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java @@ -1,7 +1,8 @@ package cn.axzo.tyr.server.service.impl; import cn.axzo.basics.common.BeanMapper; -import cn.axzo.basics.common.model.IBaseTree; +import cn.axzo.basics.common.util.StopWatchUtil; +import cn.axzo.basics.common.util.TreeUtil; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.pokonyan.config.redis.RedisClient; import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType; @@ -9,27 +10,32 @@ import cn.axzo.tyr.client.common.enums.FeatureResourceStatus; import cn.axzo.tyr.client.common.enums.FeatureResourceType; import cn.axzo.tyr.client.model.req.FeatureComponentSaveReq; import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; +import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq; +import cn.axzo.tyr.client.model.res.FeatureResourceDTO; +import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode; import cn.axzo.tyr.server.model.ResourcePermission; import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO; import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao; import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import cn.azxo.framework.common.utils.StringUtils; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.BooleanUtil; -import io.swagger.models.auth.In; +import com.google.common.collect.Lists; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; import java.util.Collections; import java.util.Comparator; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; @@ -46,9 +52,19 @@ import static cn.axzo.tyr.server.common.constants.CacheConstant.KEY_AUTH_FREE; @Slf4j @Service @RequiredArgsConstructor +@RefreshScope public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceService { private final SaasFeatureResourceDao featureResourceDao; + private final SaasFeatureResourceCacheService saasFeatureResourceCacheService; + + /** + * 功能资源树根节点配置 + * key < - > TerminalInfo定义的terminal + * value < - > 端描述 + */ + @Value("#{${featureResourceTreeRootNodeMap:{'NT_CMS_WEB_GENERAL':'CMS端', 'NT_OMS_WEB':'OMS端'}}}") + private Map treeRootNodeMap; @Override public List listNavByIds(List featureIds) { @@ -108,6 +124,40 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic } @Override + public List getTree(GetFeatureResourceTreeReq req) { + List rootNodes = treeRootNodeMap.entrySet().stream().map(e -> FeatureResourceTreeNode.builder() + .id(0L).terminal(e.getKey()).featureName(e.getValue()).children(Lists.newArrayList()).build()).collect(Collectors.toList()); + + StopWatchUtil watch = StopWatchUtil.createStarted("feature-resource-tree"); + watch.start("dbQuery"); + List saasFeatureResources = saasFeatureResourceCacheService.getByResourceTreeParam(req); + watch.stop(); + if (CollectionUtils.isEmpty(saasFeatureResources)) { + return Collections.emptyList(); + } + + List treeList = TreeUtil.buildTree(saasFeatureResources.stream() + .map(this::featureResource2Node) + .sorted(Comparator.comparing(FeatureResourceDTO::getDisplayOrder)) + .collect(Collectors.toList())); + saasFeatureResources = null; // help GC + + //搜索或需要按授权策略过滤 - 有额外的过滤条件 + watch.start("filter-node"); + List filterResultNode = filterTreeNode(req.getKeyword(), treeList); + watch.stop(); + + //把处理后的树结构添加上根节点 + watch.start("fill-children-to-root"); + List resultNode = fillChildren2Root(rootNodes, filterResultNode); + watch.stop(); + + log.info("feature-resource-tree cost:{} , ms:{}", watch.prettyPrint(), watch.getTotalTimeMillis()); + return resultNode; + } + + @Override + @CacheEvict(value = SaasFeatureResourceCacheService.CACHE_FEATURE_RESOURCE_TREE,allEntries = true) public void saveOrUpdateMenu(FeatureResourceTreeSaveReq req) { SaasFeatureResource baseResource = BeanMapper.copyBean(req, SaasFeatureResource.class); baseResource.setUpdateBy(req.getOperatorId()); @@ -258,4 +308,52 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic featureResourceDao.updateBatchById(parallelFeature); } + + private FeatureResourceTreeNode featureResource2Node(SaasFeatureResource featureResource) { + return FeatureResourceTreeNode.builder() + .id(featureResource.getId()) + .featureCode(featureResource.getFeatureCode()) + .featureName(featureResource.getFeatureName()) + .featureType(featureResource.getFeatureType()) + .terminal(featureResource.getTerminal()) + .parentId(featureResource.getParentId()) + .displayOrder(featureResource.getDisplayOrder()) + .build(); + } + + private List filterTreeNode(String keyword, List treeList) { + if (StringUtils.isBlank(keyword)) { + return treeList; + } + + return treeList.stream().filter(x -> this.recursionFilter(keyword, x)).collect(Collectors.toList()); + } + + private boolean recursionFilter(String keyword, FeatureResourceTreeNode node) { + boolean matched = node.getFeatureName().contains(keyword); + if (CollectionUtils.isEmpty(node.getNodeChildren())) { + return matched; + } + // 过滤子节点 + List filterChildren = node.getChildren().stream().filter(x -> recursionFilter(keyword, x)).collect(Collectors.toList()); + // 重置子节点 + node.setChildren(filterChildren); + if (CollectionUtils.isEmpty(filterChildren)) { + return matched; + } + return true; + } + + private List fillChildren2Root(List rootNodes, List childrenNodes) { + Map rootNodeMap = rootNodes.stream().collect(Collectors.toMap(FeatureResourceDTO::getTerminal, Function.identity(), (v1, v2) -> v1)); + for(FeatureResourceTreeNode child : childrenNodes) { + FeatureResourceTreeNode rootNode = rootNodeMap.get(child.getTerminal()); + if (child.getParentId() > 0 || Objects.isNull(rootNode)) { + continue; + } + rootNode.getChildren().add(child); + } + + return rootNodes; + } } diff --git a/tyr-server/src/main/resources/bootstrap.yml b/tyr-server/src/main/resources/bootstrap.yml index 9bf74eb2..9a6a3cb1 100644 --- a/tyr-server/src/main/resources/bootstrap.yml +++ b/tyr-server/src/main/resources/bootstrap.yml @@ -1,4 +1,6 @@ spring: + cache: + type: redis application: name: tyr cloud: From ccd762b13c79215da30cc6f55f1547c248c7cf24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=86=E9=B9=8F?= Date: Wed, 10 Apr 2024 09:12:01 +0800 Subject: [PATCH 7/7] =?UTF-8?q?feat(2227-featureResource):=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=8A=9F=E8=83=BD=E8=B5=84=E6=BA=90=E6=A0=91=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=8E=A5=E5=8F=A3=E5=8F=8A=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/service/impl/SaasFeatureResourceServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java index cd30454e..7bcc9f08 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java @@ -44,7 +44,8 @@ import static cn.axzo.tyr.server.common.constants.CacheConstant.KEY_AUTH_FREE; /** * 功能资源服务实现 - * + * 功能资源树查询增加了redis缓存,在新增、修改该表时,记得清空缓存, + * 实现:对应方法加上注解@CacheEvict(value = SaasFeatureResourceCacheService.CACHE_FEATURE_RESOURCE_TREE,allEntries = true) * @version V1.0 * @author: ZhanSiHu * @date: 2024/4/3 10:18