mirror of https://gitee.com/stylefeng/roses
【resource】更新扫描资源,可以递归获取obj类型的字段详情,新增两个资源接口,用在生成api文档
parent
27680922e2
commit
1dc2507790
|
@ -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<String, Set<String>> groupAnnotations;
|
||||
|
||||
/**
|
||||
* 泛型或object类型的字段的描述
|
||||
*/
|
||||
private Set<FieldMetadata> genericFieldMetadata;
|
||||
|
||||
}
|
|
@ -102,11 +102,11 @@ public class ResourceDefinition implements Serializable {
|
|||
/**
|
||||
* 接口参数的字段描述
|
||||
*/
|
||||
private Set<FieldDescription> paramFieldDescriptions;
|
||||
private Set<FieldMetadata> paramFieldMetadata;
|
||||
|
||||
/**
|
||||
* 接口返回结果的字段描述
|
||||
*/
|
||||
private Set<FieldDescription> responseFieldDescriptions;
|
||||
private Set<FieldMetadata> responseFieldMetadata;
|
||||
|
||||
}
|
||||
|
|
|
@ -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<FieldDescription> getClassFieldDescription(Class<?> clazz) {
|
||||
public static Set<FieldMetadata> getClassFieldDescription(Class<?> clazz) {
|
||||
|
||||
HashSet<FieldDescription> fieldDescriptions = new HashSet<>();
|
||||
HashSet<FieldMetadata> 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<String, Set<String>> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
* 资源地址
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
* 是否是资源标识
|
||||
* <p>
|
||||
* true-是资源标识
|
||||
* false-虚拟节点,不是一个具体资源
|
||||
*/
|
||||
private Boolean resourceFlag;
|
||||
|
||||
/**
|
||||
* 子节点集合
|
||||
*/
|
||||
private List children;
|
||||
|
||||
}
|
|
@ -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<SysResource> {
|
|||
*/
|
||||
void deleteResourceByProjectCode(String projectCode);
|
||||
|
||||
/**
|
||||
* 获取资源树列表,用于生成api接口
|
||||
*
|
||||
* @return 资源树列表
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/18 15:06
|
||||
*/
|
||||
List<ResourceTreeNode> getResourceTree();
|
||||
|
||||
/**
|
||||
* 获取资源的详情
|
||||
*
|
||||
* @param resourceRequest 请求参数
|
||||
* @return 资源详情
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/18 16:04
|
||||
*/
|
||||
ResourceDefinition getResourceDetail(ResourceRequest resourceRequest);
|
||||
|
||||
}
|
|
@ -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<SysResourceMapper, SysRe
|
|||
this.remove(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ResourceTreeNode> getResourceTree() {
|
||||
|
||||
// 1. 获取所有的资源
|
||||
LambdaQueryWrapper<SysResource> sysResourceLambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
sysResourceLambdaQueryWrapper.select(SysResource::getAppCode, SysResource::getModularCode, SysResource::getModularName, SysResource::getCode, SysResource::getUrl, SysResource::getName);
|
||||
List<SysResource> allResource = this.list(sysResourceLambdaQueryWrapper);
|
||||
|
||||
// 2. 按应用和模块编码设置map
|
||||
Map<String, Map<String, List<ResourceTreeNode>>> appModularResources = divideResources(allResource);
|
||||
|
||||
// 3. 根据map组装资源树
|
||||
return createResourceTree(appModularResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceDefinition getResourceDetail(ResourceRequest resourceRequest) {
|
||||
LambdaQueryWrapper<SysResource> 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<SysResourceMapper, SysRe
|
|||
return queryWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 划分数据库中的资源,切分成应用和模块分类的集合
|
||||
*
|
||||
* @return 第一个key是应用名称,第二个key是模块名称,值是应用对应的模块对应的资源列表
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/18 15:34
|
||||
*/
|
||||
private Map<String, Map<String, List<ResourceTreeNode>>> divideResources(List<SysResource> sysResources) {
|
||||
HashMap<String, Map<String, List<ResourceTreeNode>>> appModularResources = new HashMap<>();
|
||||
for (SysResource sysResource : sysResources) {
|
||||
|
||||
// 查询应用下有无资源
|
||||
String appCode = sysResource.getAppCode();
|
||||
Map<String, List<ResourceTreeNode>> modularResource = appModularResources.get(appCode);
|
||||
|
||||
// 该应用下没资源就创建一个map
|
||||
if (modularResource == null) {
|
||||
modularResource = new HashMap<>();
|
||||
}
|
||||
|
||||
// 查询当前资源的模块,有没有在appModularResources存在
|
||||
List<ResourceTreeNode> 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<ResourceTreeNode> createResourceTree(Map<String, Map<String, List<ResourceTreeNode>>> appModularResources) {
|
||||
|
||||
List<ResourceTreeNode> 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<String, List<ResourceTreeNode>> modularResources = appModularResources.get(appName);
|
||||
|
||||
// 创建模块节点
|
||||
ArrayList<ResourceTreeNode> 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;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue