From 1dc25077900c441ba80242c39a9dbe465377b53b Mon Sep 17 00:00:00 2001 From: fengshuonan Date: Fri, 18 Dec 2020 23:53:05 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90resource=E3=80=91=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E6=89=AB=E6=8F=8F=E8=B5=84=E6=BA=90=EF=BC=8C=E5=8F=AF=E4=BB=A5?= =?UTF-8?q?=E9=80=92=E5=BD=92=E8=8E=B7=E5=8F=96obj=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E7=9A=84=E5=AD=97=E6=AE=B5=E8=AF=A6=E6=83=85=EF=BC=8C=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E4=B8=A4=E4=B8=AA=E8=B5=84=E6=BA=90=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=EF=BC=8C=E7=94=A8=E5=9C=A8=E7=94=9F=E6=88=90api=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...eldDescription.java => FieldMetadata.java} | 7 +- .../api/pojo/resource/ResourceDefinition.java | 4 +- .../resource/api/util/ClassReflectUtil.java | 32 +++-- .../resource/scanner/ApiResourceScanner.java | 6 +- .../resource/request/ResourceRequest.java | 11 +- .../modular/factory/ResourceFactory.java | 12 +- .../modular/pojo/ResourceTreeNode.java | 44 +++++++ .../modular/service/SysResourceService.java | 21 ++++ .../service/impl/SysResourceServiceImpl.java | 116 ++++++++++++++++++ 9 files changed, 226 insertions(+), 27 deletions(-) rename kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/resource/api/pojo/resource/{FieldDescription.java => FieldMetadata.java} (84%) create mode 100644 kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/pojo/ResourceTreeNode.java diff --git a/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/resource/api/pojo/resource/FieldDescription.java b/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/resource/api/pojo/resource/FieldMetadata.java similarity index 84% rename from kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/resource/api/pojo/resource/FieldDescription.java rename to kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/resource/api/pojo/resource/FieldMetadata.java index 6b13fc35b..b5aa81f12 100644 --- a/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/resource/api/pojo/resource/FieldDescription.java +++ b/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/resource/api/pojo/resource/FieldMetadata.java @@ -12,7 +12,7 @@ import java.util.Set; * @date 2020/12/8 18:25 */ @Data -public class FieldDescription { +public class FieldMetadata { /** * 字段中文名称,例如:创建用户 @@ -42,4 +42,9 @@ public class FieldDescription { */ private Map> groupAnnotations; + /** + * 泛型或object类型的字段的描述 + */ + private Set genericFieldMetadata; + } diff --git a/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/resource/api/pojo/resource/ResourceDefinition.java b/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/resource/api/pojo/resource/ResourceDefinition.java index 35134a362..a55bdb36d 100644 --- a/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/resource/api/pojo/resource/ResourceDefinition.java +++ b/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/resource/api/pojo/resource/ResourceDefinition.java @@ -102,11 +102,11 @@ public class ResourceDefinition implements Serializable { /** * 接口参数的字段描述 */ - private Set paramFieldDescriptions; + private Set paramFieldMetadata; /** * 接口返回结果的字段描述 */ - private Set responseFieldDescriptions; + private Set responseFieldMetadata; } diff --git a/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/resource/api/util/ClassReflectUtil.java b/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/resource/api/util/ClassReflectUtil.java index 4cca334bf..822caadaf 100644 --- a/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/resource/api/util/ClassReflectUtil.java +++ b/kernel-d-scanner/scanner-api/src/main/java/cn/stylefeng/roses/kernel/resource/api/util/ClassReflectUtil.java @@ -2,7 +2,8 @@ package cn.stylefeng.roses.kernel.resource.api.util; import cn.hutool.core.util.ClassUtil; import cn.stylefeng.roses.kernel.resource.api.annotation.field.ChineseDescription; -import cn.stylefeng.roses.kernel.resource.api.pojo.resource.FieldDescription; +import cn.stylefeng.roses.kernel.resource.api.pojo.resource.FieldMetadata; +import cn.stylefeng.roses.kernel.rule.pojo.request.BaseRequest; import java.lang.annotation.Annotation; import java.lang.reflect.Field; @@ -29,12 +30,12 @@ public class ClassReflectUtil { * @author fengshuonan * @date 2020/12/8 18:27 */ - public static Set getClassFieldDescription(Class clazz) { + public static Set getClassFieldDescription(Class clazz) { - HashSet fieldDescriptions = new HashSet<>(); + HashSet metadataHashSet = new HashSet<>(); if (clazz == null) { - return fieldDescriptions; + return metadataHashSet; } // 获取类中的所有字段 @@ -42,22 +43,27 @@ public class ClassReflectUtil { for (Field declaredField : declaredFields) { - FieldDescription fieldDescription = new FieldDescription(); + FieldMetadata fieldMetadata = new FieldMetadata(); // 获取字段的名称 String name = declaredField.getName(); - fieldDescription.setFieldName(name); + fieldMetadata.setFieldName(name); // 获取字段的类型 Class declaredFieldType = declaredField.getType(); - fieldDescription.setFieldClassType(declaredFieldType.getSimpleName()); + fieldMetadata.setFieldClassType(declaredFieldType.getSimpleName()); + + // 如果字段类型是Object类型,则遍历Object类型里的字段 + if (BaseRequest.class.isAssignableFrom(declaredFieldType)) { + fieldMetadata.setGenericFieldMetadata(getClassFieldDescription(declaredFieldType)); + } // 获取字段的所有注解 Annotation[] annotations = declaredField.getAnnotations(); if (annotations != null && annotations.length > 0) { // 设置字段的所有注解 - fieldDescription.setAnnotations(annotationsToStrings(annotations)); + fieldMetadata.setAnnotations(annotationsToStrings(annotations)); // 遍历字段上的所有注解,找到带groups属性的,按group分类组装注解 Map> groupAnnotations = new HashMap<>(); @@ -70,19 +76,19 @@ public class ClassReflectUtil { } } // 设置分组注解 - fieldDescription.setGroupAnnotations(groupAnnotations); + fieldMetadata.setGroupAnnotations(groupAnnotations); // 填充字段的中文名称 ChineseDescription chineseDescription = declaredField.getAnnotation(ChineseDescription.class); if (chineseDescription != null) { - fieldDescription.setChineseName(chineseDescription.value()); + fieldMetadata.setChineseName(chineseDescription.value()); } } - fieldDescriptions.add(fieldDescription); + metadataHashSet.add(fieldMetadata); } - return fieldDescriptions; + return metadataHashSet; } /** @@ -95,7 +101,7 @@ public class ClassReflectUtil { try { Class annotationType = apiResource.annotationType(); Method method = annotationType.getMethod(methodName); - return (T)method.invoke(apiResource); + return (T) method.invoke(apiResource); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { // 忽略异常 } diff --git a/kernel-d-scanner/scanner-sdk-scanner/src/main/java/cn/stylefeng/roses/kernel/resource/scanner/ApiResourceScanner.java b/kernel-d-scanner/scanner-sdk-scanner/src/main/java/cn/stylefeng/roses/kernel/resource/scanner/ApiResourceScanner.java index 4ef558865..b95208e60 100644 --- a/kernel-d-scanner/scanner-sdk-scanner/src/main/java/cn/stylefeng/roses/kernel/resource/scanner/ApiResourceScanner.java +++ b/kernel-d-scanner/scanner-sdk-scanner/src/main/java/cn/stylefeng/roses/kernel/resource/scanner/ApiResourceScanner.java @@ -257,15 +257,15 @@ public class ApiResourceScanner implements BeanPostProcessor { // @ApiResource注解上标识了responseClass属性,则用responseClass的值为准,否则按真实方法的返回值class Class responseClass = invokeAnnotationMethod(apiResource, "responseClass", Class.class); if (!Void.class.equals(responseClass)) { - resourceDefinition.setResponseFieldDescriptions(ClassReflectUtil.getClassFieldDescription(responseClass)); + resourceDefinition.setResponseFieldMetadata(ClassReflectUtil.getClassFieldDescription(responseClass)); } else { Class methodReturnClass = MethodReflectUtil.getMethodReturnClass(method); - resourceDefinition.setResponseFieldDescriptions(ClassReflectUtil.getClassFieldDescription(methodReturnClass)); + resourceDefinition.setResponseFieldMetadata(ClassReflectUtil.getClassFieldDescription(methodReturnClass)); } // 填充方法的请求参数字段的详细信息 Class firstParamClass = MethodReflectUtil.getMethodFirstParamClass(method); - resourceDefinition.setParamFieldDescriptions(ClassReflectUtil.getClassFieldDescription(firstParamClass)); + resourceDefinition.setParamFieldMetadata(ClassReflectUtil.getClassFieldDescription(firstParamClass)); return resourceDefinition; } diff --git a/kernel-s-system/system-api/src/main/java/cn/stylefeng/roses/kernel/system/pojo/resource/request/ResourceRequest.java b/kernel-s-system/system-api/src/main/java/cn/stylefeng/roses/kernel/system/pojo/resource/request/ResourceRequest.java index 2336fb810..2f41d5bf3 100644 --- a/kernel-s-system/system-api/src/main/java/cn/stylefeng/roses/kernel/system/pojo/resource/request/ResourceRequest.java +++ b/kernel-s-system/system-api/src/main/java/cn/stylefeng/roses/kernel/system/pojo/resource/request/ResourceRequest.java @@ -1,8 +1,9 @@ package cn.stylefeng.roses.kernel.system.pojo.resource.request; +import cn.stylefeng.roses.kernel.rule.pojo.request.BaseRequest; import lombok.Data; -import java.io.Serializable; +import javax.validation.constraints.NotBlank; /** * 资源请求封装 @@ -11,7 +12,7 @@ import java.io.Serializable; * @since 2019-09-10 */ @Data -public class ResourceRequest implements Serializable { +public class ResourceRequest extends BaseRequest { private static final long serialVersionUID = 1L; @@ -25,6 +26,12 @@ public class ResourceRequest implements Serializable { */ private String resourceName; + /** + * 资源编码 + */ + @NotBlank(message = "资源编码为空", groups = detail.class) + private String resourceCode; + /** * 资源地址 */ diff --git a/kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/factory/ResourceFactory.java b/kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/factory/ResourceFactory.java index 679238cb1..e23c30599 100644 --- a/kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/factory/ResourceFactory.java +++ b/kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/factory/ResourceFactory.java @@ -56,13 +56,13 @@ public class ResourceFactory { } // 转化接口参数的字段描述 - if (ObjectUtil.isNotEmpty(resourceDefinition.getParamFieldDescriptions())) { - resource.setParamFieldDescriptions(JSON.toJSONString(resourceDefinition.getParamFieldDescriptions(), SerializerFeature.WriteClassName)); + if (ObjectUtil.isNotEmpty(resourceDefinition.getParamFieldMetadata())) { + resource.setParamFieldDescriptions(JSON.toJSONString(resourceDefinition.getParamFieldMetadata(), SerializerFeature.WriteClassName)); } // 转化接口返回结果的字段描述 - if (ObjectUtil.isNotEmpty(resourceDefinition.getResponseFieldDescriptions())) { - resource.setResponseFieldDescriptions(JSON.toJSONString(resourceDefinition.getResponseFieldDescriptions(), SerializerFeature.WriteClassName)); + if (ObjectUtil.isNotEmpty(resourceDefinition.getResponseFieldMetadata())) { + resource.setResponseFieldDescriptions(JSON.toJSONString(resourceDefinition.getResponseFieldMetadata(), SerializerFeature.WriteClassName)); } return resource; @@ -94,12 +94,12 @@ public class ResourceFactory { // 转化接口参数的字段描述 if (ObjectUtil.isNotEmpty(sysResource.getParamFieldDescriptions())) { - resourceDefinition.setParamFieldDescriptions(JSON.parseObject(sysResource.getParamFieldDescriptions(), Set.class, Feature.SupportAutoType)); + resourceDefinition.setParamFieldMetadata(JSON.parseObject(sysResource.getParamFieldDescriptions(), Set.class, Feature.SupportAutoType)); } // 转化接口返回结果的字段描述 if (ObjectUtil.isNotEmpty(sysResource.getResponseFieldDescriptions())) { - resourceDefinition.setResponseFieldDescriptions(JSON.parseObject(sysResource.getResponseFieldDescriptions(), Set.class, Feature.SupportAutoType)); + resourceDefinition.setResponseFieldMetadata(JSON.parseObject(sysResource.getResponseFieldDescriptions(), Set.class, Feature.SupportAutoType)); } return resourceDefinition; diff --git a/kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/pojo/ResourceTreeNode.java b/kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/pojo/ResourceTreeNode.java new file mode 100644 index 000000000..a72798367 --- /dev/null +++ b/kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/pojo/ResourceTreeNode.java @@ -0,0 +1,44 @@ +package cn.stylefeng.roses.kernel.resource.modular.pojo; + +import lombok.Data; + +import java.util.List; + +/** + * 资源树节点的描述 + * + * @author fengshuonan + * @date 2020/3/26 14:29 + */ +@Data +public class ResourceTreeNode { + + /** + * 资源id + */ + private String code; + + /** + * 父级资源id + */ + private String parentCode; + + /** + * 资源名称 + */ + private String nodeName; + + /** + * 是否是资源标识 + *

+ * true-是资源标识 + * false-虚拟节点,不是一个具体资源 + */ + private Boolean resourceFlag; + + /** + * 子节点集合 + */ + private List children; + +} diff --git a/kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/service/SysResourceService.java b/kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/service/SysResourceService.java index d32961a17..0e411b800 100644 --- a/kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/service/SysResourceService.java +++ b/kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/service/SysResourceService.java @@ -1,6 +1,8 @@ package cn.stylefeng.roses.kernel.resource.modular.service; +import cn.stylefeng.roses.kernel.resource.api.pojo.resource.ResourceDefinition; import cn.stylefeng.roses.kernel.resource.modular.entity.SysResource; +import cn.stylefeng.roses.kernel.resource.modular.pojo.ResourceTreeNode; import cn.stylefeng.roses.kernel.system.pojo.resource.request.ResourceRequest; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; @@ -46,4 +48,23 @@ public interface SysResourceService extends IService { */ void deleteResourceByProjectCode(String projectCode); + /** + * 获取资源树列表,用于生成api接口 + * + * @return 资源树列表 + * @author fengshuonan + * @date 2020/12/18 15:06 + */ + List getResourceTree(); + + /** + * 获取资源的详情 + * + * @param resourceRequest 请求参数 + * @return 资源详情 + * @author fengshuonan + * @date 2020/12/18 16:04 + */ + ResourceDefinition getResourceDetail(ResourceRequest resourceRequest); + } \ No newline at end of file diff --git a/kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/service/impl/SysResourceServiceImpl.java b/kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/service/impl/SysResourceServiceImpl.java index 55eca969a..7056f218f 100644 --- a/kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/service/impl/SysResourceServiceImpl.java +++ b/kernel-s-system/system-business-resource/src/main/java/cn/stylefeng/roses/kernel/resource/modular/service/impl/SysResourceServiceImpl.java @@ -10,6 +10,7 @@ import cn.stylefeng.roses.kernel.resource.modular.cache.ResourceCache; import cn.stylefeng.roses.kernel.resource.modular.entity.SysResource; import cn.stylefeng.roses.kernel.resource.modular.factory.ResourceFactory; import cn.stylefeng.roses.kernel.resource.modular.mapper.SysResourceMapper; +import cn.stylefeng.roses.kernel.resource.modular.pojo.ResourceTreeNode; import cn.stylefeng.roses.kernel.resource.modular.service.SysResourceService; import cn.stylefeng.roses.kernel.rule.enums.YesOrNotEnum; import cn.stylefeng.roses.kernel.system.ResourceServiceApi; @@ -25,10 +26,13 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RequestBody; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import static cn.stylefeng.roses.kernel.system.constants.SystemConstants.DEFAULT_PARENT_ID; + /** * 资源表 服务实现类 * @@ -80,6 +84,33 @@ public class SysResourceServiceImpl extends ServiceImpl getResourceTree() { + + // 1. 获取所有的资源 + LambdaQueryWrapper sysResourceLambdaQueryWrapper = new LambdaQueryWrapper<>(); + sysResourceLambdaQueryWrapper.select(SysResource::getAppCode, SysResource::getModularCode, SysResource::getModularName, SysResource::getCode, SysResource::getUrl, SysResource::getName); + List allResource = this.list(sysResourceLambdaQueryWrapper); + + // 2. 按应用和模块编码设置map + Map>> appModularResources = divideResources(allResource); + + // 3. 根据map组装资源树 + return createResourceTree(appModularResources); + } + + @Override + public ResourceDefinition getResourceDetail(ResourceRequest resourceRequest) { + LambdaQueryWrapper sysResourceLambdaQueryWrapper = new LambdaQueryWrapper<>(); + sysResourceLambdaQueryWrapper.eq(SysResource::getCode, resourceRequest.getResourceCode()); + SysResource sysResource = this.getOne(sysResourceLambdaQueryWrapper); + if (sysResource != null) { + return ResourceFactory.createResourceDefinition(sysResource); + } else { + return null; + } + } + @Override @Transactional(rollbackFor = Exception.class) public void reportResources(@RequestBody ReportResourceParam reportResourceReq) { @@ -216,4 +247,89 @@ public class SysResourceServiceImpl extends ServiceImpl>> divideResources(List sysResources) { + HashMap>> appModularResources = new HashMap<>(); + for (SysResource sysResource : sysResources) { + + // 查询应用下有无资源 + String appCode = sysResource.getAppCode(); + Map> modularResource = appModularResources.get(appCode); + + // 该应用下没资源就创建一个map + if (modularResource == null) { + modularResource = new HashMap<>(); + } + + // 查询当前资源的模块,有没有在appModularResources存在 + List resourceTreeNodes = modularResource.get(sysResource.getModularCode()); + if (resourceTreeNodes == null) { + resourceTreeNodes = new ArrayList<>(); + } + + // 将当前资源放入资源集合 + ResourceTreeNode resourceTreeNode = new ResourceTreeNode(); + resourceTreeNode.setResourceFlag(true); + resourceTreeNode.setNodeName(sysResource.getUrl() + "(" + sysResource.getName() + ")"); + resourceTreeNode.setCode(sysResource.getCode()); + resourceTreeNode.setParentCode(sysResource.getModularCode()); + resourceTreeNodes.add(resourceTreeNode); + + modularResource.put(sysResource.getModularCode(), resourceTreeNodes); + appModularResources.put(appCode, modularResource); + } + return appModularResources; + } + + /** + * 根据归好类的资源,创建资源树 + * + * @author fengshuonan + * @date 2020/12/18 15:45 + */ + private List createResourceTree(Map>> appModularResources) { + + List finalTree = new ArrayList<>(); + + // 按应用遍历应用模块资源集合 + for (String appName : appModularResources.keySet()) { + + // 创建当前应用节点 + ResourceTreeNode appNode = new ResourceTreeNode(); + appNode.setCode(appName); + appNode.setNodeName(appName); + appNode.setResourceFlag(false); + appNode.setParentCode(DEFAULT_PARENT_ID.toString()); + + // 遍历当前应用下的模块资源 + Map> modularResources = appModularResources.get(appName); + + // 创建模块节点 + ArrayList modularNodes = new ArrayList<>(); + for (String modularName : modularResources.keySet()) { + ResourceTreeNode modularNode = new ResourceTreeNode(); + modularNode.setCode(modularName); + modularNode.setNodeName(modularName); + modularNode.setResourceFlag(false); + modularNode.setParentCode(appName); + modularNode.setChildren(modularResources.get(modularName)); + modularNodes.add(modularNode); + } + + // 当前应用下添加模块的资源 + appNode.setChildren(modularNodes); + + // 添加到最终结果 + finalTree.add(appNode); + } + + return finalTree; + } + } \ No newline at end of file