diff --git a/src/main/java/com/power/doc/builder/OpenApiBuilder.java b/src/main/java/com/power/doc/builder/OpenApiBuilder.java index 15ce9a8..ad1eb03 100644 --- a/src/main/java/com/power/doc/builder/OpenApiBuilder.java +++ b/src/main/java/com/power/doc/builder/OpenApiBuilder.java @@ -11,16 +11,18 @@ import com.power.doc.model.*; import com.power.doc.template.SpringBootDocBuildTemplate; import com.power.doc.utils.DocUtil; import com.thoughtworks.qdox.JavaProjectBuilder; +import org.jetbrains.annotations.NotNull; import java.util.*; /** - * @author xingzi + * @author xingzi */ public class OpenApiBuilder { //过滤url中的特殊字符 - private static final String PATH_REGEX ="[/{};\\t+]"; + private static final String PATH_REGEX = "[/{};\\t+]"; + /** * 构建postman json * @@ -49,7 +51,8 @@ public class OpenApiBuilder { /** * 构建openApi 文件 - * @param config 配置文件 + * + * @param config 配置文件 * @param configBuilder */ private static void openApiCreate(ApiConfig config, ProjectDocConfigBuilder configBuilder) { @@ -57,7 +60,7 @@ public class OpenApiBuilder { SpringBootDocBuildTemplate docBuildTemplate = new SpringBootDocBuildTemplate(); List apiDocList = docBuildTemplate.getApiData(configBuilder); Map json = new HashMap<>(8); - json.put("openapi", "3.0.0"); + json.put("openapi", "3.0.3"); json.put("info", buildInfo(config)); json.put("servers", buildServers(config)); json.put("paths", buildPaths(apiDocList)); @@ -74,6 +77,7 @@ public class OpenApiBuilder { /** * info 信息 + * * @param apiConfig 文档配置信息 * @return */ @@ -83,20 +87,24 @@ public class OpenApiBuilder { infoMap.put("version", "1.0.0"); return infoMap; } + /** * server 信息 + * * @param config 文档配置信息 * @return */ private static List> buildServers(ApiConfig config) { List> serverList = new ArrayList<>(); Map 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); return serverList; } + /** * 构建path数据 url请求 + * * @param apiDocList api列表 * @return */ @@ -123,10 +131,12 @@ public class OpenApiBuilder { ); return pathMap; } + /** - * paths 设置url请求方式 + * paths 设置url请求方式 + * * @param apiMethodDoc 方法参数 - * @param apiDoc 类参数 + * @param apiDoc 类参数 * @return */ private static Map buildPathUrls(ApiMethodDoc apiMethodDoc, ApiDoc apiDoc) { @@ -134,10 +144,12 @@ public class OpenApiBuilder { request.put(apiMethodDoc.getType().toLowerCase(), buildPathUrlsRequest(apiMethodDoc, apiDoc)); return request; } + /** * url的基本信息 信息简介summary 详情description 所属分类tags 请求参数parameter 请求体request 返回值responses + * * @param apiMethodDoc 方法参数 - * @param apiDoc 类参数 + * @param apiDoc 类参数 * @return */ private static Map buildPathUrlsRequest(ApiMethodDoc apiMethodDoc, ApiDoc apiDoc) { @@ -148,25 +160,22 @@ public class OpenApiBuilder { request.put("requestBody", buildRequestBody(apiMethodDoc)); request.put("parameters", buildParameters(apiMethodDoc)); request.put("responses", buildResponses(apiMethodDoc)); + request.put("deprecated", apiMethodDoc.isDeprecated()); + request.put("operationId", apiMethodDoc.getMethodId()); return request; } + /** * 请求体构建 只针对post请求 并且请求体不为null + * * @param apiMethodDoc 方法参数 * @return */ private static Map buildRequestBody(ApiMethodDoc apiMethodDoc) { - int size = 0; Map requestBody = new HashMap<>(8); - //判断请求体去除pathVariable参数后是否为null - if(!CollectionUtil.isEmpty(apiMethodDoc.getRequestParams())) { - List apiParams = apiMethodDoc.getRequestParams(); - //去除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; + boolean isPost = (apiMethodDoc.getType().equals(Methods.POST.getValue()) + || apiMethodDoc.getType().equals(Methods.PUT.getValue()) || + apiMethodDoc.getType().equals(Methods.PATCH.getValue())); //如果是post请求 且包含请求体 if (isPost) { requestBody.put("content", buildContent(apiMethodDoc, false)); @@ -175,34 +184,79 @@ public class OpenApiBuilder { return null; } + /** * 构建content信息 responses 和 requestBody 都需要content信息 + * * @param apiMethodDoc 方法参数 - * @param isRep 是否是返回数据 + * @param isRep 是否是返回数据 * @return */ private static Map buildContent(ApiMethodDoc apiMethodDoc, boolean isRep) { Map 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; } + /** * 构建content的数据内容 + * * @param apiMethodDoc 方法参数 - * @param isRep 是否是返回数据 + * @param isRep 是否是返回数据 * @return */ private static Map buildContentBody(ApiMethodDoc apiMethodDoc, boolean isRep) { Map 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 map = new LinkedHashMap<>(); + map.put("type", "object"); + Map properties = new LinkedHashMap<>(); + Map 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 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)); return content; } + /** * content body 的schema 信息 - * @param url 请求的url 去除server + * + * @param url 请求的url 去除server * @param isRep 是否是返回数据 * @return */ @@ -216,10 +270,12 @@ public class OpenApiBuilder { } return schema; } + /** * 信息样例 请求和返回的信息样例 + * * @param apiMethodDoc 方法参数 - * @param isRep 是否是返回数据 + * @param isRep 是否是返回数据 * @return */ private static Map buildBodyExample(ApiMethodDoc apiMethodDoc, boolean isRep) { @@ -228,10 +284,12 @@ public class OpenApiBuilder { return content; } + /** * 信息样例数据构建 此处请求体requestBody构建完成 + * * @param apiMethodDoc 方法参数 - * @param isRep 是否为返回数据 + * @param isRep 是否为返回数据 * @return */ private static Map buildExampleData(ApiMethodDoc apiMethodDoc, boolean isRep) { @@ -250,31 +308,32 @@ public class OpenApiBuilder { /** * 构建请求参数 用于get请求 @PathVariable Header 参数构建 + * * @param apiMethodDoc 方法体 * @return */ private static List> buildParameters(ApiMethodDoc apiMethodDoc) { Map parameters; List> parametersList = new ArrayList<>(); - //如果是get请求 或 包含@pathvariable - if (apiMethodDoc.getType().equals(Methods.GET.getValue()) || apiMethodDoc.getPath().contains("{")) { - if (apiMethodDoc.getRequestParams() == null) { - return null; - } - 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"); - } + for (ApiParam apiParam : apiMethodDoc.getPathParams()) { + parameters = getStringParams(apiParam); + parameters.put("in", "path"); + List children = apiParam.getChildren(); + if (CollectionUtil.isEmpty(children)) { 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 children = apiParam.getChildren(); + if (CollectionUtil.isEmpty(children)) { + parametersList.add(parameters); + } + } + } //如果包含请求头 if (!CollectionUtil.isEmpty(apiMethodDoc.getRequestHeaders())) { for (ApiReqHeader header : apiMethodDoc.getRequestHeaders()) { @@ -289,8 +348,22 @@ public class OpenApiBuilder { } return parametersList; } + + @NotNull + private static Map getStringParams(ApiParam apiParam) { + Map 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 设置请求参数 + * * @param apiParam 参数信息 * @return */ @@ -303,12 +376,14 @@ public class OpenApiBuilder { schema.put("format", "binary"); } } else { - schema.put("format", "int16".equals(apiParam.getType())?"int32":apiParam.getType()); + schema.put("format", "int16".equals(apiParam.getType()) ? "int32" : apiParam.getType()); } return schema; } + /** * 如果包含header 设置请求参数 + * * @param header 参数信息 * @return */ @@ -316,11 +391,13 @@ public class OpenApiBuilder { Map schema = new HashMap<>(10); String openApiType = DocUtil.javaTypeToOpenApiTypeConvert(header.getType()); 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; } + /** * 构建返回信息 + * * @param apiMethodDoc 方法参数 * @return */ @@ -329,22 +406,23 @@ public class OpenApiBuilder { response.put("200", buildResponsesBody(apiMethodDoc)); return response; } + /** * 构建返回信息实体 + * * @param apiMethodDoc 方法参数 * @return */ private static Map buildResponsesBody(ApiMethodDoc apiMethodDoc) { Map responseBody = new HashMap<>(10); - responseBody.put("description", "a pet to be returned"); - if (!CollectionUtil.isEmpty(apiMethodDoc.getResponseParams())) { - responseBody.put("content", buildContent(apiMethodDoc, true)); - } + responseBody.put("description", "OK"); + responseBody.put("content", buildContent(apiMethodDoc, true)); return responseBody; } /** * 构建component + * * @param apiDocs 请求列表 * @return */ @@ -358,7 +436,12 @@ public class OpenApiBuilder { method -> { //request components List requestParams = method.getRequestParams(); - component.put(method.getPath().replaceAll(PATH_REGEX, "_") + "request", buildProperties(requestParams)); + if (CollectionUtil.isNotEmpty(requestParams)) { + Map prop = buildProperties(requestParams); + if (Objects.nonNull(prop) && prop.size() > 0) { + component.put(method.getPath().replaceAll(PATH_REGEX, "_") + "request", buildProperties(requestParams)); + } + } //response components List responseParams = method.getResponseParams(); component.put(method.getPath().replaceAll(PATH_REGEX, "_") + "response", buildProperties(responseParams)); @@ -372,24 +455,32 @@ public class OpenApiBuilder { /** * component schema properties 信息 + * * @param apiParam 参数列表 * @return */ private static Map buildProperties(List apiParam) { - Map component = new HashMap<>(); - Map propertiesData = new HashMap<>(); + Map propertiesData = new LinkedHashMap<>(); List requiredList = new ArrayList<>(); if (apiParam != null) { + int paramsSize = apiParam.size(); for (ApiParam param : apiParam) { if (param.isRequired()) { requiredList.add(param.getField()); } + if (param.getType().equals("map") && paramsSize == 1) { + continue; + } + if (param.isQueryParam() || param.isPathParam()) { + continue; + } String field = param.getField(); - propertiesData.put(field, buildPropertiesData(param)); } - component.put("properties", propertiesData); + if (!propertiesData.isEmpty()) { + component.put("properties", propertiesData); + } if (!CollectionUtil.isEmpty(requiredList)) { component.put("required", requiredList); } @@ -399,8 +490,10 @@ public class OpenApiBuilder { } } + /** * component schema properties 实体信息构建 + * * @param apiParam 参数基本信息 * @return */ @@ -422,8 +515,8 @@ public class OpenApiBuilder { if (apiParam.getChildren() != null) { propertiesData.put("type", "object"); propertiesData.put("description", apiParam.getDesc() + "(object)"); - propertiesData.put("properties",buildProperties(apiParam.getChildren()).get("properties")); - propertiesData.put("requires",buildProperties(apiParam.getChildren()).get("requires")); + propertiesData.put("properties", buildProperties(apiParam.getChildren()).get("properties")); + propertiesData.put("requires", buildProperties(apiParam.getChildren()).get("requires")); } } if ("array".equals(apiParam.getType())) { diff --git a/src/main/java/com/power/doc/builder/PostmanJsonBuilder.java b/src/main/java/com/power/doc/builder/PostmanJsonBuilder.java index efea1a4..20dcfff 100644 --- a/src/main/java/com/power/doc/builder/PostmanJsonBuilder.java +++ b/src/main/java/com/power/doc/builder/PostmanJsonBuilder.java @@ -28,20 +28,22 @@ import com.google.gson.GsonBuilder; import com.power.common.util.FileUtil; import com.power.common.util.StringUtil; import com.power.doc.constants.DocGlobalConstants; -import com.power.doc.model.ApiConfig; -import com.power.doc.model.ApiDoc; -import com.power.doc.model.ApiMethodDoc; -import com.power.doc.model.ApiReqHeader; +import com.power.doc.model.*; import com.power.doc.model.postman.InfoBean; import com.power.doc.model.postman.ItemBean; 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.body.BodyBean; import com.power.doc.model.postman.request.header.HeaderBean; import com.power.doc.template.IDocBuildTemplate; import com.power.doc.template.SpringBootDocBuildTemplate; +import com.power.doc.utils.PathUtil; import com.thoughtworks.qdox.JavaProjectBuilder; +import java.net.MalformedURLException; +import java.net.URL; import java.util.ArrayList; import java.util.List; @@ -119,13 +121,59 @@ public class PostmanJsonBuilder { requestBean.setHeader(buildHeaderBeanList(apiMethodDoc)); requestBean.setBody(buildBodyBean(apiMethodDoc)); - requestBean.setUrl(apiMethodDoc.getRequestExample().getUrl() == null ? apiMethodDoc.getUrl() : apiMethodDoc.getRequestExample().getUrl()); + requestBean.setUrl(buildUrlBean(apiMethodDoc)); item.setRequest(requestBean); 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 hosts = new ArrayList<>(); + hosts.add(url1.getHost()); + urlBean.setHost(hosts); + } catch (MalformedURLException e) { + } + String shortUrl = PathUtil.toPostmanPath(apiMethodDoc.getPath()); + String[] paths = shortUrl.split("/"); + List pathList = new ArrayList<>(); + for (String str : paths) { + if (StringUtil.isNotEmpty(str)) { + pathList.add(str); + } + } + if (shortUrl.endsWith("/")) { + pathList.add(""); + } + + urlBean.setPath(pathList); + List 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 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; + } + /** * 构造请求体 * diff --git a/src/main/java/com/power/doc/constants/DocGlobalConstants.java b/src/main/java/com/power/doc/constants/DocGlobalConstants.java index 87c8c2c..cdc1dd8 100644 --- a/src/main/java/com/power/doc/constants/DocGlobalConstants.java +++ b/src/main/java/com/power/doc/constants/DocGlobalConstants.java @@ -71,7 +71,7 @@ public interface DocGlobalConstants { 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"; diff --git a/src/main/java/com/power/doc/helper/JsonBuildHelper.java b/src/main/java/com/power/doc/helper/JsonBuildHelper.java index 40645e9..014d0e2 100644 --- a/src/main/java/com/power/doc/helper/JsonBuildHelper.java +++ b/src/main/java/com/power/doc/helper/JsonBuildHelper.java @@ -109,6 +109,9 @@ public class JsonBuildHelper { } } if (JavaClassValidateUtil.isPrimitive(typeName)) { + if(DocGlobalConstants.JAVA_STRING_FULLY.equals(typeName)){ + return "string"; + } return StringUtil.removeQuotes(DocUtil.jsonValueByType(typeName)); } if (javaClass.isEnum()) { diff --git a/src/main/java/com/power/doc/helper/ParamsBuildHelper.java b/src/main/java/com/power/doc/helper/ParamsBuildHelper.java index 3129391..657dbd9 100644 --- a/src/main/java/com/power/doc/helper/ParamsBuildHelper.java +++ b/src/main/java/com/power/doc/helper/ParamsBuildHelper.java @@ -216,8 +216,14 @@ public class ParamsBuildHelper { continue; } 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); - param.setPid(pid); + param.setPid(pid).setValue(fieldValue); String processedType = isShowJavaType ? typeSimpleName : DocClassUtil.processTypeNameForParams(typeSimpleName.toLowerCase()); param.setType(processedType); if (StringUtil.isNotEmpty(comment)) { diff --git a/src/main/java/com/power/doc/model/ApiMethodDoc.java b/src/main/java/com/power/doc/model/ApiMethodDoc.java index ca2f3e4..a3b0de6 100644 --- a/src/main/java/com/power/doc/model/ApiMethodDoc.java +++ b/src/main/java/com/power/doc/model/ApiMethodDoc.java @@ -26,6 +26,7 @@ import com.power.doc.model.request.ApiRequestExample; import java.io.Serializable; import java.util.List; +import java.util.Map; /** * java api method info model. @@ -149,6 +150,16 @@ public class ApiMethodDoc implements Serializable { */ private boolean deprecated; + /** + * return schema + */ + private Map returnSchema; + + /** + * request schema + */ + private Map requestSchema; + public String getMethodId() { return methodId; @@ -318,6 +329,23 @@ public class ApiMethodDoc implements Serializable { this.queryParams = queryParams; } + + public Map getReturnSchema() { + return returnSchema; + } + + public void setReturnSchema(Map returnSchema) { + this.returnSchema = returnSchema; + } + + public Map getRequestSchema() { + return requestSchema; + } + + public void setRequestSchema(Map requestSchema) { + this.requestSchema = requestSchema; + } + @Override public String toString() { final StringBuilder sb = new StringBuilder("{"); diff --git a/src/main/java/com/power/doc/model/ApiMethodReqParam.java b/src/main/java/com/power/doc/model/ApiMethodReqParam.java new file mode 100644 index 0000000..bba4ce9 --- /dev/null +++ b/src/main/java/com/power/doc/model/ApiMethodReqParam.java @@ -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 pathParams; + + /** + * query params + */ + private List queryParams; + + /** + * http request params + */ + private List requestParams; + + public static ApiMethodReqParam builder(){ + return new ApiMethodReqParam(); + } + + public List getPathParams() { + return pathParams; + } + + public ApiMethodReqParam setPathParams(List pathParams) { + this.pathParams = pathParams; + return this; + } + + public List getQueryParams() { + return queryParams; + } + + public ApiMethodReqParam setQueryParams(List queryParams) { + this.queryParams = queryParams; + return this; + } + + public List getRequestParams() { + return requestParams; + } + + public ApiMethodReqParam setRequestParams(List requestParams) { + this.requestParams = requestParams; + return this; + } +} diff --git a/src/main/java/com/power/doc/model/ApiParam.java b/src/main/java/com/power/doc/model/ApiParam.java index 517a139..b55db59 100644 --- a/src/main/java/com/power/doc/model/ApiParam.java +++ b/src/main/java/com/power/doc/model/ApiParam.java @@ -23,6 +23,7 @@ package com.power.doc.model; import java.util.List; +import java.util.Map; /** * @author yu 2019/9/27. @@ -75,7 +76,7 @@ public class ApiParam { private boolean queryParam; /** - * + * param mock value */ private String value; @@ -84,6 +85,11 @@ public class ApiParam { */ private List children; + /** + * openapi items + */ + private boolean hasItems; + public static ApiParam of(){ return new ApiParam(); } @@ -187,6 +193,15 @@ public class ApiParam { return this; } + public boolean isHasItems() { + return hasItems; + } + + public ApiParam setHasItems(boolean hasItems) { + this.hasItems = hasItems; + return this; + } + @Override public String toString() { final StringBuilder sb = new StringBuilder("{"); diff --git a/src/main/java/com/power/doc/model/DocJavaMethod.java b/src/main/java/com/power/doc/model/DocJavaMethod.java index d81c856..6d648ee 100644 --- a/src/main/java/com/power/doc/model/DocJavaMethod.java +++ b/src/main/java/com/power/doc/model/DocJavaMethod.java @@ -13,6 +13,10 @@ public class DocJavaMethod { private JavaMethod javaMethod; + private Map returnSchema; + + private Map requestSchema; + private Map actualTypesMap; public static DocJavaMethod builder(){ @@ -36,4 +40,22 @@ public class DocJavaMethod { this.actualTypesMap = actualTypesMap; return this; } + + public Map getReturnSchema() { + return returnSchema; + } + + public DocJavaMethod setReturnSchema(Map returnSchema) { + this.returnSchema = returnSchema; + return this; + } + + public Map getRequestSchema() { + return requestSchema; + } + + public DocJavaMethod setRequestSchema(Map requestSchema) { + this.requestSchema = requestSchema; + return this; + } } diff --git a/src/main/java/com/power/doc/model/postman/UrlBean.java b/src/main/java/com/power/doc/model/postman/UrlBean.java new file mode 100644 index 0000000..4beae8d --- /dev/null +++ b/src/main/java/com/power/doc/model/postman/UrlBean.java @@ -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 path; + + private List host; + + private String port; + + private List query; + + private List variable; + + public String getRaw() { + return raw; + } + + public void setRaw(String raw) { + this.raw = raw; + } + + public List getPath() { + return path; + } + + public void setPath(List path) { + this.path = path; + } + + public List getQuery() { + return query; + } + + public void setQuery(List query) { + this.query = query; + } + + public List getVariable() { + return variable; + } + + public void setVariable(List variable) { + this.variable = variable; + } + + public List getHost() { + return host; + } + + public void setHost(List host) { + this.host = host; + } + + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } +} diff --git a/src/main/java/com/power/doc/model/postman/request/ParamBean.java b/src/main/java/com/power/doc/model/postman/request/ParamBean.java new file mode 100644 index 0000000..afeccb8 --- /dev/null +++ b/src/main/java/com/power/doc/model/postman/request/ParamBean.java @@ -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; + } +} diff --git a/src/main/java/com/power/doc/model/postman/request/RequestBean.java b/src/main/java/com/power/doc/model/postman/request/RequestBean.java index 015ad95..a174239 100644 --- a/src/main/java/com/power/doc/model/postman/request/RequestBean.java +++ b/src/main/java/com/power/doc/model/postman/request/RequestBean.java @@ -1,79 +1,80 @@ -/* - * smart-doc https://github.com/shalousun/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.postman.request; - -import com.power.doc.model.postman.request.body.BodyBean; -import com.power.doc.model.postman.request.header.HeaderBean; - -import java.util.List; - -/** - * @author xingzi - */ -public class RequestBean { - private String method; - private BodyBean body; - private String url; - private String description; - private List header; - - public String getMethod() { - return method; - } - - public void setMethod(String method) { - this.method = method; - } - - public BodyBean getBody() { - return body; - } - - public void setBody(BodyBean body) { - this.body = body; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public List getHeader() { - return header; - } - - public void setHeader(List header) { - this.header = header; - } -} +/* + * smart-doc https://github.com/shalousun/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.postman.request; + +import com.power.doc.model.postman.UrlBean; +import com.power.doc.model.postman.request.body.BodyBean; +import com.power.doc.model.postman.request.header.HeaderBean; + +import java.util.List; + +/** + * @author xingzi + */ +public class RequestBean { + private String method; + private BodyBean body; + private UrlBean url; + private String description; + private List header; + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public BodyBean getBody() { + return body; + } + + public void setBody(BodyBean body) { + this.body = body; + } + + public UrlBean getUrl() { + return url; + } + + public void setUrl(UrlBean url) { + this.url = url; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public List getHeader() { + return header; + } + + public void setHeader(List header) { + this.header = header; + } +} diff --git a/src/main/java/com/power/doc/model/postman/request/body/BodyBean.java b/src/main/java/com/power/doc/model/postman/request/body/BodyBean.java index 1167830..a9b6469 100644 --- a/src/main/java/com/power/doc/model/postman/request/body/BodyBean.java +++ b/src/main/java/com/power/doc/model/postman/request/body/BodyBean.java @@ -1,88 +1,86 @@ -/* - * smart-doc https://github.com/shalousun/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.postman.request.body; - - -import com.power.doc.model.FormData; - -import java.util.List; - -/** - * @author xingzi - */ -public class BodyBean { - private String mode; - private String raw; - private List formdata; - private BodyOptions options; - - public BodyBean(boolean isFormData) { - if (isFormData) { - - } else { - this.options = new BodyOptions(); - } - } - - public List getFormdata() { - return formdata; - } - - public void setFormdata(List formdata) { - this.formdata = formdata; - } - - public String getMode() { - return mode; - } - - public void setMode(String mode) { - this.mode = mode; - } - - public String getRaw() { - return raw; - } - - public void setRaw(String raw) { - this.raw = raw; - } - - private class BodyOptions { - private Raw raw; - - public BodyOptions() { - this.raw = new Raw(); - } - - private class Raw { - private String language; - - Raw() { - this.language = "json"; - } - } - } - - -} +/* + * smart-doc https://github.com/shalousun/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.postman.request.body; + + +import com.power.doc.model.FormData; + +import java.util.List; + +/** + * @author xingzi + */ +public class BodyBean { + private String mode; + private String raw; + private List formdata; + private BodyOptions options; + + public BodyBean(boolean isFormData) { + if (!isFormData) { + this.options = new BodyOptions(); + } + } + + public List getFormdata() { + return formdata; + } + + public void setFormdata(List formdata) { + this.formdata = formdata; + } + + public String getMode() { + return mode; + } + + public void setMode(String mode) { + this.mode = mode; + } + + public String getRaw() { + return raw; + } + + public void setRaw(String raw) { + this.raw = raw; + } + + private class BodyOptions { + private Raw raw; + + public BodyOptions() { + this.raw = new Raw(); + } + + private class Raw { + private String language; + + Raw() { + this.language = "json"; + } + } + } + + +} diff --git a/src/main/java/com/power/doc/template/IDocBuildTemplate.java b/src/main/java/com/power/doc/template/IDocBuildTemplate.java index b339198..63ab659 100644 --- a/src/main/java/com/power/doc/template/IDocBuildTemplate.java +++ b/src/main/java/com/power/doc/template/IDocBuildTemplate.java @@ -29,8 +29,8 @@ import com.power.doc.helper.ParamsBuildHelper; import com.power.doc.model.*; import com.power.doc.utils.DocClassUtil; import com.power.doc.utils.DocUtil; -import com.power.doc.utils.JavaClassUtil; import com.power.doc.utils.JavaClassValidateUtil; +import com.power.doc.utils.OpenApiSchemaUtil; import com.thoughtworks.qdox.model.JavaClass; import com.thoughtworks.qdox.model.JavaMethod; import com.thoughtworks.qdox.model.JavaType; @@ -120,15 +120,15 @@ public interface IDocBuildTemplate { return null; } if (JavaClassValidateUtil.isPrimitive(typeName)) { - String processedName = projectBuilder.getApiConfig().getShowJavaType() ? - JavaClassUtil.getClassSimpleName(typeName) : DocClassUtil.processTypeNameForParams(typeName); - return ParamsBuildHelper.primitiveReturnRespComment(processedName); + docJavaMethod.setReturnSchema(OpenApiSchemaUtil.primaryTypeSchema(typeName)); + return null; } if (JavaClassValidateUtil.isCollection(typeName)) { if (returnType.contains("<")) { String gicName = returnType.substring(returnType.indexOf("<") + 1, returnType.lastIndexOf(">")); 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(), Boolean.TRUE, new HashMap<>(), projectBuilder, null, 0); @@ -142,7 +142,8 @@ public interface IDocBuildTemplate { return null; } 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(), Boolean.TRUE, new HashMap<>(), projectBuilder, null, 0); diff --git a/src/main/java/com/power/doc/template/SpringBootDocBuildTemplate.java b/src/main/java/com/power/doc/template/SpringBootDocBuildTemplate.java index 3b884b9..9474120 100644 --- a/src/main/java/com/power/doc/template/SpringBootDocBuildTemplate.java +++ b/src/main/java/com/power/doc/template/SpringBootDocBuildTemplate.java @@ -39,6 +39,7 @@ import com.thoughtworks.qdox.model.expression.AnnotationValue; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Logger; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -50,7 +51,7 @@ import static com.power.doc.constants.DocTags.IGNORE; * @author yu 2019/12/21. */ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { - + private static Logger log = Logger.getLogger(SpringBootDocBuildTemplate.class.getName()); private List headers; /** @@ -148,15 +149,16 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { if (method.isPrivate() || Objects.nonNull(method.getTagByName(IGNORE))) { 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 RequestMapping requestMapping = new SpringMVCRequestMappingHandler() .handle(projectBuilder.getServerUrl(), baseUrl, method, constantsMap); if (Objects.isNull(requestMapping)) { continue; } + if (StringUtil.isEmpty(method.getComment()) && apiConfig.isStrict()) { + throw new RuntimeException("Unable to find comment for method " + method.getName() + " in " + cls.getCanonicalName()); + } + methodOrder++; ApiMethodDoc apiMethodDoc = new ApiMethodDoc(); apiMethodDoc.setName(method.getName()); @@ -186,12 +188,20 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { apiMethodDoc.setServerUrl(projectBuilder.getServerUrl()); apiMethodDoc.setPath(requestMapping.getShortUrl()); apiMethodDoc.setDeprecated(requestMapping.isDeprecated()); + ApiMethodReqParam apiMethodReqParam = requestParams(docJavaMethod, projectBuilder); + apiMethodDoc.setPathParams(apiMethodReqParam.getPathParams()); + apiMethodDoc.setQueryParams(apiMethodReqParam.getQueryParams()); // build request params - List requestParams = requestParams(docJavaMethod, projectBuilder); 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 allApiReqHeaders; if (this.headers != null) { allApiReqHeaders = Stream.of(this.headers, apiReqHeaders) @@ -217,6 +227,8 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { if (paramsDataToTree) { responseParams = ApiParamTreeUtil.apiParamToTree(responseParams); } + apiMethodDoc.setReturnSchema(docJavaMethod.getReturnSchema()); + apiMethodDoc.setRequestSchema(docJavaMethod.getRequestSchema()); apiMethodDoc.setResponseParams(responseParams); methodDocList.add(apiMethodDoc); } @@ -444,7 +456,7 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { return requestExample; } - private List requestParams(final DocJavaMethod docJavaMethod, ProjectDocConfigBuilder builder) { + private ApiMethodReqParam requestParams(final DocJavaMethod docJavaMethod, ProjectDocConfigBuilder builder) { JavaMethod javaMethod = docJavaMethod.getJavaMethod(); boolean isStrict = builder.getApiConfig().isStrict(); Map responseFieldMap = new HashMap<>(); @@ -453,11 +465,12 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { Map paramTagMap = DocUtil.getParamsComments(javaMethod, DocTags.PARAM, className); List parameterList = javaMethod.getParameters(); if (parameterList.size() < 1) { - return null; + return new ApiMethodReqParam(); } + List paramList = new ArrayList<>(); Map constantsMap = builder.getConstantsMap(); boolean requestFieldToUnderline = builder.getApiConfig().isRequestFieldToUnderline(); - List paramList = new ArrayList<>(); + Map actualTypesMap = docJavaMethod.getActualTypesMap(); int requestBodyCounter = 0; out: @@ -495,7 +508,12 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { if (typeName.contains(DocGlobalConstants.MULTIPART_FILE_FULLY)) { ApiParam param = ApiParam.of().setField(paramName).setType("file") .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); continue; } @@ -542,10 +560,7 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { } boolean required = Boolean.parseBoolean(strRequired); boolean queryParam = false; - if (isPathVariable) { - comment = comment + " (This is path parameter.)"; - } else if (!isRequestBody && requestBodyCounter > 0) { - comment = comment + " (This is query parameter.)"; + if (!isRequestBody && !isPathVariable) { queryParam = true; } if (JavaClassValidateUtil.isCollection(fullTypeName) || JavaClassValidateUtil.isArray(fullTypeName)) { @@ -563,6 +578,10 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { .setId(paramList.size() + 1) .setType("array"); paramList.add(param); + if (requestBodyCounter > 0) { + Map map = OpenApiSchemaUtil.arrayTypeSchema(gicName); + docJavaMethod.setRequestSchema(map); + } } else { if (requestBodyCounter > 0) { //for json @@ -583,7 +602,14 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { .setQueryParam(queryParam).setValue(value) .setDesc(comment).setRequired(required).setVersion(DocGlobalConstants.DEFAULT_VERSION); paramList.add(param); + if (requestBodyCounter > 0) { + Map map = OpenApiSchemaUtil.primaryTypeSchema(simpleName); + docJavaMethod.setRequestSchema(map); + } } 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)) { ApiParam apiParam = ApiParam.of().setField(paramName).setType("map") .setId(paramList.size() + 1) @@ -591,10 +617,29 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { .setQueryParam(queryParam) .setDesc(comment).setRequired(required).setVersion(DocGlobalConstants.DEFAULT_VERSION); paramList.add(apiParam); + if (requestBodyCounter > 0) { + Map map = OpenApiSchemaUtil.mapTypeSchema("object"); + docJavaMethod.setRequestSchema(map); + } continue; } 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 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 else if (javaClass.isEnum()) { @@ -610,7 +655,26 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { paramList.addAll(ParamsBuildHelper.buildParams(typeName, DocGlobalConstants.EMPTY, 0, "true", responseFieldMap, Boolean.FALSE, new HashMap<>(), builder, groupClasses, 0)); } } - return paramList; + List pathParams = new ArrayList<>(); + List queryParams = new ArrayList<>(); + List 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) { diff --git a/src/main/java/com/power/doc/utils/DocUtil.java b/src/main/java/com/power/doc/utils/DocUtil.java index c2b2ec4..fb7a0d8 100644 --- a/src/main/java/com/power/doc/utils/DocUtil.java +++ b/src/main/java/com/power/doc/utils/DocUtil.java @@ -463,9 +463,8 @@ public class DocUtil { switch (type) { case "int32": case "int16": - return "integer"; case "int64": - return "long"; + return "integer"; case "double": case "float": case "number": diff --git a/src/main/java/com/power/doc/utils/OpenApiSchemaUtil.java b/src/main/java/com/power/doc/utils/OpenApiSchemaUtil.java new file mode 100644 index 0000000..35e26f1 --- /dev/null +++ b/src/main/java/com/power/doc/utils/OpenApiSchemaUtil.java @@ -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 primaryTypeSchema(String primaryType){ + Map map = new HashMap<>(); + map.put("type", DocClassUtil.processTypeNameForParams(primaryType)); + return map; + } + + public static Map mapTypeSchema(String primaryType){ + Map map = new LinkedHashMap<>(); + map.put("type", "object"); + Map items = new HashMap<>(); + items.put("type", DocClassUtil.processTypeNameForParams(primaryType)); + map.put("additionalProperties", items); + return map; + } + + public static Map arrayTypeSchema(String primaryType){ + Map map = new HashMap<>(); + map.put("type", "array"); + Map items = new HashMap<>(); + items.put("type", DocClassUtil.processTypeNameForParams(primaryType)); + map.put("items", items); + return map; + } +} diff --git a/src/main/java/com/power/doc/utils/PathUtil.java b/src/main/java/com/power/doc/utils/PathUtil.java index d313718..e61890b 100644 --- a/src/main/java/com/power/doc/utils/PathUtil.java +++ b/src/main/java/com/power/doc/utils/PathUtil.java @@ -1,49 +1,63 @@ -/* - * smart-doc https://github.com/shalousun/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.utils; - -import com.power.common.util.StringUtil; -import org.apache.commons.lang3.StringUtils; - -import java.io.File; - -public class PathUtil { - - /** - * Get the java class name - * - * @param parentDir parent dir - * @param className class name - * @return java file name - */ - public static String javaFilePath(String parentDir, String className) { - if (StringUtil.isEmpty(parentDir)) { - parentDir = "java.io.tmpdir"; - } - if (!StringUtils.endsWith(parentDir, File.separator)) { - parentDir += File.separator; - } - className = className.replaceAll("\\.", "\\" + File.separator); - return parentDir + className + ".java"; - } -} +/* + * smart-doc https://github.com/shalousun/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.utils; + +import com.power.common.util.StringUtil; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; + +public class PathUtil { + + /** + * Get the java class name + * + * @param parentDir parent dir + * @param className class name + * @return java file name + */ + public static String javaFilePath(String parentDir, String className) { + if (StringUtil.isEmpty(parentDir)) { + parentDir = "java.io.tmpdir"; + } + if (!StringUtils.endsWith(parentDir, File.separator)) { + parentDir += File.separator; + } + className = className.replaceAll("\\.", "\\" + File.separator); + 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; + } +} diff --git a/src/main/resources/template/AllInOne.adoc b/src/main/resources/template/AllInOne.adoc index 7b34312..319ec70 100644 --- a/src/main/resources/template/AllInOne.adoc +++ b/src/main/resources/template/AllInOne.adoc @@ -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)){%> -*Request-parameters:* +*Body-parameters:* [width="100%",options="header"] [stripes=even] diff --git a/src/main/resources/template/AllInOne.btl b/src/main/resources/template/AllInOne.btl index 59efa7e..18ea36d 100644 --- a/src/main/resources/template/AllInOne.btl +++ b/src/main/resources/template/AllInOne.btl @@ -44,9 +44,33 @@ Header | Type|Description|Required|Since ---|---|---|---|---- ${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)){%> -**Request-parameters:** +**Body-parameters:** Parameter | Type|Description|Required|Since ---|---|---|---|--- diff --git a/src/main/resources/template/AllInOne.html b/src/main/resources/template/AllInOne.html index 8dd535a..3b20095 100644 --- a/src/main/resources/template/AllInOne.html +++ b/src/main/resources/template/AllInOne.html @@ -1,24 +1,372 @@ -<%if(isNotEmpty(projectName)){%>${projectName}<%}else{%>API Reference<%}%>
<%if(isNotEmpty(revisionLogList)){%>
<%for(revisionLog in revisionLogList){%><%}%>
VersionUpdate TimeStatusAuthorDescription

${revisionLog.version}

${revisionLog.revisionTime}

${revisionLog.status}

${revisionLog.author}

${revisionLog.remarks}

<%}%><%for(api in apiDocList){%>

${api.order}. ${api.desc}

<%for(doc in api.list){%>

<%if(doc.deprecated){%>${api.order}.${doc.order}. ${doc.desc}<%}else{%>${api.order}.${doc.order}. ${doc.desc}<%}%>

Type: ${doc.type}

<%if(isNotEmpty(doc.author)){%>

Author: ${doc.author}

<%}%>

Content-Type: ${doc.contentType}

Description: ${doc.detail}

<%if(isNotEmpty(doc.requestHeaders)){%>

Request-headers:

<%for(header in doc.requestHeaders){%><%}%>
HeaderTypeDescriptionRequiredSince

${header.name}

${header.type}

${header.desc}

${header.required}

${header.since}

<%}%><%if(isNotEmpty(doc.requestParams)){%>

Request-parameters:

<%for(param in doc.requestParams){%><%}%>
ParameterTypeDescriptionRequiredSince

${param.field}

${param.type}

${param.desc}

${param.required}

${param.version}

<%}%><%if(isNotEmpty(doc.requestUsage)&&isRequestExample){%>

Request-example:

${doc.requestUsage}
<%}%><%if(isNotEmpty(doc.responseParams)){%>

Response-fields:

<%for(param in doc.responseParams){%><%}%>
FieldTypeDescriptionSince

${param.field}

${param.type}

${param.desc}

${param.version}

<%}%><%if(isNotEmpty(doc.responseUsage)&&isResponseExample){%>

Response-example:

${doc.responseUsage}
<%}%>
<%}%>
<%}%><%if(isNotEmpty(errorCodeList)){%>

${apiDocList.~size+1}. ${errorListTitle}

<%for(error in errorCodeList){%><%}%>
Error codeDescription

${error.value}

${error.desc}

<%}%><%if(isNotEmpty(dictList)){%>

${dictListOrder}. ${dictListTitle}

<% for(dict in dictList){ %>

${dictListOrder}.${dict.order}. ${dict.title}

<%for(dataDict in dict.dataDictList){%><%}%>
CodeTypeDescription

${dataDict.value}

${dataDict.type}

${dataDict.desc}

<%}%>
<%}%>
Generated by smart-doc at ${createTime}Suggestions,contact,support and error reporting on Gitee or Github
- + + + + +
<%if(isNotEmpty(revisionLogList)){%> +
+
+ + + + + + + + + + + + + + + + + + <%for(revisionLog in revisionLogList){%> + + + + + + + + <%}%> + +
VersionUpdate TimeStatusAuthorDescription

${revisionLog.version}

${revisionLog.revisionTime}

+

${revisionLog.status}

${revisionLog.author}

${revisionLog.remarks}

+
+
+ <%}%><%for(api in apiDocList){%> +

${api.order}. ${api.desc} +

+
<%for(doc in api.list){%> +

<%if(doc.deprecated){%>${api.order}.${doc.order}. ${doc.desc}<%}else{%>${api.order}.${doc.order}. ${doc.desc}<%}%> +

+ +

Type: ${doc.type}

+ <%if(isNotEmpty(doc.author)){%> +

Author: ${doc.author}

+ <%}%> +

Content-Type: ${doc.contentType}

+

Description: ${doc.detail}

+ <%if(isNotEmpty(doc.requestHeaders)){%> +

Request-headers:

+ + + + + + + + + + + + + + + + + + <%for(header in doc.requestHeaders){%> + + + + + + + + <%}%> + +
HeaderTypeDescriptionRequiredSince

${header.name}

${header.type}

${header.desc}

${header.required}

${header.since}

+ <%}%> + <%if(isNotEmpty(doc.pathParams)){%> +

Path-parameters:

+ + + + + + + + + + + + + + + + + + <%for(param in doc.pathParams){%> + + + + + + + + <%}%> + +
ParameterTypeDescriptionRequiredSince

${param.field}

${param.type}

${param.desc}

${param.required}

${param.version}

+ <%}%> + <%if(isNotEmpty(doc.queryParams)){%> +

Query-parameters:

+ + + + + + + + + + + + + + + + + + <%for(param in doc.queryParams){%> + + + + + + + + <%}%> + +
ParameterTypeDescriptionRequiredSince

${param.field}

${param.type}

${param.desc}

${param.required}

${param.version}

+ <%}%> + <%if(isNotEmpty(doc.requestParams)){%> +

Body-parameters:

+ + + + + + + + + + + + + + + + + + <%for(param in doc.requestParams){%> + + + + + + + + <%}%> + +
ParameterTypeDescriptionRequiredSince

${param.field}

${param.type}

${param.desc}

${param.required}

${param.version}

+ <%}%> + <%if(isNotEmpty(doc.requestUsage)&&isRequestExample){%> +

Request-example:

+
+
+
${doc.requestUsage}
+
+
+ <%}%><%if(isNotEmpty(doc.responseParams)){%> +

Response-fields:

+ + + + + + + + + + + + + + + + <%for(param in doc.responseParams){%> + + + + + + + <%}%> + +
FieldTypeDescriptionSince

${param.field}

${param.type}

${param.desc}

${param.version}

+ <%}%><%if(isNotEmpty(doc.responseUsage)&&isResponseExample){%> +

Response-example:

+
+
+
${doc.responseUsage}
+
+
+ <%}%> +
+ <%}%> +
+
+ <%}%><%if(isNotEmpty(errorCodeList)){%> +

${apiDocList.~size+1}. ${errorListTitle} +

+
+ + + + + + + + + + + + <%for(error in errorCodeList){%> + + + + + <%}%> + +
Error codeDescription

${error.value}

${error.desc}

+
+
+ <%}%><%if(isNotEmpty(dictList)){%> +

${dictListOrder}. ${dictListTitle} +

+
<% for(dict in dictList){ %> +

${dictListOrder}.${dict.order}. ${dict.title} +

+ + + + + + + + + + + + + + <%for(dataDict in dict.dataDictList){%> + + + + + + <%}%> + +
CodeTypeDescription

${dataDict.value}

${dataDict.type}

${dataDict.desc}

+
+ <%}%> +
+
+ <%}%> +
Generated by smart-doc at ${createTime}Suggestions,contact,support and error reporting on Gitee or Github +
+
+ diff --git a/src/main/resources/template/ApiDoc.adoc b/src/main/resources/template/ApiDoc.adoc index d9b9d1c..f9b1580 100644 --- a/src/main/resources/template/ApiDoc.adoc +++ b/src/main/resources/template/ApiDoc.adoc @@ -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)){%> *Request-parameters:* @@ -43,8 +73,9 @@ for(param in doc.requestParams){ %> |${param.field}|${param.type}|${param.desc}|${param.required}|${param.version} <%}%> -<%}%> |==================== +<%}%> + <%if(isNotEmpty(doc.requestUsage)&&isRequestExample){%> *Request-example:* @@ -64,8 +95,9 @@ for(param in doc.responseParams){ %> |${param.field}|${param.type}|${param.desc}|${param.version} <%}%> -<%}%> |==================== +<%}%> + <%if(isNotEmpty(doc.responseUsage)&&isResponseExample){%> *Response-example:* diff --git a/src/main/resources/template/ApiDoc.btl b/src/main/resources/template/ApiDoc.btl index 2b76d44..b4b3b2c 100644 --- a/src/main/resources/template/ApiDoc.btl +++ b/src/main/resources/template/ApiDoc.btl @@ -28,8 +28,32 @@ Header | Type|Description|Required|Since ${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)){%> -**Request-parameters:** +**Body-parameters:** Parameter|Type|Description|Required|Since ---|---|---|---|---