Optimize the generation of openapi and postman collection

This commit is contained in:
oppofind 2020-11-30 01:16:15 +08:00
parent 1d43300b00
commit 9c404e5f81
23 changed files with 1293 additions and 328 deletions

View File

@ -11,16 +11,18 @@ import com.power.doc.model.*;
import com.power.doc.template.SpringBootDocBuildTemplate; import com.power.doc.template.SpringBootDocBuildTemplate;
import com.power.doc.utils.DocUtil; import com.power.doc.utils.DocUtil;
import com.thoughtworks.qdox.JavaProjectBuilder; import com.thoughtworks.qdox.JavaProjectBuilder;
import org.jetbrains.annotations.NotNull;
import java.util.*; import java.util.*;
/** /**
* @author xingzi * @author xingzi
*/ */
public class OpenApiBuilder { public class OpenApiBuilder {
//过滤url中的特殊字符 //过滤url中的特殊字符
private static final String PATH_REGEX ="[/{};\\t+]"; private static final String PATH_REGEX = "[/{};\\t+]";
/** /**
* 构建postman json * 构建postman json
* *
@ -49,7 +51,8 @@ public class OpenApiBuilder {
/** /**
* 构建openApi 文件 * 构建openApi 文件
* @param config 配置文件 *
* @param config 配置文件
* @param configBuilder * @param configBuilder
*/ */
private static void openApiCreate(ApiConfig config, ProjectDocConfigBuilder configBuilder) { private static void openApiCreate(ApiConfig config, ProjectDocConfigBuilder configBuilder) {
@ -57,7 +60,7 @@ public class OpenApiBuilder {
SpringBootDocBuildTemplate docBuildTemplate = new SpringBootDocBuildTemplate(); SpringBootDocBuildTemplate docBuildTemplate = new SpringBootDocBuildTemplate();
List<ApiDoc> apiDocList = docBuildTemplate.getApiData(configBuilder); List<ApiDoc> apiDocList = docBuildTemplate.getApiData(configBuilder);
Map<String, Object> json = new HashMap<>(8); Map<String, Object> json = new HashMap<>(8);
json.put("openapi", "3.0.0"); json.put("openapi", "3.0.3");
json.put("info", buildInfo(config)); json.put("info", buildInfo(config));
json.put("servers", buildServers(config)); json.put("servers", buildServers(config));
json.put("paths", buildPaths(apiDocList)); json.put("paths", buildPaths(apiDocList));
@ -74,6 +77,7 @@ public class OpenApiBuilder {
/** /**
* info 信息 * info 信息
*
* @param apiConfig 文档配置信息 * @param apiConfig 文档配置信息
* @return * @return
*/ */
@ -83,20 +87,24 @@ public class OpenApiBuilder {
infoMap.put("version", "1.0.0"); infoMap.put("version", "1.0.0");
return infoMap; return infoMap;
} }
/** /**
* server 信息 * server 信息
*
* @param config 文档配置信息 * @param config 文档配置信息
* @return * @return
*/ */
private static List<Map<String, Object>> buildServers(ApiConfig config) { private static List<Map<String, Object>> buildServers(ApiConfig config) {
List<Map<String, Object>> serverList = new ArrayList<>(); List<Map<String, Object>> serverList = new ArrayList<>();
Map<String, Object> serverMap = new HashMap<>(8); Map<String, Object> serverMap = new HashMap<>(8);
serverMap.put("url", config.getServerUrl() == null ? "http://127.0.0.1" : config.getServerUrl()); serverMap.put("url", config.getServerUrl() == null ? "" : config.getServerUrl());
serverList.add(serverMap); serverList.add(serverMap);
return serverList; return serverList;
} }
/** /**
* 构建path数据 url请求 * 构建path数据 url请求
*
* @param apiDocList api列表 * @param apiDocList api列表
* @return * @return
*/ */
@ -123,10 +131,12 @@ public class OpenApiBuilder {
); );
return pathMap; return pathMap;
} }
/** /**
* paths 设置url请求方式 * paths 设置url请求方式
*
* @param apiMethodDoc 方法参数 * @param apiMethodDoc 方法参数
* @param apiDoc 类参数 * @param apiDoc 类参数
* @return * @return
*/ */
private static Map<String, Object> buildPathUrls(ApiMethodDoc apiMethodDoc, ApiDoc apiDoc) { private static Map<String, Object> buildPathUrls(ApiMethodDoc apiMethodDoc, ApiDoc apiDoc) {
@ -134,10 +144,12 @@ public class OpenApiBuilder {
request.put(apiMethodDoc.getType().toLowerCase(), buildPathUrlsRequest(apiMethodDoc, apiDoc)); request.put(apiMethodDoc.getType().toLowerCase(), buildPathUrlsRequest(apiMethodDoc, apiDoc));
return request; return request;
} }
/** /**
* url的基本信息 信息简介summary 详情description 所属分类tags 请求参数parameter 请求体request 返回值responses * url的基本信息 信息简介summary 详情description 所属分类tags 请求参数parameter 请求体request 返回值responses
*
* @param apiMethodDoc 方法参数 * @param apiMethodDoc 方法参数
* @param apiDoc 类参数 * @param apiDoc 类参数
* @return * @return
*/ */
private static Map<String, Object> buildPathUrlsRequest(ApiMethodDoc apiMethodDoc, ApiDoc apiDoc) { private static Map<String, Object> buildPathUrlsRequest(ApiMethodDoc apiMethodDoc, ApiDoc apiDoc) {
@ -148,25 +160,22 @@ public class OpenApiBuilder {
request.put("requestBody", buildRequestBody(apiMethodDoc)); request.put("requestBody", buildRequestBody(apiMethodDoc));
request.put("parameters", buildParameters(apiMethodDoc)); request.put("parameters", buildParameters(apiMethodDoc));
request.put("responses", buildResponses(apiMethodDoc)); request.put("responses", buildResponses(apiMethodDoc));
request.put("deprecated", apiMethodDoc.isDeprecated());
request.put("operationId", apiMethodDoc.getMethodId());
return request; return request;
} }
/** /**
* 请求体构建 只针对post请求 并且请求体不为null * 请求体构建 只针对post请求 并且请求体不为null
*
* @param apiMethodDoc 方法参数 * @param apiMethodDoc 方法参数
* @return * @return
*/ */
private static Map<String, Object> buildRequestBody(ApiMethodDoc apiMethodDoc) { private static Map<String, Object> buildRequestBody(ApiMethodDoc apiMethodDoc) {
int size = 0;
Map<String, Object> requestBody = new HashMap<>(8); Map<String, Object> requestBody = new HashMap<>(8);
//判断请求体去除pathVariable参数后是否为null boolean isPost = (apiMethodDoc.getType().equals(Methods.POST.getValue())
if(!CollectionUtil.isEmpty(apiMethodDoc.getRequestParams())) { || apiMethodDoc.getType().equals(Methods.PUT.getValue()) ||
List<ApiParam> apiParams = apiMethodDoc.getRequestParams(); apiMethodDoc.getType().equals(Methods.PATCH.getValue()));
//去除pathVariable参数
size = (int) apiParams.stream()
.filter(apiParam -> !apiParam.isPathParam()).count();
}
boolean isPost = (apiMethodDoc.getType().equals(Methods.POST.getValue()) || apiMethodDoc.getType().equals(Methods.PUT.getValue()) ||
apiMethodDoc.getType().equals(Methods.PATCH.getValue())) && size > 0;
//如果是post请求 且包含请求体 //如果是post请求 且包含请求体
if (isPost) { if (isPost) {
requestBody.put("content", buildContent(apiMethodDoc, false)); requestBody.put("content", buildContent(apiMethodDoc, false));
@ -175,34 +184,79 @@ public class OpenApiBuilder {
return null; return null;
} }
/** /**
* 构建content信息 responses requestBody 都需要content信息 * 构建content信息 responses requestBody 都需要content信息
*
* @param apiMethodDoc 方法参数 * @param apiMethodDoc 方法参数
* @param isRep 是否是返回数据 * @param isRep 是否是返回数据
* @return * @return
*/ */
private static Map<String, Object> buildContent(ApiMethodDoc apiMethodDoc, boolean isRep) { private static Map<String, Object> buildContent(ApiMethodDoc apiMethodDoc, boolean isRep) {
Map<String, Object> content = new HashMap<>(8); Map<String, Object> content = new HashMap<>(8);
content.put(apiMethodDoc.getContentType(), buildContentBody(apiMethodDoc, isRep)); String contentType = apiMethodDoc.getContentType();
if (isRep) {
contentType = "*/*";
}
content.put(contentType, buildContentBody(apiMethodDoc, isRep));
return content; return content;
} }
/** /**
* 构建content的数据内容 * 构建content的数据内容
*
* @param apiMethodDoc 方法参数 * @param apiMethodDoc 方法参数
* @param isRep 是否是返回数据 * @param isRep 是否是返回数据
* @return * @return
*/ */
private static Map<String, Object> buildContentBody(ApiMethodDoc apiMethodDoc, boolean isRep) { private static Map<String, Object> buildContentBody(ApiMethodDoc apiMethodDoc, boolean isRep) {
Map<String, Object> content = new HashMap<>(8); Map<String, Object> content = new HashMap<>(8);
content.put("schema", buildBodySchema(apiMethodDoc.getPath(), isRep)); if (Objects.nonNull(apiMethodDoc.getReturnSchema()) && isRep) {
content.put("schema", apiMethodDoc.getReturnSchema());
} else {
if (!isRep && apiMethodDoc.getContentType().equals(DocGlobalConstants.MULTIPART_TYPE)) {
// formdata
Map<String, Object> map = new LinkedHashMap<>();
map.put("type", "object");
Map<String, Object> properties = new LinkedHashMap<>();
Map<String, Object> detail;
for (ApiParam apiParam : apiMethodDoc.getQueryParams()) {
detail = new HashMap<>();
detail.put("type", apiParam.getType());
detail.put("description", apiParam.getDesc());
detail.put("example", apiParam.getValue());
if ("file".equals(apiParam.getType())) {
if (apiParam.isHasItems()) {
detail.put("type", "array");
Map<String, Object> items = new HashMap<>();
items.put("type", "string");
items.put("format", "binary");
detail.put("items", items);
} else {
detail.put("format", "binary");
}
}
properties.put(apiParam.getField(), detail);
}
map.put("properties", properties);
content.put("schema", map);
} else if (!isRep && Objects.nonNull(apiMethodDoc.getRequestSchema())) {
content.put("schema", apiMethodDoc.getRequestSchema());
} else {
content.put("schema", buildBodySchema(apiMethodDoc.getPath(), isRep));
}
}
content.put("examples", buildBodyExample(apiMethodDoc, isRep)); content.put("examples", buildBodyExample(apiMethodDoc, isRep));
return content; return content;
} }
/** /**
* content body 的schema 信息 * content body 的schema 信息
* @param url 请求的url 去除server *
* @param url 请求的url 去除server
* @param isRep 是否是返回数据 * @param isRep 是否是返回数据
* @return * @return
*/ */
@ -216,10 +270,12 @@ public class OpenApiBuilder {
} }
return schema; return schema;
} }
/** /**
* 信息样例 请求和返回的信息样例 * 信息样例 请求和返回的信息样例
*
* @param apiMethodDoc 方法参数 * @param apiMethodDoc 方法参数
* @param isRep 是否是返回数据 * @param isRep 是否是返回数据
* @return * @return
*/ */
private static Map<String, Object> buildBodyExample(ApiMethodDoc apiMethodDoc, boolean isRep) { private static Map<String, Object> buildBodyExample(ApiMethodDoc apiMethodDoc, boolean isRep) {
@ -228,10 +284,12 @@ public class OpenApiBuilder {
return content; return content;
} }
/** /**
* 信息样例数据构建 此处请求体requestBody构建完成 * 信息样例数据构建 此处请求体requestBody构建完成
*
* @param apiMethodDoc 方法参数 * @param apiMethodDoc 方法参数
* @param isRep 是否为返回数据 * @param isRep 是否为返回数据
* @return * @return
*/ */
private static Map<String, Object> buildExampleData(ApiMethodDoc apiMethodDoc, boolean isRep) { private static Map<String, Object> buildExampleData(ApiMethodDoc apiMethodDoc, boolean isRep) {
@ -250,31 +308,32 @@ public class OpenApiBuilder {
/** /**
* 构建请求参数 用于get请求 @PathVariable Header 参数构建 * 构建请求参数 用于get请求 @PathVariable Header 参数构建
*
* @param apiMethodDoc 方法体 * @param apiMethodDoc 方法体
* @return * @return
*/ */
private static List<Map<String, Object>> buildParameters(ApiMethodDoc apiMethodDoc) { private static List<Map<String, Object>> buildParameters(ApiMethodDoc apiMethodDoc) {
Map<String, Object> parameters; Map<String, Object> parameters;
List<Map<String, Object>> parametersList = new ArrayList<>(); List<Map<String, Object>> parametersList = new ArrayList<>();
//如果是get请求 包含@pathvariable for (ApiParam apiParam : apiMethodDoc.getPathParams()) {
if (apiMethodDoc.getType().equals(Methods.GET.getValue()) || apiMethodDoc.getPath().contains("{")) { parameters = getStringParams(apiParam);
if (apiMethodDoc.getRequestParams() == null) { parameters.put("in", "path");
return null; List<ApiParam> children = apiParam.getChildren();
} if (CollectionUtil.isEmpty(children)) {
for (ApiParam apiParam : apiMethodDoc.getRequestParams()) {
parameters = new HashMap<>(20);
parameters.put("name", apiParam.getField());
parameters.put("description", apiParam.getDesc());
parameters.put("required", apiParam.isRequired());
parameters.put("schema", buildParametersSchema(apiParam));
if (apiParam.isPathParam()) {
parameters.put("in", "path");
} else {
parameters.put("in", "query");
}
parametersList.add(parameters); parametersList.add(parameters);
} }
} }
// not handle form data
if (!apiMethodDoc.getContentType().equals(DocGlobalConstants.MULTIPART_TYPE)) {
for (ApiParam apiParam : apiMethodDoc.getQueryParams()) {
parameters = getStringParams(apiParam);
parameters.put("in", "query");
List<ApiParam> children = apiParam.getChildren();
if (CollectionUtil.isEmpty(children)) {
parametersList.add(parameters);
}
}
}
//如果包含请求头 //如果包含请求头
if (!CollectionUtil.isEmpty(apiMethodDoc.getRequestHeaders())) { if (!CollectionUtil.isEmpty(apiMethodDoc.getRequestHeaders())) {
for (ApiReqHeader header : apiMethodDoc.getRequestHeaders()) { for (ApiReqHeader header : apiMethodDoc.getRequestHeaders()) {
@ -289,8 +348,22 @@ public class OpenApiBuilder {
} }
return parametersList; return parametersList;
} }
@NotNull
private static Map<String, Object> getStringParams(ApiParam apiParam) {
Map<String, Object> parameters;
parameters = new HashMap<>(20);
parameters.put("name", apiParam.getField());
parameters.put("description", apiParam.getDesc());
parameters.put("required", apiParam.isRequired());
parameters.put("example", StringUtil.removeQuotes(apiParam.getValue()));
parameters.put("schema", buildParametersSchema(apiParam));
return parameters;
}
/** /**
* 如果是get请求或者是@PathVariable 设置请求参数 * 如果是get请求或者是@PathVariable 设置请求参数
*
* @param apiParam 参数信息 * @param apiParam 参数信息
* @return * @return
*/ */
@ -303,12 +376,14 @@ public class OpenApiBuilder {
schema.put("format", "binary"); schema.put("format", "binary");
} }
} else { } else {
schema.put("format", "int16".equals(apiParam.getType())?"int32":apiParam.getType()); schema.put("format", "int16".equals(apiParam.getType()) ? "int32" : apiParam.getType());
} }
return schema; return schema;
} }
/** /**
* 如果包含header 设置请求参数 * 如果包含header 设置请求参数
*
* @param header 参数信息 * @param header 参数信息
* @return * @return
*/ */
@ -316,11 +391,13 @@ public class OpenApiBuilder {
Map<String, Object> schema = new HashMap<>(10); Map<String, Object> schema = new HashMap<>(10);
String openApiType = DocUtil.javaTypeToOpenApiTypeConvert(header.getType()); String openApiType = DocUtil.javaTypeToOpenApiTypeConvert(header.getType());
schema.put("type", openApiType); schema.put("type", openApiType);
schema.put("format", "int16".equals(header.getType())?"int32":header.getType()); schema.put("format", "int16".equals(header.getType()) ? "int32" : header.getType());
return schema; return schema;
} }
/** /**
* 构建返回信息 * 构建返回信息
*
* @param apiMethodDoc 方法参数 * @param apiMethodDoc 方法参数
* @return * @return
*/ */
@ -329,22 +406,23 @@ public class OpenApiBuilder {
response.put("200", buildResponsesBody(apiMethodDoc)); response.put("200", buildResponsesBody(apiMethodDoc));
return response; return response;
} }
/** /**
* 构建返回信息实体 * 构建返回信息实体
*
* @param apiMethodDoc 方法参数 * @param apiMethodDoc 方法参数
* @return * @return
*/ */
private static Map<String, Object> buildResponsesBody(ApiMethodDoc apiMethodDoc) { private static Map<String, Object> buildResponsesBody(ApiMethodDoc apiMethodDoc) {
Map<String, Object> responseBody = new HashMap<>(10); Map<String, Object> responseBody = new HashMap<>(10);
responseBody.put("description", "a pet to be returned"); responseBody.put("description", "OK");
if (!CollectionUtil.isEmpty(apiMethodDoc.getResponseParams())) { responseBody.put("content", buildContent(apiMethodDoc, true));
responseBody.put("content", buildContent(apiMethodDoc, true));
}
return responseBody; return responseBody;
} }
/** /**
* 构建component * 构建component
*
* @param apiDocs 请求列表 * @param apiDocs 请求列表
* @return * @return
*/ */
@ -358,7 +436,12 @@ public class OpenApiBuilder {
method -> { method -> {
//request components //request components
List<ApiParam> requestParams = method.getRequestParams(); List<ApiParam> requestParams = method.getRequestParams();
component.put(method.getPath().replaceAll(PATH_REGEX, "_") + "request", buildProperties(requestParams)); if (CollectionUtil.isNotEmpty(requestParams)) {
Map<String, Object> prop = buildProperties(requestParams);
if (Objects.nonNull(prop) && prop.size() > 0) {
component.put(method.getPath().replaceAll(PATH_REGEX, "_") + "request", buildProperties(requestParams));
}
}
//response components //response components
List<ApiParam> responseParams = method.getResponseParams(); List<ApiParam> responseParams = method.getResponseParams();
component.put(method.getPath().replaceAll(PATH_REGEX, "_") + "response", buildProperties(responseParams)); component.put(method.getPath().replaceAll(PATH_REGEX, "_") + "response", buildProperties(responseParams));
@ -372,24 +455,32 @@ public class OpenApiBuilder {
/** /**
* component schema properties 信息 * component schema properties 信息
*
* @param apiParam 参数列表 * @param apiParam 参数列表
* @return * @return
*/ */
private static Map<String, Object> buildProperties(List<ApiParam> apiParam) { private static Map<String, Object> buildProperties(List<ApiParam> apiParam) {
Map<String, Object> component = new HashMap<>(); Map<String, Object> component = new HashMap<>();
Map<String, Object> propertiesData = new HashMap<>(); Map<String, Object> propertiesData = new LinkedHashMap<>();
List<String> requiredList = new ArrayList<>(); List<String> requiredList = new ArrayList<>();
if (apiParam != null) { if (apiParam != null) {
int paramsSize = apiParam.size();
for (ApiParam param : apiParam) { for (ApiParam param : apiParam) {
if (param.isRequired()) { if (param.isRequired()) {
requiredList.add(param.getField()); requiredList.add(param.getField());
} }
if (param.getType().equals("map") && paramsSize == 1) {
continue;
}
if (param.isQueryParam() || param.isPathParam()) {
continue;
}
String field = param.getField(); String field = param.getField();
propertiesData.put(field, buildPropertiesData(param)); propertiesData.put(field, buildPropertiesData(param));
} }
component.put("properties", propertiesData); if (!propertiesData.isEmpty()) {
component.put("properties", propertiesData);
}
if (!CollectionUtil.isEmpty(requiredList)) { if (!CollectionUtil.isEmpty(requiredList)) {
component.put("required", requiredList); component.put("required", requiredList);
} }
@ -399,8 +490,10 @@ public class OpenApiBuilder {
} }
} }
/** /**
* component schema properties 实体信息构建 * component schema properties 实体信息构建
*
* @param apiParam 参数基本信息 * @param apiParam 参数基本信息
* @return * @return
*/ */
@ -422,8 +515,8 @@ public class OpenApiBuilder {
if (apiParam.getChildren() != null) { if (apiParam.getChildren() != null) {
propertiesData.put("type", "object"); propertiesData.put("type", "object");
propertiesData.put("description", apiParam.getDesc() + "(object)"); propertiesData.put("description", apiParam.getDesc() + "(object)");
propertiesData.put("properties",buildProperties(apiParam.getChildren()).get("properties")); propertiesData.put("properties", buildProperties(apiParam.getChildren()).get("properties"));
propertiesData.put("requires",buildProperties(apiParam.getChildren()).get("requires")); propertiesData.put("requires", buildProperties(apiParam.getChildren()).get("requires"));
} }
} }
if ("array".equals(apiParam.getType())) { if ("array".equals(apiParam.getType())) {

View File

@ -28,20 +28,22 @@ import com.google.gson.GsonBuilder;
import com.power.common.util.FileUtil; import com.power.common.util.FileUtil;
import com.power.common.util.StringUtil; import com.power.common.util.StringUtil;
import com.power.doc.constants.DocGlobalConstants; import com.power.doc.constants.DocGlobalConstants;
import com.power.doc.model.ApiConfig; import com.power.doc.model.*;
import com.power.doc.model.ApiDoc;
import com.power.doc.model.ApiMethodDoc;
import com.power.doc.model.ApiReqHeader;
import com.power.doc.model.postman.InfoBean; import com.power.doc.model.postman.InfoBean;
import com.power.doc.model.postman.ItemBean; import com.power.doc.model.postman.ItemBean;
import com.power.doc.model.postman.RequestItem; import com.power.doc.model.postman.RequestItem;
import com.power.doc.model.postman.UrlBean;
import com.power.doc.model.postman.request.ParamBean;
import com.power.doc.model.postman.request.RequestBean; import com.power.doc.model.postman.request.RequestBean;
import com.power.doc.model.postman.request.body.BodyBean; import com.power.doc.model.postman.request.body.BodyBean;
import com.power.doc.model.postman.request.header.HeaderBean; import com.power.doc.model.postman.request.header.HeaderBean;
import com.power.doc.template.IDocBuildTemplate; import com.power.doc.template.IDocBuildTemplate;
import com.power.doc.template.SpringBootDocBuildTemplate; import com.power.doc.template.SpringBootDocBuildTemplate;
import com.power.doc.utils.PathUtil;
import com.thoughtworks.qdox.JavaProjectBuilder; import com.thoughtworks.qdox.JavaProjectBuilder;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -119,13 +121,59 @@ public class PostmanJsonBuilder {
requestBean.setHeader(buildHeaderBeanList(apiMethodDoc)); requestBean.setHeader(buildHeaderBeanList(apiMethodDoc));
requestBean.setBody(buildBodyBean(apiMethodDoc)); requestBean.setBody(buildBodyBean(apiMethodDoc));
requestBean.setUrl(apiMethodDoc.getRequestExample().getUrl() == null ? apiMethodDoc.getUrl() : apiMethodDoc.getRequestExample().getUrl()); requestBean.setUrl(buildUrlBean(apiMethodDoc));
item.setRequest(requestBean); item.setRequest(requestBean);
return item; return item;
} }
private static UrlBean buildUrlBean(ApiMethodDoc apiMethodDoc) {
UrlBean urlBean = new UrlBean();
String url = apiMethodDoc.getRequestExample().getUrl() == null ? apiMethodDoc.getUrl() : apiMethodDoc.getRequestExample().getUrl();
urlBean.setRaw(PathUtil.toPostmanPath(url));
try {
URL url1 = new java.net.URL(apiMethodDoc.getServerUrl());
urlBean.setPort(String.valueOf(url1.getPort()));
List<String> hosts = new ArrayList<>();
hosts.add(url1.getHost());
urlBean.setHost(hosts);
} catch (MalformedURLException e) {
}
String shortUrl = PathUtil.toPostmanPath(apiMethodDoc.getPath());
String[] paths = shortUrl.split("/");
List<String> pathList = new ArrayList<>();
for (String str : paths) {
if (StringUtil.isNotEmpty(str)) {
pathList.add(str);
}
}
if (shortUrl.endsWith("/")) {
pathList.add("");
}
urlBean.setPath(pathList);
List<ParamBean> queryParams = new ArrayList<>();
for (ApiParam apiParam : apiMethodDoc.getQueryParams()) {
ParamBean queryParam = new ParamBean();
queryParam.setDescription(apiParam.getDesc());
queryParam.setKey(apiParam.getField());
queryParam.setValue(apiParam.getValue());
queryParams.add(queryParam);
}
List<ParamBean> variables = new ArrayList<>();
for (ApiParam apiParam : apiMethodDoc.getPathParams()) {
ParamBean queryParam = new ParamBean();
queryParam.setDescription(apiParam.getDesc());
queryParam.setKey(apiParam.getField());
queryParam.setValue(apiParam.getValue());
variables.add(queryParam);
}
urlBean.setVariable(variables);
urlBean.setQuery(queryParams);
return urlBean;
}
/** /**
* 构造请求体 * 构造请求体
* *

View File

@ -71,7 +71,7 @@ public interface DocGlobalConstants {
String POSTMAN_JSON = "/postman.json"; String POSTMAN_JSON = "/postman.json";
String OPEN_API_JSON = "/openApi3.0.json"; String OPEN_API_JSON = "/openapi.json";
String CONTROLLER_FULLY = "org.springframework.stereotype.Controller"; String CONTROLLER_FULLY = "org.springframework.stereotype.Controller";

View File

@ -109,6 +109,9 @@ public class JsonBuildHelper {
} }
} }
if (JavaClassValidateUtil.isPrimitive(typeName)) { if (JavaClassValidateUtil.isPrimitive(typeName)) {
if(DocGlobalConstants.JAVA_STRING_FULLY.equals(typeName)){
return "string";
}
return StringUtil.removeQuotes(DocUtil.jsonValueByType(typeName)); return StringUtil.removeQuotes(DocUtil.jsonValueByType(typeName));
} }
if (javaClass.isEnum()) { if (javaClass.isEnum()) {

View File

@ -216,8 +216,14 @@ public class ParamsBuildHelper {
continue; continue;
} }
if (JavaClassValidateUtil.isPrimitive(subTypeName)) { if (JavaClassValidateUtil.isPrimitive(subTypeName)) {
String fieldValue = "";
if (tagsMap.containsKey(DocTags.MOCK) && StringUtil.isNotEmpty(tagsMap.get(DocTags.MOCK))) {
fieldValue = tagsMap.get(DocTags.MOCK);
} else {
fieldValue = DocUtil.getValByTypeAndFieldName(typeSimpleName, field.getName());
}
ApiParam param = ApiParam.of().setField(pre + fieldName); ApiParam param = ApiParam.of().setField(pre + fieldName);
param.setPid(pid); param.setPid(pid).setValue(fieldValue);
String processedType = isShowJavaType ? typeSimpleName : DocClassUtil.processTypeNameForParams(typeSimpleName.toLowerCase()); String processedType = isShowJavaType ? typeSimpleName : DocClassUtil.processTypeNameForParams(typeSimpleName.toLowerCase());
param.setType(processedType); param.setType(processedType);
if (StringUtil.isNotEmpty(comment)) { if (StringUtil.isNotEmpty(comment)) {

View File

@ -26,6 +26,7 @@ import com.power.doc.model.request.ApiRequestExample;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* java api method info model. * java api method info model.
@ -149,6 +150,16 @@ public class ApiMethodDoc implements Serializable {
*/ */
private boolean deprecated; private boolean deprecated;
/**
* return schema
*/
private Map<String,Object> returnSchema;
/**
* request schema
*/
private Map<String,Object> requestSchema;
public String getMethodId() { public String getMethodId() {
return methodId; return methodId;
@ -318,6 +329,23 @@ public class ApiMethodDoc implements Serializable {
this.queryParams = queryParams; this.queryParams = queryParams;
} }
public Map<String, Object> getReturnSchema() {
return returnSchema;
}
public void setReturnSchema(Map<String, Object> returnSchema) {
this.returnSchema = returnSchema;
}
public Map<String, Object> getRequestSchema() {
return requestSchema;
}
public void setRequestSchema(Map<String, Object> requestSchema) {
this.requestSchema = requestSchema;
}
@Override @Override
public String toString() { public String toString() {
final StringBuilder sb = new StringBuilder("{"); final StringBuilder sb = new StringBuilder("{");

View File

@ -0,0 +1,77 @@
/*
* smart-doc
*
* Copyright (C) 2018-2020 smart-doc
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.power.doc.model;
import java.util.List;
/**
* @author yu 2020/11/26.
*/
public class ApiMethodReqParam {
/**
* path params
*/
private List<ApiParam> pathParams;
/**
* query params
*/
private List<ApiParam> queryParams;
/**
* http request params
*/
private List<ApiParam> requestParams;
public static ApiMethodReqParam builder(){
return new ApiMethodReqParam();
}
public List<ApiParam> getPathParams() {
return pathParams;
}
public ApiMethodReqParam setPathParams(List<ApiParam> pathParams) {
this.pathParams = pathParams;
return this;
}
public List<ApiParam> getQueryParams() {
return queryParams;
}
public ApiMethodReqParam setQueryParams(List<ApiParam> queryParams) {
this.queryParams = queryParams;
return this;
}
public List<ApiParam> getRequestParams() {
return requestParams;
}
public ApiMethodReqParam setRequestParams(List<ApiParam> requestParams) {
this.requestParams = requestParams;
return this;
}
}

View File

@ -23,6 +23,7 @@
package com.power.doc.model; package com.power.doc.model;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* @author yu 2019/9/27. * @author yu 2019/9/27.
@ -75,7 +76,7 @@ public class ApiParam {
private boolean queryParam; private boolean queryParam;
/** /**
* * param mock value
*/ */
private String value; private String value;
@ -84,6 +85,11 @@ public class ApiParam {
*/ */
private List<ApiParam> children; private List<ApiParam> children;
/**
* openapi items
*/
private boolean hasItems;
public static ApiParam of(){ public static ApiParam of(){
return new ApiParam(); return new ApiParam();
} }
@ -187,6 +193,15 @@ public class ApiParam {
return this; return this;
} }
public boolean isHasItems() {
return hasItems;
}
public ApiParam setHasItems(boolean hasItems) {
this.hasItems = hasItems;
return this;
}
@Override @Override
public String toString() { public String toString() {
final StringBuilder sb = new StringBuilder("{"); final StringBuilder sb = new StringBuilder("{");

View File

@ -13,6 +13,10 @@ public class DocJavaMethod {
private JavaMethod javaMethod; private JavaMethod javaMethod;
private Map<String,Object> returnSchema;
private Map<String,Object> requestSchema;
private Map<String, JavaType> actualTypesMap; private Map<String, JavaType> actualTypesMap;
public static DocJavaMethod builder(){ public static DocJavaMethod builder(){
@ -36,4 +40,22 @@ public class DocJavaMethod {
this.actualTypesMap = actualTypesMap; this.actualTypesMap = actualTypesMap;
return this; return this;
} }
public Map<String,Object> getReturnSchema() {
return returnSchema;
}
public DocJavaMethod setReturnSchema(Map<String,Object> returnSchema) {
this.returnSchema = returnSchema;
return this;
}
public Map<String, Object> getRequestSchema() {
return requestSchema;
}
public DocJavaMethod setRequestSchema(Map<String, Object> requestSchema) {
this.requestSchema = requestSchema;
return this;
}
} }

View File

@ -0,0 +1,69 @@
package com.power.doc.model.postman;
import com.power.doc.model.postman.request.ParamBean;
import java.util.List;
/**
* @author yu 2020/11/28.
*/
public class UrlBean {
private String raw;
private List<String> path;
private List<String> host;
private String port;
private List<ParamBean> query;
private List<ParamBean> variable;
public String getRaw() {
return raw;
}
public void setRaw(String raw) {
this.raw = raw;
}
public List<String> getPath() {
return path;
}
public void setPath(List<String> path) {
this.path = path;
}
public List<ParamBean> getQuery() {
return query;
}
public void setQuery(List<ParamBean> query) {
this.query = query;
}
public List<ParamBean> getVariable() {
return variable;
}
public void setVariable(List<ParamBean> variable) {
this.variable = variable;
}
public List<String> getHost() {
return host;
}
public void setHost(List<String> host) {
this.host = host;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
}

View File

@ -0,0 +1,34 @@
package com.power.doc.model.postman.request;
/**
* @author yu 2020/11/28.
*/
public class ParamBean {
private String key;
private String value;
private String description;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

View File

@ -1,79 +1,80 @@
/* /*
* smart-doc https://github.com/shalousun/smart-doc * smart-doc https://github.com/shalousun/smart-doc
* *
* Copyright (C) 2018-2020 smart-doc * Copyright (C) 2018-2020 smart-doc
* *
* Licensed to the Apache Software Foundation (ASF) under one * Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file * or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information * distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file * regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the * to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance * "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at * with the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, * Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an * software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the * KIND, either express or implied. See the License for the
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package com.power.doc.model.postman.request; package com.power.doc.model.postman.request;
import com.power.doc.model.postman.request.body.BodyBean; import com.power.doc.model.postman.UrlBean;
import com.power.doc.model.postman.request.header.HeaderBean; import com.power.doc.model.postman.request.body.BodyBean;
import com.power.doc.model.postman.request.header.HeaderBean;
import java.util.List;
import java.util.List;
/**
* @author xingzi /**
*/ * @author xingzi
public class RequestBean { */
private String method; public class RequestBean {
private BodyBean body; private String method;
private String url; private BodyBean body;
private String description; private UrlBean url;
private List<HeaderBean> header; private String description;
private List<HeaderBean> header;
public String getMethod() {
return method; public String getMethod() {
} return method;
}
public void setMethod(String method) {
this.method = method; public void setMethod(String method) {
} this.method = method;
}
public BodyBean getBody() {
return body; public BodyBean getBody() {
} return body;
}
public void setBody(BodyBean body) {
this.body = body; public void setBody(BodyBean body) {
} this.body = body;
}
public String getUrl() {
return url; public UrlBean getUrl() {
} return url;
}
public void setUrl(String url) {
this.url = url; public void setUrl(UrlBean url) {
} this.url = url;
}
public String getDescription() {
return description; public String getDescription() {
} return description;
}
public void setDescription(String description) {
this.description = description; public void setDescription(String description) {
} this.description = description;
}
public List<HeaderBean> getHeader() {
return header; public List<HeaderBean> getHeader() {
} return header;
}
public void setHeader(List<HeaderBean> header) {
this.header = header; public void setHeader(List<HeaderBean> header) {
} this.header = header;
} }
}

View File

@ -1,88 +1,86 @@
/* /*
* smart-doc https://github.com/shalousun/smart-doc * smart-doc https://github.com/shalousun/smart-doc
* *
* Copyright (C) 2018-2020 smart-doc * Copyright (C) 2018-2020 smart-doc
* *
* Licensed to the Apache Software Foundation (ASF) under one * Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file * or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information * distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file * regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the * to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance * "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at * with the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, * Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an * software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the * KIND, either express or implied. See the License for the
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package com.power.doc.model.postman.request.body; package com.power.doc.model.postman.request.body;
import com.power.doc.model.FormData; import com.power.doc.model.FormData;
import java.util.List; import java.util.List;
/** /**
* @author xingzi * @author xingzi
*/ */
public class BodyBean { public class BodyBean {
private String mode; private String mode;
private String raw; private String raw;
private List<FormData> formdata; private List<FormData> formdata;
private BodyOptions options; private BodyOptions options;
public BodyBean(boolean isFormData) { public BodyBean(boolean isFormData) {
if (isFormData) { if (!isFormData) {
this.options = new BodyOptions();
} else { }
this.options = new BodyOptions(); }
}
} public List<FormData> getFormdata() {
return formdata;
public List<FormData> getFormdata() { }
return formdata;
} public void setFormdata(List<FormData> formdata) {
this.formdata = formdata;
public void setFormdata(List<FormData> formdata) { }
this.formdata = formdata;
} public String getMode() {
return mode;
public String getMode() { }
return mode;
} public void setMode(String mode) {
this.mode = mode;
public void setMode(String mode) { }
this.mode = mode;
} public String getRaw() {
return raw;
public String getRaw() { }
return raw;
} public void setRaw(String raw) {
this.raw = raw;
public void setRaw(String raw) { }
this.raw = raw;
} private class BodyOptions {
private Raw raw;
private class BodyOptions {
private Raw raw; public BodyOptions() {
this.raw = new Raw();
public BodyOptions() { }
this.raw = new Raw();
} private class Raw {
private String language;
private class Raw {
private String language; Raw() {
this.language = "json";
Raw() { }
this.language = "json"; }
} }
}
}
}
}

View File

@ -29,8 +29,8 @@ import com.power.doc.helper.ParamsBuildHelper;
import com.power.doc.model.*; import com.power.doc.model.*;
import com.power.doc.utils.DocClassUtil; import com.power.doc.utils.DocClassUtil;
import com.power.doc.utils.DocUtil; import com.power.doc.utils.DocUtil;
import com.power.doc.utils.JavaClassUtil;
import com.power.doc.utils.JavaClassValidateUtil; import com.power.doc.utils.JavaClassValidateUtil;
import com.power.doc.utils.OpenApiSchemaUtil;
import com.thoughtworks.qdox.model.JavaClass; import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod; import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.JavaType; import com.thoughtworks.qdox.model.JavaType;
@ -120,15 +120,15 @@ public interface IDocBuildTemplate<T> {
return null; return null;
} }
if (JavaClassValidateUtil.isPrimitive(typeName)) { if (JavaClassValidateUtil.isPrimitive(typeName)) {
String processedName = projectBuilder.getApiConfig().getShowJavaType() ? docJavaMethod.setReturnSchema(OpenApiSchemaUtil.primaryTypeSchema(typeName));
JavaClassUtil.getClassSimpleName(typeName) : DocClassUtil.processTypeNameForParams(typeName); return null;
return ParamsBuildHelper.primitiveReturnRespComment(processedName);
} }
if (JavaClassValidateUtil.isCollection(typeName)) { if (JavaClassValidateUtil.isCollection(typeName)) {
if (returnType.contains("<")) { if (returnType.contains("<")) {
String gicName = returnType.substring(returnType.indexOf("<") + 1, returnType.lastIndexOf(">")); String gicName = returnType.substring(returnType.indexOf("<") + 1, returnType.lastIndexOf(">"));
if (JavaClassValidateUtil.isPrimitive(gicName)) { if (JavaClassValidateUtil.isPrimitive(gicName)) {
return ParamsBuildHelper.primitiveReturnRespComment("array of " + DocClassUtil.processTypeNameForParams(gicName)); docJavaMethod.setReturnSchema(OpenApiSchemaUtil.arrayTypeSchema(gicName));
return null;
} }
return ParamsBuildHelper.buildParams(gicName, "", 0, null, projectBuilder.getCustomRespFieldMap(), return ParamsBuildHelper.buildParams(gicName, "", 0, null, projectBuilder.getCustomRespFieldMap(),
Boolean.TRUE, new HashMap<>(), projectBuilder, null, 0); Boolean.TRUE, new HashMap<>(), projectBuilder, null, 0);
@ -142,7 +142,8 @@ public interface IDocBuildTemplate<T> {
return null; return null;
} }
if (JavaClassValidateUtil.isPrimitive(keyValue[1])) { if (JavaClassValidateUtil.isPrimitive(keyValue[1])) {
return ParamsBuildHelper.primitiveReturnRespComment("key value"); docJavaMethod.setReturnSchema(OpenApiSchemaUtil.mapTypeSchema(keyValue[1]));
return null;
} }
return ParamsBuildHelper.buildParams(keyValue[1], "", 0, null, projectBuilder.getCustomRespFieldMap(), return ParamsBuildHelper.buildParams(keyValue[1], "", 0, null, projectBuilder.getCustomRespFieldMap(),
Boolean.TRUE, new HashMap<>(), projectBuilder, null, 0); Boolean.TRUE, new HashMap<>(), projectBuilder, null, 0);

View File

@ -39,6 +39,7 @@ import com.thoughtworks.qdox.model.expression.AnnotationValue;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -50,7 +51,7 @@ import static com.power.doc.constants.DocTags.IGNORE;
* @author yu 2019/12/21. * @author yu 2019/12/21.
*/ */
public class SpringBootDocBuildTemplate implements IDocBuildTemplate<ApiDoc> { public class SpringBootDocBuildTemplate implements IDocBuildTemplate<ApiDoc> {
private static Logger log = Logger.getLogger(SpringBootDocBuildTemplate.class.getName());
private List<ApiReqHeader> headers; private List<ApiReqHeader> headers;
/** /**
@ -148,15 +149,16 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate<ApiDoc> {
if (method.isPrivate() || Objects.nonNull(method.getTagByName(IGNORE))) { if (method.isPrivate() || Objects.nonNull(method.getTagByName(IGNORE))) {
continue; continue;
} }
if (StringUtil.isEmpty(method.getComment()) && apiConfig.isStrict()) {
throw new RuntimeException("Unable to find comment for method " + method.getName() + " in " + cls.getCanonicalName());
}
//handle request mapping //handle request mapping
RequestMapping requestMapping = new SpringMVCRequestMappingHandler() RequestMapping requestMapping = new SpringMVCRequestMappingHandler()
.handle(projectBuilder.getServerUrl(), baseUrl, method, constantsMap); .handle(projectBuilder.getServerUrl(), baseUrl, method, constantsMap);
if (Objects.isNull(requestMapping)) { if (Objects.isNull(requestMapping)) {
continue; continue;
} }
if (StringUtil.isEmpty(method.getComment()) && apiConfig.isStrict()) {
throw new RuntimeException("Unable to find comment for method " + method.getName() + " in " + cls.getCanonicalName());
}
methodOrder++; methodOrder++;
ApiMethodDoc apiMethodDoc = new ApiMethodDoc(); ApiMethodDoc apiMethodDoc = new ApiMethodDoc();
apiMethodDoc.setName(method.getName()); apiMethodDoc.setName(method.getName());
@ -186,12 +188,20 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate<ApiDoc> {
apiMethodDoc.setServerUrl(projectBuilder.getServerUrl()); apiMethodDoc.setServerUrl(projectBuilder.getServerUrl());
apiMethodDoc.setPath(requestMapping.getShortUrl()); apiMethodDoc.setPath(requestMapping.getShortUrl());
apiMethodDoc.setDeprecated(requestMapping.isDeprecated()); apiMethodDoc.setDeprecated(requestMapping.isDeprecated());
ApiMethodReqParam apiMethodReqParam = requestParams(docJavaMethod, projectBuilder);
apiMethodDoc.setPathParams(apiMethodReqParam.getPathParams());
apiMethodDoc.setQueryParams(apiMethodReqParam.getQueryParams());
// build request params // build request params
List<ApiParam> requestParams = requestParams(docJavaMethod, projectBuilder);
if (paramsDataToTree) { if (paramsDataToTree) {
requestParams = ApiParamTreeUtil.apiParamToTree(requestParams); apiMethodDoc.setPathParams(ApiParamTreeUtil.apiParamToTree(apiMethodReqParam.getPathParams()));
apiMethodDoc.setQueryParams(ApiParamTreeUtil.apiParamToTree(apiMethodReqParam.getQueryParams()));
apiMethodDoc.setRequestParams(ApiParamTreeUtil.apiParamToTree(apiMethodReqParam.getRequestParams()));
} else {
apiMethodDoc.setPathParams(apiMethodReqParam.getPathParams());
apiMethodDoc.setQueryParams(apiMethodReqParam.getQueryParams());
apiMethodDoc.setRequestParams(apiMethodReqParam.getRequestParams());
} }
apiMethodDoc.setRequestParams(requestParams);
List<ApiReqHeader> allApiReqHeaders; List<ApiReqHeader> allApiReqHeaders;
if (this.headers != null) { if (this.headers != null) {
allApiReqHeaders = Stream.of(this.headers, apiReqHeaders) allApiReqHeaders = Stream.of(this.headers, apiReqHeaders)
@ -217,6 +227,8 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate<ApiDoc> {
if (paramsDataToTree) { if (paramsDataToTree) {
responseParams = ApiParamTreeUtil.apiParamToTree(responseParams); responseParams = ApiParamTreeUtil.apiParamToTree(responseParams);
} }
apiMethodDoc.setReturnSchema(docJavaMethod.getReturnSchema());
apiMethodDoc.setRequestSchema(docJavaMethod.getRequestSchema());
apiMethodDoc.setResponseParams(responseParams); apiMethodDoc.setResponseParams(responseParams);
methodDocList.add(apiMethodDoc); methodDocList.add(apiMethodDoc);
} }
@ -444,7 +456,7 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate<ApiDoc> {
return requestExample; return requestExample;
} }
private List<ApiParam> requestParams(final DocJavaMethod docJavaMethod, ProjectDocConfigBuilder builder) { private ApiMethodReqParam requestParams(final DocJavaMethod docJavaMethod, ProjectDocConfigBuilder builder) {
JavaMethod javaMethod = docJavaMethod.getJavaMethod(); JavaMethod javaMethod = docJavaMethod.getJavaMethod();
boolean isStrict = builder.getApiConfig().isStrict(); boolean isStrict = builder.getApiConfig().isStrict();
Map<String, CustomRespField> responseFieldMap = new HashMap<>(); Map<String, CustomRespField> responseFieldMap = new HashMap<>();
@ -453,11 +465,12 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate<ApiDoc> {
Map<String, String> paramTagMap = DocUtil.getParamsComments(javaMethod, DocTags.PARAM, className); Map<String, String> paramTagMap = DocUtil.getParamsComments(javaMethod, DocTags.PARAM, className);
List<JavaParameter> parameterList = javaMethod.getParameters(); List<JavaParameter> parameterList = javaMethod.getParameters();
if (parameterList.size() < 1) { if (parameterList.size() < 1) {
return null; return new ApiMethodReqParam();
} }
List<ApiParam> paramList = new ArrayList<>();
Map<String, String> constantsMap = builder.getConstantsMap(); Map<String, String> constantsMap = builder.getConstantsMap();
boolean requestFieldToUnderline = builder.getApiConfig().isRequestFieldToUnderline(); boolean requestFieldToUnderline = builder.getApiConfig().isRequestFieldToUnderline();
List<ApiParam> paramList = new ArrayList<>();
Map<String, JavaType> actualTypesMap = docJavaMethod.getActualTypesMap(); Map<String, JavaType> actualTypesMap = docJavaMethod.getActualTypesMap();
int requestBodyCounter = 0; int requestBodyCounter = 0;
out: out:
@ -495,7 +508,12 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate<ApiDoc> {
if (typeName.contains(DocGlobalConstants.MULTIPART_FILE_FULLY)) { if (typeName.contains(DocGlobalConstants.MULTIPART_FILE_FULLY)) {
ApiParam param = ApiParam.of().setField(paramName).setType("file") ApiParam param = ApiParam.of().setField(paramName).setType("file")
.setId(paramList.size() + 1).setQueryParam(true) .setId(paramList.size() + 1).setQueryParam(true)
.setDesc(comment).setRequired(true).setVersion(DocGlobalConstants.DEFAULT_VERSION); .setRequired(true).setVersion(DocGlobalConstants.DEFAULT_VERSION);
if(typeName.contains("[]")){
comment = comment+"(array of file)";
param.setDesc(comment);
param.setHasItems(true);
}
paramList.add(param); paramList.add(param);
continue; continue;
} }
@ -542,10 +560,7 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate<ApiDoc> {
} }
boolean required = Boolean.parseBoolean(strRequired); boolean required = Boolean.parseBoolean(strRequired);
boolean queryParam = false; boolean queryParam = false;
if (isPathVariable) { if (!isRequestBody && !isPathVariable) {
comment = comment + " (This is path parameter.)";
} else if (!isRequestBody && requestBodyCounter > 0) {
comment = comment + " (This is query parameter.)";
queryParam = true; queryParam = true;
} }
if (JavaClassValidateUtil.isCollection(fullTypeName) || JavaClassValidateUtil.isArray(fullTypeName)) { if (JavaClassValidateUtil.isCollection(fullTypeName) || JavaClassValidateUtil.isArray(fullTypeName)) {
@ -563,6 +578,10 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate<ApiDoc> {
.setId(paramList.size() + 1) .setId(paramList.size() + 1)
.setType("array"); .setType("array");
paramList.add(param); paramList.add(param);
if (requestBodyCounter > 0) {
Map<String, Object> map = OpenApiSchemaUtil.arrayTypeSchema(gicName);
docJavaMethod.setRequestSchema(map);
}
} else { } else {
if (requestBodyCounter > 0) { if (requestBodyCounter > 0) {
//for json //for json
@ -583,7 +602,14 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate<ApiDoc> {
.setQueryParam(queryParam).setValue(value) .setQueryParam(queryParam).setValue(value)
.setDesc(comment).setRequired(required).setVersion(DocGlobalConstants.DEFAULT_VERSION); .setDesc(comment).setRequired(required).setVersion(DocGlobalConstants.DEFAULT_VERSION);
paramList.add(param); paramList.add(param);
if (requestBodyCounter > 0) {
Map<String, Object> map = OpenApiSchemaUtil.primaryTypeSchema(simpleName);
docJavaMethod.setRequestSchema(map);
}
} else if (JavaClassValidateUtil.isMap(fullTypeName)) { } else if (JavaClassValidateUtil.isMap(fullTypeName)) {
log.warning("When using smart-doc, it is not recommended to use Map to receive parameters, Check it in "
+ javaMethod.getDeclaringClass().getCanonicalName()+"#"+javaMethod.getName());
if (DocGlobalConstants.JAVA_MAP_FULLY.equals(typeName)) { if (DocGlobalConstants.JAVA_MAP_FULLY.equals(typeName)) {
ApiParam apiParam = ApiParam.of().setField(paramName).setType("map") ApiParam apiParam = ApiParam.of().setField(paramName).setType("map")
.setId(paramList.size() + 1) .setId(paramList.size() + 1)
@ -591,10 +617,29 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate<ApiDoc> {
.setQueryParam(queryParam) .setQueryParam(queryParam)
.setDesc(comment).setRequired(required).setVersion(DocGlobalConstants.DEFAULT_VERSION); .setDesc(comment).setRequired(required).setVersion(DocGlobalConstants.DEFAULT_VERSION);
paramList.add(apiParam); paramList.add(apiParam);
if (requestBodyCounter > 0) {
Map<String, Object> map = OpenApiSchemaUtil.mapTypeSchema("object");
docJavaMethod.setRequestSchema(map);
}
continue; continue;
} }
String[] gicNameArr = DocClassUtil.getSimpleGicName(typeName); String[] gicNameArr = DocClassUtil.getSimpleGicName(typeName);
paramList.addAll(ParamsBuildHelper.buildParams(gicNameArr[1], DocGlobalConstants.EMPTY, 0, "true", responseFieldMap, Boolean.FALSE, new HashMap<>(), builder, groupClasses, 0)); if(JavaClassValidateUtil.isPrimitive(gicNameArr[1])){
ApiParam apiParam = ApiParam.of().setField(paramName).setType("map")
.setId(paramList.size() + 1)
.setPathParam(isPathVariable)
.setQueryParam(queryParam)
.setDesc(comment).setRequired(required).setVersion(DocGlobalConstants.DEFAULT_VERSION);
paramList.add(apiParam);
if (requestBodyCounter > 0) {
Map<String, Object> map = OpenApiSchemaUtil.mapTypeSchema(gicNameArr[1]);
docJavaMethod.setRequestSchema(map);
}
} else {
paramList.addAll(ParamsBuildHelper.buildParams(gicNameArr[1], DocGlobalConstants.EMPTY, 0,
"true", responseFieldMap, Boolean.FALSE, new HashMap<>(), builder, groupClasses, 0));
}
} }
// param is enum // param is enum
else if (javaClass.isEnum()) { else if (javaClass.isEnum()) {
@ -610,7 +655,26 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate<ApiDoc> {
paramList.addAll(ParamsBuildHelper.buildParams(typeName, DocGlobalConstants.EMPTY, 0, "true", responseFieldMap, Boolean.FALSE, new HashMap<>(), builder, groupClasses, 0)); paramList.addAll(ParamsBuildHelper.buildParams(typeName, DocGlobalConstants.EMPTY, 0, "true", responseFieldMap, Boolean.FALSE, new HashMap<>(), builder, groupClasses, 0));
} }
} }
return paramList; List<ApiParam> pathParams = new ArrayList<>();
List<ApiParam> queryParams = new ArrayList<>();
List<ApiParam> bodyParams = new ArrayList<>();
for (ApiParam param : paramList) {
if (param.isPathParam()) {
param.setId(pathParams.size() + 1);
pathParams.add(param);
} else if (param.isQueryParam() || requestBodyCounter < 1) {
param.setId(queryParams.size() + 1);
queryParams.add(param);
} else {
param.setId(bodyParams.size() + 1);
bodyParams.add(param);
}
}
ApiMethodReqParam apiMethodReqParam = ApiMethodReqParam.builder()
.setRequestParams(bodyParams)
.setPathParams(pathParams)
.setQueryParams(queryParams);
return apiMethodReqParam;
} }
private String getParamName(String paramName, JavaAnnotation annotation) { private String getParamName(String paramName, JavaAnnotation annotation) {

View File

@ -463,9 +463,8 @@ public class DocUtil {
switch (type) { switch (type) {
case "int32": case "int32":
case "int16": case "int16":
return "integer";
case "int64": case "int64":
return "long"; return "integer";
case "double": case "double":
case "float": case "float":
case "number": case "number":

View File

@ -0,0 +1,35 @@
package com.power.doc.utils;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author yu 2020/11/29.
*/
public class OpenApiSchemaUtil {
public static Map<String,Object> primaryTypeSchema(String primaryType){
Map<String, Object> map = new HashMap<>();
map.put("type", DocClassUtil.processTypeNameForParams(primaryType));
return map;
}
public static Map<String,Object> mapTypeSchema(String primaryType){
Map<String, Object> map = new LinkedHashMap<>();
map.put("type", "object");
Map<String, Object> items = new HashMap<>();
items.put("type", DocClassUtil.processTypeNameForParams(primaryType));
map.put("additionalProperties", items);
return map;
}
public static Map<String,Object> arrayTypeSchema(String primaryType){
Map<String, Object> map = new HashMap<>();
map.put("type", "array");
Map<String, Object> items = new HashMap<>();
items.put("type", DocClassUtil.processTypeNameForParams(primaryType));
map.put("items", items);
return map;
}
}

View File

@ -1,49 +1,63 @@
/* /*
* smart-doc https://github.com/shalousun/smart-doc * smart-doc https://github.com/shalousun/smart-doc
* *
* Copyright (C) 2018-2020 smart-doc * Copyright (C) 2018-2020 smart-doc
* *
* Licensed to the Apache Software Foundation (ASF) under one * Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file * or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information * distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file * regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the * to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance * "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at * with the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, * Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an * software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the * KIND, either express or implied. See the License for the
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package com.power.doc.utils; package com.power.doc.utils;
import com.power.common.util.StringUtil; import com.power.common.util.StringUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.io.File; import java.io.File;
public class PathUtil { public class PathUtil {
/** /**
* Get the java class name * Get the java class name
* *
* @param parentDir parent dir * @param parentDir parent dir
* @param className class name * @param className class name
* @return java file name * @return java file name
*/ */
public static String javaFilePath(String parentDir, String className) { public static String javaFilePath(String parentDir, String className) {
if (StringUtil.isEmpty(parentDir)) { if (StringUtil.isEmpty(parentDir)) {
parentDir = "java.io.tmpdir"; parentDir = "java.io.tmpdir";
} }
if (!StringUtils.endsWith(parentDir, File.separator)) { if (!StringUtils.endsWith(parentDir, File.separator)) {
parentDir += File.separator; parentDir += File.separator;
} }
className = className.replaceAll("\\.", "\\" + File.separator); className = className.replaceAll("\\.", "\\" + File.separator);
return parentDir + className + ".java"; return parentDir + className + ".java";
} }
}
/**
* to postman path
* @param path path
* @return String
*/
public static String toPostmanPath(String path){
if(StringUtil.isNotEmpty(path)){
path = path.replace("{",":");
path = path.replace("}","");
return path;
}
return null;
}
}

View File

@ -49,8 +49,38 @@ ${doc.headers}
|==================== |====================
<%}%> <%}%>
<%if(isNotEmpty(doc.pathParams)){%>
*Path-parameters:*
[width="100%",options="header"]
[stripes=even]
|====================
|Parameter | Type|Description|Required|Since
<%
for(param in doc.pathParams){
%>
|${param.field}|${param.type}|${param.desc}|${param.required}|${param.version}
<%}%>
|====================
<%}%>
<%if(isNotEmpty(doc.queryParams)){%>
*Query-parameters:*
[width="100%",options="header"]
[stripes=even]
|====================
|Parameter | Type|Description|Required|Since
<%
for(param in doc.queryParams){
%>
|${param.field}|${param.type}|${param.desc}|${param.required}|${param.version}
<%}%>
|====================
<%}%>
<%if(isNotEmpty(doc.requestParams)){%> <%if(isNotEmpty(doc.requestParams)){%>
*Request-parameters:* *Body-parameters:*
[width="100%",options="header"] [width="100%",options="header"]
[stripes=even] [stripes=even]

View File

@ -44,9 +44,33 @@ Header | Type|Description|Required|Since
---|---|---|---|---- ---|---|---|---|----
${doc.headers} ${doc.headers}
<%}%> <%}%>
<%if(isNotEmpty(doc.pathParams)){%>
**Path-parameters:**
Parameter | Type|Description|Required|Since
---|---|---|---|---
<%
for(param in doc.pathParams){
%>
${param.field}|${param.type}|${param.desc}|${param.required}|${param.version}
<%}%>
<%}%>
<%if(isNotEmpty(doc.queryParams)){%>
**Query-parameters:**
Parameter | Type|Description|Required|Since
---|---|---|---|---
<%
for(param in doc.queryParams){
%>
${param.field}|${param.type}|${param.desc}|${param.required}|${param.version}
<%}%>
<%}%>
<%if(isNotEmpty(doc.requestParams)){%> <%if(isNotEmpty(doc.requestParams)){%>
**Request-parameters:** **Body-parameters:**
Parameter | Type|Description|Required|Since Parameter | Type|Description|Required|Since
---|---|---|---|--- ---|---|---|---|---

File diff suppressed because one or more lines are too long

View File

@ -31,6 +31,36 @@ ${doc.headers}
<%}%> <%}%>
|==================== |====================
<%if(isNotEmpty(doc.pathParams)){%>
*Path-parameters:*
[width="100%",options="header"]
[stripes=even]
|====================
|Parameter | Type|Description|Required|Since
<%
for(param in doc.pathParams){
%>
|${param.field}|${param.type}|${param.desc}|${param.required}|${param.version}
<%}%>
|====================
<%}%>
<%if(isNotEmpty(doc.queryParams)){%>
*Query-parameters:*
[width="100%",options="header"]
[stripes=even]
|====================
|Parameter | Type|Description|Required|Since
<%
for(param in doc.queryParams){
%>
|${param.field}|${param.type}|${param.desc}|${param.required}|${param.version}
<%}%>
|====================
<%}%>
<%if(isNotEmpty(doc.requestParams)){%> <%if(isNotEmpty(doc.requestParams)){%>
*Request-parameters:* *Request-parameters:*
@ -43,8 +73,9 @@ for(param in doc.requestParams){
%> %>
|${param.field}|${param.type}|${param.desc}|${param.required}|${param.version} |${param.field}|${param.type}|${param.desc}|${param.required}|${param.version}
<%}%> <%}%>
<%}%>
|==================== |====================
<%}%>
<%if(isNotEmpty(doc.requestUsage)&&isRequestExample){%> <%if(isNotEmpty(doc.requestUsage)&&isRequestExample){%>
*Request-example:* *Request-example:*
@ -64,8 +95,9 @@ for(param in doc.responseParams){
%> %>
|${param.field}|${param.type}|${param.desc}|${param.version} |${param.field}|${param.type}|${param.desc}|${param.version}
<%}%> <%}%>
<%}%>
|==================== |====================
<%}%>
<%if(isNotEmpty(doc.responseUsage)&&isResponseExample){%> <%if(isNotEmpty(doc.responseUsage)&&isResponseExample){%>
*Response-example:* *Response-example:*

View File

@ -28,8 +28,32 @@ Header | Type|Description|Required|Since
${doc.headers} ${doc.headers}
<%}%> <%}%>
<%if(isNotEmpty(doc.pathParams)){%>
**Path-parameters:**
Parameter|Type|Description|Required|Since
---|---|---|---|---
<%
for(param in doc.pathParams){
%>
${param.field}|${param.type}|${param.desc}|${param.required}|${param.version}
<%}%>
<%}%>
<%if(isNotEmpty(doc.queryParams)){%>
**Query-parameters:**
Parameter|Type|Description|Required|Since
---|---|---|---|---
<%
for(param in doc.queryParams){
%>
${param.field}|${param.type}|${param.desc}|${param.required}|${param.version}
<%}%>
<%}%>
<%if(isNotEmpty(doc.requestParams)){%> <%if(isNotEmpty(doc.requestParams)){%>
**Request-parameters:** **Body-parameters:**
Parameter|Type|Description|Required|Since Parameter|Type|Description|Required|Since
---|---|---|---|--- ---|---|---|---|---