mirror of
https://gitee.com/ssssssss-team/magic-api.git
synced 2026-06-03 20:39:46 +08:00
初步实现插件机制
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
package org.ssssssss.magicapi.swagger;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
import org.ssssssss.magicapi.core.config.MagicAPIProperties;
|
||||
import org.ssssssss.magicapi.core.config.MagicPluginConfiguration;
|
||||
import org.ssssssss.magicapi.core.model.Plugin;
|
||||
import org.ssssssss.magicapi.core.service.MagicResourceService;
|
||||
import org.ssssssss.magicapi.core.service.impl.RequestMagicDynamicRegistry;
|
||||
import org.ssssssss.magicapi.swagger.entity.SwaggerEntity;
|
||||
import org.ssssssss.magicapi.swagger.entity.SwaggerProvider;
|
||||
import org.ssssssss.magicapi.utils.Mapping;
|
||||
import springfox.documentation.swagger.web.SwaggerResource;
|
||||
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(SwaggerConfig.class)
|
||||
@ConditionalOnClass(name = "springfox.documentation.swagger.web.SwaggerResourcesProvider")
|
||||
public class MagicSwaggerConfiguration implements MagicPluginConfiguration {
|
||||
|
||||
private final MagicAPIProperties properties;
|
||||
private final SwaggerConfig swaggerConfig;
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
@Lazy
|
||||
private RequestMappingHandlerMapping requestMappingHandlerMapping;
|
||||
|
||||
public MagicSwaggerConfiguration(MagicAPIProperties properties, SwaggerConfig swaggerConfig, ApplicationContext applicationContext) {
|
||||
this.properties = properties;
|
||||
this.swaggerConfig = swaggerConfig;
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plugin plugin() {
|
||||
return new Plugin("Swagger");
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public SwaggerResourcesProvider magicSwaggerResourcesProvider(RequestMagicDynamicRegistry requestMagicDynamicRegistry, MagicResourceService magicResourceService, ServletContext servletContext) throws NoSuchMethodException {
|
||||
Mapping mapping = Mapping.create(requestMappingHandlerMapping);
|
||||
RequestMappingInfo requestMappingInfo = mapping.paths(swaggerConfig.getLocation()).build();
|
||||
SwaggerEntity.License license = new SwaggerEntity.License("MIT", "https://gitee.com/ssssssss-team/magic-api/blob/master/LICENSE");
|
||||
SwaggerEntity.Info info = new SwaggerEntity.Info(swaggerConfig.getDescription(), swaggerConfig.getVersion(), swaggerConfig.getTitle(), license, swaggerConfig.getConcat());
|
||||
// 构建文档信息
|
||||
SwaggerProvider swaggerProvider = new SwaggerProvider(requestMagicDynamicRegistry, magicResourceService, servletContext.getContextPath(), info, properties.isPersistenceResponseBody());
|
||||
|
||||
|
||||
// 注册swagger.json
|
||||
mapping.register(requestMappingInfo, swaggerProvider, SwaggerProvider.class.getDeclaredMethod("swaggerJson"));
|
||||
|
||||
return () -> {
|
||||
List<SwaggerResource> resources = new ArrayList<>();
|
||||
// 追加Magic Swagger信息
|
||||
resources.add(swaggerResource(swaggerConfig.getName(), swaggerConfig.getLocation()));
|
||||
Map<String, SwaggerResourcesProvider> beans = applicationContext.getBeansOfType(SwaggerResourcesProvider.class);
|
||||
// 获取已定义的文档信息
|
||||
for (Map.Entry<String, SwaggerResourcesProvider> entry : beans.entrySet()) {
|
||||
if (!"magicSwaggerResourcesProvider".equalsIgnoreCase(entry.getKey())) {
|
||||
resources.addAll(entry.getValue().get());
|
||||
}
|
||||
}
|
||||
return resources;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建 SwaggerResource
|
||||
*
|
||||
* @param name 名字
|
||||
* @param location 位置
|
||||
*/
|
||||
private SwaggerResource swaggerResource(String name, String location) {
|
||||
SwaggerResource resource = new SwaggerResource();
|
||||
resource.setName(name);
|
||||
resource.setLocation(location);
|
||||
resource.setSwaggerVersion("2.0");
|
||||
return resource;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package org.ssssssss.magicapi.swagger;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import org.ssssssss.magicapi.swagger.entity.SwaggerEntity;
|
||||
|
||||
/**
|
||||
* Swagger 配置
|
||||
*
|
||||
* @author mxd
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "magic-api.swagger")
|
||||
public class SwaggerConfig {
|
||||
|
||||
/**
|
||||
* 资源名称
|
||||
*/
|
||||
private String name = "MagicAPI接口";
|
||||
|
||||
/**
|
||||
* 资源位置
|
||||
*/
|
||||
private String location = "/v2/api-docs/magic-api/swagger2.json";
|
||||
|
||||
/**
|
||||
* 文档标题
|
||||
*/
|
||||
private String title = "MagicAPI Swagger Docs";
|
||||
|
||||
/**
|
||||
* 文档描述
|
||||
*/
|
||||
private String description = "MagicAPI 接口信息";
|
||||
|
||||
@NestedConfigurationProperty
|
||||
private SwaggerEntity.Concat concat = new SwaggerEntity.Concat();
|
||||
|
||||
/**
|
||||
* 文档版本
|
||||
*/
|
||||
private String version = "1.0";
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public SwaggerEntity.Concat getConcat() {
|
||||
return concat;
|
||||
}
|
||||
|
||||
public void setConcat(SwaggerEntity.Concat concat) {
|
||||
this.concat = concat;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,510 @@
|
||||
package org.ssssssss.magicapi.swagger.entity;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Swagger接口信息
|
||||
*
|
||||
* @author mxd
|
||||
*/
|
||||
public class SwaggerEntity {
|
||||
|
||||
private String swagger = "2.0";
|
||||
|
||||
private String host;
|
||||
|
||||
private String basePath;
|
||||
|
||||
private Info info;
|
||||
|
||||
private final Set<Tag> tags = new TreeSet<>(Comparator.comparing(Tag::getName));
|
||||
|
||||
private final Map<String, Object> definitions = new HashMap<>();
|
||||
|
||||
private final Map<String, Map<String, Path>> paths = new HashMap<>();
|
||||
|
||||
private static Map<String, Object> doProcessSchema(Object target) {
|
||||
Map<String, Object> result = new HashMap<>(3);
|
||||
result.put("type", getType(target));
|
||||
if (target instanceof List) {
|
||||
List<?> targetList = (List<?>) target;
|
||||
if (targetList.size() > 0) {
|
||||
result.put("items", doProcessSchema(targetList.get(0)));
|
||||
} else {
|
||||
result.put("items", Collections.emptyList());
|
||||
}
|
||||
} else if (target instanceof Map) {
|
||||
Set<Map.Entry> entries = ((Map) target).entrySet();
|
||||
Map<String, Map<String, Object>> properties = new HashMap<>(entries.size());
|
||||
for (Map.Entry entry : entries) {
|
||||
properties.put(Objects.toString(entry.getKey()), doProcessSchema(entry.getValue()));
|
||||
}
|
||||
result.put("properties", properties);
|
||||
} else {
|
||||
result.put("example", target == null ? "" : target);
|
||||
result.put("description", target == null ? "" : target);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String getType(Object object) {
|
||||
if (object instanceof Number) {
|
||||
return "number";
|
||||
}
|
||||
if (object instanceof String) {
|
||||
return "string";
|
||||
}
|
||||
if (object instanceof Boolean) {
|
||||
return "boolean";
|
||||
}
|
||||
if (object instanceof List) {
|
||||
return "array";
|
||||
}
|
||||
if (object instanceof Map) {
|
||||
return "object";
|
||||
}
|
||||
return "string";
|
||||
}
|
||||
|
||||
public static Map<String, Object> createParameter(boolean required, String name, String in, String type, String description, Object example) {
|
||||
Map<String, Object> parameter = new HashMap<>();
|
||||
parameter.put("required", required);
|
||||
parameter.put("name", name);
|
||||
parameter.put("in", in);
|
||||
parameter.put("description", description);
|
||||
|
||||
if ("body".equalsIgnoreCase(in)) {
|
||||
Map<String, Object> schema = new HashMap<>();
|
||||
schema.put("type", type);
|
||||
schema.put("example", example);
|
||||
parameter.put("schema", schema);
|
||||
} else {
|
||||
parameter.put("x-example", example);
|
||||
parameter.put("type", type);
|
||||
}
|
||||
return parameter;
|
||||
}
|
||||
|
||||
public Info getInfo() {
|
||||
return info;
|
||||
}
|
||||
|
||||
public void setInfo(Info info) {
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public void addPath(String path, String method, Path pathInfo) {
|
||||
Map<String, Path> map = paths.computeIfAbsent(path, k -> new HashMap<>());
|
||||
map.put(method.toLowerCase(), pathInfo);
|
||||
}
|
||||
|
||||
public void addTag(String name, String description) {
|
||||
this.tags.add(new Tag(name, description));
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public String getSwagger() {
|
||||
return swagger;
|
||||
}
|
||||
|
||||
public void setSwagger(String swagger) {
|
||||
this.swagger = swagger;
|
||||
}
|
||||
|
||||
public String getBasePath() {
|
||||
return basePath;
|
||||
}
|
||||
|
||||
public void setBasePath(String basePath) {
|
||||
this.basePath = basePath;
|
||||
}
|
||||
|
||||
public Map<String, Object> getDefinitions() {
|
||||
return definitions;
|
||||
}
|
||||
|
||||
public void addDefinitions(String path, Object definition) {
|
||||
definitions.put(path, definition);
|
||||
}
|
||||
|
||||
public Set<Tag> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public Map<String, Map<String, Path>> getPaths() {
|
||||
return paths;
|
||||
}
|
||||
|
||||
public static class Concat {
|
||||
|
||||
private String name;
|
||||
|
||||
private String url;
|
||||
|
||||
private String email;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Info {
|
||||
|
||||
private String description;
|
||||
|
||||
private String version;
|
||||
|
||||
private String title;
|
||||
|
||||
private License license;
|
||||
|
||||
private Concat concat;
|
||||
|
||||
public Info(String description, String version, String title, License license, Concat concat) {
|
||||
this.description = description;
|
||||
this.version = version;
|
||||
this.title = title;
|
||||
this.license = license;
|
||||
this.concat = concat;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public License getLicense() {
|
||||
return license;
|
||||
}
|
||||
|
||||
public void setLicense(License license) {
|
||||
this.license = license;
|
||||
}
|
||||
|
||||
public Concat getConcat() {
|
||||
return concat;
|
||||
}
|
||||
|
||||
public void setConcat(Concat concat) {
|
||||
this.concat = concat;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Path {
|
||||
|
||||
private List<String> tags = new ArrayList<>();
|
||||
|
||||
private String summary;
|
||||
|
||||
private String description;
|
||||
|
||||
private final String operationId;
|
||||
|
||||
private List<String> produces = new ArrayList<>();
|
||||
|
||||
private List<String> consumes = new ArrayList<>();
|
||||
|
||||
private List<Map<String, Object>> parameters = new ArrayList<>();
|
||||
|
||||
private Map<String, Object> responses = new HashMap<>();
|
||||
|
||||
public Path(String operationId) {
|
||||
this.operationId = operationId;
|
||||
}
|
||||
|
||||
public void addProduce(String produce) {
|
||||
this.produces.add(produce);
|
||||
}
|
||||
|
||||
public void addConsume(String consume) {
|
||||
this.consumes.add(consume);
|
||||
}
|
||||
|
||||
public void addParameter(Map<String, Object> parameter) {
|
||||
this.parameters.add(parameter);
|
||||
}
|
||||
|
||||
public String getOperationId() {
|
||||
return operationId;
|
||||
}
|
||||
|
||||
public void addResponse(String status, Object object) {
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("description", "OK");
|
||||
response.put("schema", doProcessSchema(object));
|
||||
response.put("example", object);
|
||||
this.responses.put(status, response);
|
||||
}
|
||||
|
||||
public List<String> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public void setTags(List<String> tags) {
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
public void addTag(String tag) {
|
||||
this.tags.add(tag);
|
||||
}
|
||||
|
||||
public String getSummary() {
|
||||
return summary;
|
||||
}
|
||||
|
||||
public void setSummary(String summary) {
|
||||
this.summary = summary;
|
||||
}
|
||||
|
||||
public List<String> getProduces() {
|
||||
return produces;
|
||||
}
|
||||
|
||||
public void setProduces(List<String> produces) {
|
||||
this.produces = produces;
|
||||
}
|
||||
|
||||
public List<String> getConsumes() {
|
||||
return consumes;
|
||||
}
|
||||
|
||||
public void setConsumes(List<String> consumes) {
|
||||
this.consumes = consumes;
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public void setParameters(List<Map<String, Object>> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public Map<String, Object> getResponses() {
|
||||
return responses;
|
||||
}
|
||||
|
||||
public void setResponses(Map<String, Object> responses) {
|
||||
this.responses = responses;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Parameter {
|
||||
|
||||
private String name;
|
||||
|
||||
private String in;
|
||||
|
||||
private boolean required = false;
|
||||
|
||||
private String type;
|
||||
|
||||
private Object schema;
|
||||
|
||||
private String description;
|
||||
|
||||
private Object example;
|
||||
|
||||
public Parameter(boolean required, String name, String in, String type, String description, Object example) {
|
||||
this.name = name;
|
||||
this.in = in;
|
||||
this.type = type;
|
||||
this.description = description;
|
||||
this.required = required;
|
||||
if ("body".equalsIgnoreCase(in)) {
|
||||
this.schema = "";
|
||||
} else {
|
||||
this.example = example;
|
||||
/*
|
||||
* fix swagger文档使用knife4j时无法显示接口详情的问题(query类型参数)
|
||||
* schema 需设置为空字符串,否则请求参数中数据类型字段显示不正确
|
||||
*/
|
||||
this.schema = "";
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getIn() {
|
||||
return in;
|
||||
}
|
||||
|
||||
public void setIn(String in) {
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
public boolean isRequired() {
|
||||
return required;
|
||||
}
|
||||
|
||||
public void setRequired(boolean required) {
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Object getSchema() {
|
||||
return schema;
|
||||
}
|
||||
|
||||
public void setSchema(Object schema) {
|
||||
this.schema = schema;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Object getExample() {
|
||||
return example;
|
||||
}
|
||||
|
||||
public void setExample(Object example) {
|
||||
this.example = example;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Tag {
|
||||
|
||||
private String name;
|
||||
|
||||
private String description;
|
||||
|
||||
public Tag(String name, String description) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Tag tag = (Tag) o;
|
||||
return Objects.equals(name, tag.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class License {
|
||||
|
||||
private String name;
|
||||
|
||||
private String url;
|
||||
|
||||
public License(String name, String url) {
|
||||
this.name = name;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
package org.ssssssss.magicapi.swagger.entity;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.ssssssss.magicapi.core.config.MagicConfiguration;
|
||||
import org.ssssssss.magicapi.core.model.ApiInfo;
|
||||
import org.ssssssss.magicapi.core.model.BaseDefinition;
|
||||
import org.ssssssss.magicapi.core.model.DataType;
|
||||
import org.ssssssss.magicapi.core.model.Path;
|
||||
import org.ssssssss.magicapi.core.service.MagicResourceService;
|
||||
import org.ssssssss.magicapi.core.service.impl.RequestMagicDynamicRegistry;
|
||||
import org.ssssssss.magicapi.utils.JsonUtils;
|
||||
import org.ssssssss.magicapi.utils.PathUtils;
|
||||
import org.ssssssss.script.parsing.ast.literal.BooleanLiteral;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static org.ssssssss.magicapi.core.config.Constants.*;
|
||||
|
||||
/**
|
||||
* 生成swagger用的json
|
||||
*
|
||||
* @author mxd
|
||||
*/
|
||||
public class SwaggerProvider {
|
||||
|
||||
/**
|
||||
* swagger Model定义路径前缀
|
||||
*/
|
||||
private static final String DEFINITION = "#/definitions/";
|
||||
/**
|
||||
* body空对象
|
||||
*/
|
||||
private static final String BODY_EMPTY = "{}";
|
||||
|
||||
private final Map<String, Object> DEFINITION_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
private final RequestMagicDynamicRegistry requestMagicDynamicRegistry;
|
||||
|
||||
private final MagicResourceService magicResourceService;
|
||||
/**
|
||||
* 基础路径
|
||||
*/
|
||||
private final String basePath;
|
||||
private final SwaggerEntity.Info info;
|
||||
private final boolean persistenceResponseBody;
|
||||
|
||||
public SwaggerProvider(RequestMagicDynamicRegistry requestMagicDynamicRegistry, MagicResourceService magicResourceService, String basePath, SwaggerEntity.Info info, boolean persistenceResponseBody) {
|
||||
this.requestMagicDynamicRegistry = requestMagicDynamicRegistry;
|
||||
this.magicResourceService = magicResourceService;
|
||||
this.basePath = basePath;
|
||||
this.info = info;
|
||||
this.persistenceResponseBody = persistenceResponseBody;
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
public SwaggerEntity swaggerJson() {
|
||||
this.DEFINITION_MAP.clear();
|
||||
List<ApiInfo> infos = requestMagicDynamicRegistry.mappings();
|
||||
SwaggerEntity swaggerEntity = new SwaggerEntity();
|
||||
swaggerEntity.setInfo(info);
|
||||
swaggerEntity.setBasePath(this.basePath);
|
||||
for (ApiInfo info : infos) {
|
||||
String groupName = magicResourceService.getGroupName(info.getGroupId()).replace("/", "-");
|
||||
String requestPath = PathUtils.replaceSlash("/" + magicResourceService.getGroupPath(info.getGroupId()) + "/" + info.getPath());
|
||||
SwaggerEntity.Path path = new SwaggerEntity.Path(info.getId());
|
||||
path.addTag(groupName);
|
||||
boolean hasBody = false;
|
||||
try {
|
||||
List<Map<String, Object>> parameters = parseParameters(info);
|
||||
hasBody = parameters.stream().anyMatch(it -> VAR_NAME_REQUEST_BODY.equals(it.get("in")));
|
||||
BaseDefinition baseDefinition = info.getRequestBodyDefinition();
|
||||
if (hasBody && baseDefinition != null) {
|
||||
doProcessDefinition(baseDefinition, info, groupName, "root_", "request", 0);
|
||||
}
|
||||
parameters.forEach(path::addParameter);
|
||||
if (this.persistenceResponseBody) {
|
||||
baseDefinition = info.getResponseBodyDefinition();
|
||||
if (baseDefinition != null) {
|
||||
Map responseMap = parseResponse(info);
|
||||
if (!responseMap.isEmpty()) {
|
||||
path.setResponses(responseMap);
|
||||
doProcessDefinition(baseDefinition, info, groupName, "root_" + baseDefinition.getName(), "response", 0);
|
||||
}
|
||||
} else {
|
||||
path.addResponse("200", JsonUtils.readValue(Objects.toString(info.getResponseBody(), BODY_EMPTY), Object.class));
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
if (hasBody) {
|
||||
path.addConsume("application/json");
|
||||
} else {
|
||||
path.addConsume("*/*");
|
||||
}
|
||||
path.addProduce("application/json");
|
||||
path.setSummary(info.getName());
|
||||
path.setDescription(StringUtils.defaultIfBlank(info.getDescription(), info.getName()));
|
||||
|
||||
swaggerEntity.addPath(requestPath, info.getMethod(), path);
|
||||
}
|
||||
|
||||
if (this.DEFINITION_MAP.size() > 0) {
|
||||
Set<Map.Entry> entries = ((Map) this.DEFINITION_MAP).entrySet();
|
||||
for (Map.Entry entry : entries) {
|
||||
swaggerEntity.addDefinitions(Objects.toString(entry.getKey()), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return swaggerEntity;
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> parseParameters(ApiInfo info) {
|
||||
List<Map<String, Object>> parameters = new ArrayList<>();
|
||||
info.getParameters().forEach(it -> parameters.add(SwaggerEntity.createParameter(it.isRequired(), it.getName(), VAR_NAME_QUERY, it.getDataType().getJavascriptType(), it.getDescription(), it.getValue())));
|
||||
info.getHeaders().forEach(it -> parameters.add(SwaggerEntity.createParameter(it.isRequired(), it.getName(), VAR_NAME_HEADER, it.getDataType().getJavascriptType(), it.getDescription(), it.getValue())));
|
||||
List<Path> paths = new ArrayList<>(info.getPaths());
|
||||
MagicConfiguration.getMagicResourceService().getGroupsByFileId(info.getId())
|
||||
.stream()
|
||||
.flatMap(it -> it.getPaths().stream())
|
||||
.filter(it -> !paths.contains(it))
|
||||
.forEach(paths::add);
|
||||
paths.forEach(it -> parameters.add(SwaggerEntity.createParameter(it.isRequired(), it.getName(), VAR_NAME_PATH_VARIABLE, it.getDataType().getJavascriptType(), it.getDescription(), it.getValue())));
|
||||
try {
|
||||
BaseDefinition baseDefinition = info.getRequestBodyDefinition();
|
||||
if (baseDefinition != null && !CollectionUtils.isEmpty(baseDefinition.getChildren())) {
|
||||
Map<String, Object> parameter = SwaggerEntity.createParameter(baseDefinition.isRequired(), StringUtils.isNotBlank(baseDefinition.getName()) ? baseDefinition.getName() : VAR_NAME_REQUEST_BODY, VAR_NAME_REQUEST_BODY, baseDefinition.getDataType().getJavascriptType(), baseDefinition.getDescription(), baseDefinition);
|
||||
Map<String, Object> schema = new HashMap<>(2);
|
||||
String groupName = magicResourceService.getGroupName(info.getGroupId()).replace("/", "-");
|
||||
String voName = groupName + "«" + info.getPath().replaceFirst("/", "").replaceAll("/", "_") + "«request«";
|
||||
if (DataType.Array == baseDefinition.getDataType()) {
|
||||
voName += "root_" + (StringUtils.isNotBlank(baseDefinition.getName()) ? baseDefinition.getName() + "_" : "_") + "»»»";
|
||||
|
||||
Map<String, Object> items = new HashMap<>(2);
|
||||
items.put("originalRef", voName);
|
||||
items.put("$ref", DEFINITION + voName);
|
||||
schema.put("items", items);
|
||||
schema.put("type", VAR_NAME_REQUEST_BODY_VALUE_TYPE_ARRAY);
|
||||
} else {
|
||||
voName += "root_" + baseDefinition.getName() + "»»»";
|
||||
schema.put("originalRef", voName);
|
||||
schema.put("$ref", DEFINITION + voName);
|
||||
}
|
||||
parameter.put("schema", schema);
|
||||
parameters.add(parameter);
|
||||
} else {
|
||||
Object object = JsonUtils.readValue(info.getRequestBody(), Object.class);
|
||||
boolean isListOrMap = (object instanceof List || object instanceof Map);
|
||||
if (isListOrMap && BooleanLiteral.isTrue(object)) {
|
||||
parameters.add(SwaggerEntity.createParameter(false, VAR_NAME_REQUEST_BODY, VAR_NAME_REQUEST_BODY, object instanceof List ? VAR_NAME_REQUEST_BODY_VALUE_TYPE_ARRAY : VAR_NAME_REQUEST_BODY_VALUE_TYPE_OBJECT, null, object));
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private Map<String, Object> parseResponse(ApiInfo info) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
BaseDefinition baseDefinition = info.getResponseBodyDefinition();
|
||||
if (!CollectionUtils.isEmpty(baseDefinition.getChildren())) {
|
||||
String groupName = magicResourceService.getGroupName(info.getGroupId()).replace("/", "-");
|
||||
String voName = groupName + "«" + info.getPath().replaceFirst("/", "").replaceAll("/", "_") + "«response«";
|
||||
voName += "root_" + baseDefinition.getName() + "»»»";
|
||||
|
||||
Map<String, Object> schema = new HashMap<>(2);
|
||||
schema.put("originalRef", voName);
|
||||
schema.put("$ref", DEFINITION + voName);
|
||||
|
||||
Map<String, Object> response = new HashMap<>(2);
|
||||
response.put("description", "OK");
|
||||
response.put("schema", schema);
|
||||
result.put("200", response);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, Object> doProcessDefinition(BaseDefinition target, ApiInfo info, String groupName, String parentName, String definitionType, int level) {
|
||||
Map<String, Object> result = new HashMap<>(4);
|
||||
result.put("description", target.getDescription());
|
||||
if (DataType.Array == target.getDataType()) {
|
||||
if (!CollectionUtils.isEmpty(target.getChildren())) {
|
||||
result.put("items", doProcessDefinition(target.getChildren().get(0), info, groupName, parentName + target.getName() + "_", definitionType, level + 1));
|
||||
} else {
|
||||
result.put("items", Collections.emptyList());
|
||||
}
|
||||
result.put("type", target.getDataType().getJavascriptType());
|
||||
} else if (DataType.Object == target.getDataType()) {
|
||||
String voName = groupName + "«" + info.getPath().replaceFirst("/", "").replaceAll("/", "_") + (StringUtils.equals("response", definitionType) ? "«response«" : "«request«") + parentName + target.getName() + "»»»";
|
||||
|
||||
Map<String, Object> definition = new HashMap<>(4);
|
||||
Map<String, Map<String, Object>> properties = new HashMap<>(target.getChildren().size());
|
||||
Set<String> requiredSet = new HashSet<>(target.getChildren().size());
|
||||
for (BaseDefinition obj : target.getChildren()) {
|
||||
properties.put(obj.getName(), doProcessDefinition(obj, info, groupName, parentName + target.getName() + "_", definitionType, level + 1));
|
||||
if (obj.isRequired()) {
|
||||
requiredSet.add(obj.getName());
|
||||
}
|
||||
}
|
||||
definition.put("properties", properties);
|
||||
definition.put("description", target.getDescription());
|
||||
definition.put("type", target.getDataType().getJavascriptType());
|
||||
definition.put("required", requiredSet);
|
||||
if (this.DEFINITION_MAP.containsKey(voName)) {
|
||||
// TODO 应该不会出现名字都一样的
|
||||
voName = voName.replace("»»»", "_" + level + "»»»");
|
||||
}
|
||||
|
||||
this.DEFINITION_MAP.put(voName, definition);
|
||||
result.put("originalRef", voName);
|
||||
result.put("$ref", DEFINITION + voName);
|
||||
|
||||
} else {
|
||||
result.put("example", target.getValue());
|
||||
result.put("type", target.getDataType().getJavascriptType());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.ssssssss.magicapi.swagger.MagicSwaggerConfiguration
|
||||
Reference in New Issue
Block a user