support spring mvc form data

This commit is contained in:
oppofind 2019-12-25 01:20:26 +08:00
parent d046deda9e
commit ca12a4860d
21 changed files with 477 additions and 180 deletions

View File

@ -154,4 +154,6 @@
2. 修改支持上传文件参数不列举到文档的问题。
3. 新增ApiDataBuilder用于获取smart-doc生成的文档数据包含header、字典、错误码等。
4. 合并fork分支的github book html5模板新增搜索和锚点。
5. 重点smart-doc的maven插件smart-doc-maven-plugin增强对maven标准项目的支持。
5. 新增自定义@mock tag用于指定生成文档的字段值@param 的参数注释增加mock值的功能(@param name 姓名|张三)
6. 重点smart-doc的maven插件smart-doc-maven-plugin增强对maven标准项目的支持。
7. 全面支持表单。

View File

@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>smart-doc</artifactId>
<packaging>jar</packaging>
<version>1.7.9</version>
<version>1.8.0</version>
<name>smart-doc</name>
<url>https://github.com/shalousun/smart-doc.git</url>

View File

@ -2,6 +2,8 @@ package com.power.doc.builder;
import com.power.doc.model.ApiConfig;
import com.power.doc.model.ApiDoc;
import com.power.doc.template.IDocBuildTemplate;
import com.power.doc.template.SpringBootDocBuildTemplate;
import com.thoughtworks.qdox.JavaProjectBuilder;
import java.util.List;
@ -29,8 +31,9 @@ public class AdocDocBuilder {
DocBuilderTemplate builderTemplate = new DocBuilderTemplate();
builderTemplate.checkAndInit(config);
JavaProjectBuilder javaProjectBuilder = new JavaProjectBuilder();
SourceBuilder sourceBuilder = new SourceBuilder(config,javaProjectBuilder);
List<ApiDoc> apiDocList = sourceBuilder.getControllerApiData();
ProjectDocConfigBuilder configBuilder = new ProjectDocConfigBuilder(config,javaProjectBuilder);
IDocBuildTemplate docBuildTemplate = new SpringBootDocBuildTemplate();
List<ApiDoc> apiDocList = docBuildTemplate.getApiData(configBuilder);
if (config.isAllInOne()) {
builderTemplate.buildAllInOne(apiDocList, config, javaProjectBuilder,ALL_IN_ONE_ADOC_TPL, INDEX_DOC);
} else {

View File

@ -3,6 +3,8 @@ package com.power.doc.builder;
import com.power.common.util.DateTimeUtil;
import com.power.doc.model.ApiConfig;
import com.power.doc.model.ApiDoc;
import com.power.doc.template.IDocBuildTemplate;
import com.power.doc.template.SpringBootDocBuildTemplate;
import com.thoughtworks.qdox.JavaProjectBuilder;
import java.util.List;
@ -28,8 +30,9 @@ public class ApiDocBuilder {
JavaProjectBuilder javaProjectBuilder = new JavaProjectBuilder();
DocBuilderTemplate builderTemplate = new DocBuilderTemplate();
builderTemplate.checkAndInit(config);
SourceBuilder sourceBuilder = new SourceBuilder(config,javaProjectBuilder);
List<ApiDoc> apiDocList = sourceBuilder.getControllerApiData();
ProjectDocConfigBuilder configBuilder = new ProjectDocConfigBuilder(config,javaProjectBuilder);
IDocBuildTemplate docBuildTemplate = new SpringBootDocBuildTemplate();
List<ApiDoc> apiDocList = docBuildTemplate.getApiData(configBuilder);
if (config.isAllInOne()) {
String version = config.isCoverOld() ? "" : "-V" + DateTimeUtil.long2Str(System.currentTimeMillis(), DATE_FORMAT);
builderTemplate.buildAllInOne(apiDocList, config, javaProjectBuilder,ALL_IN_ONE_MD_TPL, "AllInOne" + version + ".md");

View File

@ -5,6 +5,8 @@ import com.power.doc.constants.DocGlobalConstants;
import com.power.doc.constants.DocLanguage;
import com.power.doc.constants.TemplateVariable;
import com.power.doc.model.*;
import com.power.doc.template.IDocBuildTemplate;
import com.power.doc.template.SpringBootDocBuildTemplate;
import com.power.doc.utils.BeetlTemplateUtil;
import com.power.doc.utils.DocUtil;
import com.thoughtworks.qdox.JavaProjectBuilder;
@ -61,15 +63,15 @@ public class DocBuilderTemplate {
* @param javaProjectBuilder JavaProjectBuilder
* @return
*/
public ApiAllData getApiData(ApiConfig config,JavaProjectBuilder javaProjectBuilder) {
public ApiAllData getApiData(ApiConfig config, JavaProjectBuilder javaProjectBuilder) {
ApiAllData apiAllData = new ApiAllData();
apiAllData.setProjectName(config.getProjectName());
apiAllData.setProjectId(DocUtil.handleId(config.getProjectName()));
apiAllData.setLanguage(config.getLanguage().getCode());
apiAllData.setApiDocList(listOfApiData(config,javaProjectBuilder));
apiAllData.setApiDocList(listOfApiData(config, javaProjectBuilder));
apiAllData.setErrorCodeList(errorCodeDictToList(config));
apiAllData.setRevisionLogs(config.getRevisionLogs());
apiAllData.setApiDocDictList(buildDictionary(config,javaProjectBuilder));
apiAllData.setApiDocDictList(buildDictionary(config, javaProjectBuilder));
return apiAllData;
}
@ -101,13 +103,13 @@ public class DocBuilderTemplate {
/**
* Merge all api doc into one document
*
* @param apiDocList list data of Api doc
* @param config api config
* @param apiDocList list data of Api doc
* @param config api config
* @param javaProjectBuilder JavaProjectBuilder
* @param template template
* @param outPutFileName output file
* @param template template
* @param outPutFileName output file
*/
public void buildAllInOne(List<ApiDoc> apiDocList, ApiConfig config,JavaProjectBuilder javaProjectBuilder, String template, String outPutFileName) {
public void buildAllInOne(List<ApiDoc> apiDocList, ApiConfig config, JavaProjectBuilder javaProjectBuilder, String template, String outPutFileName) {
String outPath = config.getOutPath();
String strTime = DateTimeUtil.long2Str(now, DateTimeUtil.DATE_FORMAT_SECOND);
FileUtil.mkdirs(outPath);
@ -137,7 +139,7 @@ public class DocBuilderTemplate {
tpl.binding(TemplateVariable.ERROR_LIST_TITLE.getVariable(), DocGlobalConstants.ERROR_CODE_LIST_CN_TITLE);
tpl.binding(TemplateVariable.DICT_LIST_TITLE.getVariable(), DocGlobalConstants.DICT_CN_TITLE);
}
List<ApiDocDict> apiDocDictList = buildDictionary(config,javaProjectBuilder);
List<ApiDocDict> apiDocDictList = buildDictionary(config, javaProjectBuilder);
tpl.binding(TemplateVariable.DICT_LIST.getVariable(), apiDocDictList);
FileUtil.nioWriteFile(tpl.render(), outPath + FILE_SEPARATOR + outPutFileName);
}
@ -167,7 +169,7 @@ public class DocBuilderTemplate {
*/
public void buildSingleControllerApi(String outPath, String controllerName, String template, String fileExtension) {
FileUtil.mkdirs(outPath);
SourceBuilder sourceBuilder = new SourceBuilder(Boolean.TRUE,new JavaProjectBuilder());
SourceBuilder sourceBuilder = new SourceBuilder(Boolean.TRUE, new JavaProjectBuilder());
ApiDoc doc = sourceBuilder.getSingleControllerApiData(controllerName);
Template mapper = BeetlTemplateUtil.getByName(template);
mapper.binding(TemplateVariable.DESC.getVariable(), doc.getDesc());
@ -179,7 +181,7 @@ public class DocBuilderTemplate {
/**
* Build dictionary
*
* @param config api config
* @param config api config
* @param javaProjectBuilder JavaProjectBuilder
* @return list of ApiDocDict
*/
@ -239,21 +241,22 @@ public class DocBuilderTemplate {
}
clzz = Class.forName(dictionary.getEnumClassName());
}
List<ApiErrorCode> enumDictionaryList = EnumUtil.getEnumInformation(clzz,dictionary.getCodeField(),
List<ApiErrorCode> enumDictionaryList = EnumUtil.getEnumInformation(clzz, dictionary.getCodeField(),
dictionary.getDescField());
errorCodeList.addAll(enumDictionaryList);
}
} catch ( ClassNotFoundException e) {
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return errorCodeList;
}
}
private List<ApiDoc> listOfApiData(ApiConfig config,JavaProjectBuilder javaProjectBuilder) {
private List<ApiDoc> listOfApiData(ApiConfig config, JavaProjectBuilder javaProjectBuilder) {
this.checkAndInitForGetApiData(config);
config.setMd5EncryptedHtmlName(true);
SourceBuilder sourceBuilder = new SourceBuilder(config,javaProjectBuilder);
return sourceBuilder.getControllerApiData();
ProjectDocConfigBuilder configBuilder = new ProjectDocConfigBuilder(config, javaProjectBuilder);
IDocBuildTemplate docBuildTemplate = new SpringBootDocBuildTemplate();
return docBuildTemplate.getApiData(configBuilder);
}
}

View File

@ -10,6 +10,8 @@ import com.power.doc.model.ApiConfig;
import com.power.doc.model.ApiDoc;
import com.power.doc.model.ApiDocDict;
import com.power.doc.model.ApiErrorCode;
import com.power.doc.template.IDocBuildTemplate;
import com.power.doc.template.SpringBootDocBuildTemplate;
import com.power.doc.utils.BeetlTemplateUtil;
import com.power.doc.utils.MarkDownUtil;
import com.thoughtworks.qdox.JavaProjectBuilder;
@ -39,8 +41,9 @@ public class HtmlApiDocBuilder {
DocBuilderTemplate builderTemplate = new DocBuilderTemplate();
builderTemplate.checkAndInit(config);
JavaProjectBuilder javaProjectBuilder = new JavaProjectBuilder();
SourceBuilder sourceBuilder = new SourceBuilder(config,javaProjectBuilder);
List<ApiDoc> apiDocList = sourceBuilder.getControllerApiData();
ProjectDocConfigBuilder configBuilder = new ProjectDocConfigBuilder(config,javaProjectBuilder);
IDocBuildTemplate docBuildTemplate = new SpringBootDocBuildTemplate();
List<ApiDoc> apiDocList = docBuildTemplate.getApiData(configBuilder);
if (config.isAllInOne()) {
Template indexCssTemplate = BeetlTemplateUtil.getByName(ALL_IN_ONE_CSS);
FileUtil.nioWriteFile(indexCssTemplate.render(), config.getOutPath() + FILE_SEPARATOR + ALL_IN_ONE_CSS);
@ -52,7 +55,6 @@ public class HtmlApiDocBuilder {
buildApiDoc(apiDocList, config.getOutPath());
buildErrorCodeDoc(config.getErrorCodes(), config.getOutPath());
buildDictionary(apiDocDictList, config.getOutPath());
}
}

View File

@ -15,7 +15,7 @@ import com.power.doc.model.postman.ItemBean;
import com.power.doc.model.postman.RequestItem;
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.FormData;
import com.power.doc.model.FormData;
import com.power.doc.model.postman.request.header.HeaderBean;
import com.thoughtworks.qdox.JavaProjectBuilder;
import org.apache.commons.lang3.StringUtils;

View File

@ -52,7 +52,7 @@ public class ProjectDocConfigBuilder {
}
this.javaProjectBuilder = javaProjectBuilder;
this.loadJavaSource(apiConfig.getSourceCodePaths(),this.javaProjectBuilder);
this.initClassFilesMap(apiConfig);
this.initClassFilesMap();
this.initCustomResponseFieldsMap(apiConfig);
}
@ -76,7 +76,7 @@ public class ProjectDocConfigBuilder {
}
}
private void initClassFilesMap(ApiConfig config) {
private void initClassFilesMap() {
Collection<JavaClass> javaClasses = javaProjectBuilder.getClasses();
for (JavaClass cls : javaClasses) {
classFilesMap.put(cls.getFullyQualifiedName(), cls);

View File

@ -6,9 +6,8 @@ import com.power.common.util.JsonFormatUtil;
import com.power.common.util.StringUtil;
import com.power.common.util.UrlUtil;
import com.power.doc.constants.*;
import com.power.doc.helper.JsonBuildHelper;
import com.power.doc.model.*;
import com.power.doc.model.postman.request.body.FormData;
import com.power.doc.model.FormData;
import com.power.doc.utils.DocClassUtil;
import com.power.doc.utils.DocUtil;
import com.power.doc.utils.ReqJsonUtil;

View File

@ -5,7 +5,7 @@ import com.power.common.util.UrlUtil;
import com.power.doc.constants.DocGlobalConstants;
import com.power.doc.constants.Methods;
import com.power.doc.constants.SpringMvcAnnotations;
import com.power.doc.model.RequestMapping;
import com.power.doc.model.request.RequestMapping;
import com.power.doc.utils.DocUrlUtil;
import com.power.doc.utils.DocUtil;
import com.thoughtworks.qdox.model.JavaAnnotation;
@ -86,7 +86,7 @@ public class SpringMVCRequestMappingHandler {
shortUrl = DocUrlUtil.getMvcUrls("", controllerBaseUrl, Arrays.asList(urls));
} else {
url = UrlUtil.simplifyUrl(serverUrl + "/" + controllerBaseUrl + "/" + shortUrl);
shortUrl = UrlUtil.simplifyUrl("/" + controllerBaseUrl + "/" + url);
shortUrl = UrlUtil.simplifyUrl("/" + controllerBaseUrl + "/" + shortUrl);
}
RequestMapping requestMapping = RequestMapping.builder().
setMediaType(mediaType).setMethodType(methodType).setUrl(url).setShortUrl(shortUrl)

View File

@ -0,0 +1,128 @@
package com.power.doc.helper;
import com.power.common.util.RandomUtil;
import com.power.common.util.StringUtil;
import com.power.doc.builder.ProjectDocConfigBuilder;
import com.power.doc.model.FormData;
import com.power.doc.utils.DocClassUtil;
import com.power.doc.utils.DocUtil;
import com.power.doc.utils.JavaClassUtil;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaField;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author yu 2019/12/25.
*/
public class FormDataBuildHelper {
/**
* build form data
*
* @param className class name
* @param registryClasses Class container
* @param counter invoked counter
* @param builder ProjectDocConfigBuilder
* @param pre pre
* @return list of FormData
*/
public static List<FormData> getFormData(String className, Map<String, String> registryClasses, int counter, ProjectDocConfigBuilder builder, String pre) {
if (StringUtil.isEmpty(className)) {
throw new RuntimeException("Class name can't be null or empty.");
}
// Check circular reference
List<FormData> formDataList = new ArrayList<>();
if (registryClasses.containsKey(className) && counter > registryClasses.size()) {
return formDataList;
}
// Registry class
registryClasses.put(className, className);
counter++;
String simpleName = DocClassUtil.getSimpleName(className);
String[] globGicName = DocClassUtil.getSimpleGicName(className);
JavaClass cls = builder.getJavaProjectBuilder().getClassByName(simpleName);
List<JavaField> fields = JavaClassUtil.getFields(cls, 0);
if (DocClassUtil.isPrimitive(simpleName)) {
FormData formData = new FormData();
formData.setKey(pre);
formData.setType("text");
formData.setValue(RandomUtil.randomValueByType(className));
formDataList.add(formData);
return formDataList;
}
if (DocClassUtil.isCollection(simpleName) || DocClassUtil.isArray(simpleName)) {
String gicName = globGicName[0];
if (DocClassUtil.isArray(gicName)) {
gicName = gicName.substring(0, gicName.indexOf("["));
}
formDataList.addAll(getFormData(gicName, registryClasses, counter, builder, pre + "[]"));
}
int n = 0;
out:
for (JavaField field : fields) {
String fieldName = field.getName();
String subTypeName = field.getType().getFullyQualifiedName();
String fieldGicName = field.getType().getGenericCanonicalName();
JavaClass javaClass = builder.getJavaProjectBuilder().getClassByName(subTypeName);
if ("this$0".equals(fieldName) ||
"serialVersionUID".equals(fieldName) ||
DocClassUtil.isIgnoreFieldTypes(subTypeName)) {
continue;
}
String typeSimpleName = field.getType().getSimpleName();
if (DocClassUtil.isMap(subTypeName)) {
continue;
}
String comment = field.getComment();
if (StringUtil.isNotEmpty(comment)) {
comment = DocUtil.replaceNewLineToHtmlBr(comment);
}
if (DocClassUtil.isPrimitive(subTypeName)) {
String fieldValue = DocUtil.getValByTypeAndFieldName(typeSimpleName, field.getName());
FormData formData = new FormData();
formData.setKey(pre + fieldName);
formData.setType("text");
formData.setValue(fieldValue);
formData.setDesc(comment);
formDataList.add(formData);
} else if (javaClass.isEnum()) {
Object value = JavaClassUtil.getEnumValue(javaClass, Boolean.FALSE);
FormData formData = new FormData();
formData.setKey(pre + fieldName);
formData.setType("text");
formData.setValue(String.valueOf(value));
formData.setDesc(comment);
formDataList.add(formData);
} else if (DocClassUtil.isCollection(subTypeName)) {
String gNameTemp = field.getType().getGenericCanonicalName();
String[] gNameArr = DocClassUtil.getSimpleGicName(gNameTemp);
if (gNameArr.length == 0) {
continue out;
}
String gName = DocClassUtil.getSimpleGicName(gNameTemp)[0];
if (!DocClassUtil.isPrimitive(gName)) {
if (!simpleName.equals(gName) && !gName.equals(simpleName)) {
if (gName.length() == 1) {
int len = globGicName.length;
if (len > 0) {
String gicName = (n < len) ? globGicName[n] : globGicName[len - 1];
if (!DocClassUtil.isPrimitive(gicName) && !simpleName.equals(gicName)) {
formDataList.addAll(getFormData(gicName, registryClasses, counter, builder, pre + fieldName + "[0]."));
}
}
} else {
formDataList.addAll(getFormData(gName, registryClasses, counter, builder, pre + fieldName + "[0]."));
}
}
}
} else {
formDataList.addAll(getFormData(fieldGicName, registryClasses,counter, builder, pre + fieldName + "."));
}
}
return formDataList;
}
}

View File

@ -10,7 +10,7 @@ import com.power.doc.constants.DocTags;
import com.power.doc.model.ApiMethodDoc;
import com.power.doc.model.ApiReturn;
import com.power.doc.model.CustomRespField;
import com.power.doc.model.postman.request.body.FormData;
import com.power.doc.model.FormData;
import com.power.doc.utils.*;
import com.thoughtworks.qdox.model.*;

View File

@ -1,5 +1,7 @@
package com.power.doc.model;
import com.power.doc.model.request.ApiRequestExample;
import java.io.Serializable;
import java.util.List;
@ -43,10 +45,20 @@ public class ApiMethodDoc implements Serializable {
private String detail;
/**
* controller method url
* server url
*/
private String serverUrl;
/**
* controller method url contains server
*/
private String url;
/**
* controller path
*/
private String path;
/**
* http request type
*/
@ -84,6 +96,11 @@ public class ApiMethodDoc implements Serializable {
*/
private String requestUsage;
/**
* request example detail
*/
private ApiRequestExample requestExample;
/**
* http request-example requestUrlParam
*/
@ -239,4 +256,28 @@ public class ApiMethodDoc implements Serializable {
public void setAuthor(String author) {
this.author = author;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getServerUrl() {
return serverUrl;
}
public void setServerUrl(String serverUrl) {
this.serverUrl = serverUrl;
}
public ApiRequestExample getRequestExample() {
return requestExample;
}
public void setRequestExample(ApiRequestExample requestExample) {
this.requestExample = requestExample;
}
}

View File

@ -1,13 +1,14 @@
package com.power.doc.model.postman.request.body;
package com.power.doc.model;
/**
* @author xingzi 2019/12/21 20:20
*/
public class FormData {
private String key;
private String type;
private String src;
private String value;
private String key;
private String type;
private String desc;
private String src;
private String value;
public String getKey() {
return key;
@ -40,4 +41,12 @@ public class FormData {
public void setValue(String value) {
this.value = value;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}

View File

@ -1,6 +1,8 @@
package com.power.doc.model.postman.request.body;
import com.power.doc.model.FormData;
import java.util.List;
/**

View File

@ -1,6 +1,6 @@
package com.power.doc.model;
package com.power.doc.model.request;
import com.power.doc.model.postman.request.body.FormData;
import com.power.doc.model.FormData;
import java.util.List;
@ -10,12 +10,24 @@ import java.util.List;
public class ApiRequestExample {
/**
* json body
*/
private String jsonBody;
/**
* example body
*/
private String exampleBody;
/**
* url
*/
private String url;
/**
* list of form data
*/
private List<FormData> formDataList;
private boolean json;

View File

@ -1,16 +1,23 @@
package com.power.doc.model;
package com.power.doc.model.request;
/**
* @author yu 2019/12/22.
*/
public class RequestMapping {
/**
* url
*/
private String url;
/**
* path
*/
private String shortUrl;
private String methodType;
private String mediaType;
private boolean postMethod;
public static RequestMapping builder(){
public static RequestMapping builder() {
return new RequestMapping();
}

View File

@ -14,6 +14,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static com.power.doc.constants.DocGlobalConstants.NO_COMMENTS_FOUND;
/**
* @author yu 2019/12/21.
*/
@ -38,6 +40,17 @@ public interface IDocBuildTemplate {
return builder.toString();
}
default String paramCommentResolve(String comment) {
if (StringUtil.isEmpty(comment)) {
comment = NO_COMMENTS_FOUND;
} else {
if (comment.contains("|")) {
comment = comment.substring(0, comment.indexOf("|"));
}
}
return comment;
}
default void handleApiDoc(JavaClass cls, List<ApiDoc> apiDocList, List<ApiMethodDoc> apiMethodDocs, int order, boolean isUseMD5) {
String controllerName = cls.getName();

View File

@ -1,29 +1,32 @@
package com.power.doc.template;
import com.power.common.util.JsonFormatUtil;
import com.power.common.util.RandomUtil;
import com.power.common.util.StringUtil;
import com.power.common.util.UrlUtil;
import com.power.doc.builder.ProjectDocConfigBuilder;
import com.power.doc.constants.*;
import com.power.doc.handler.SpringMVCRequestHeaderHandler;
import com.power.doc.handler.SpringMVCRequestMappingHandler;
import com.power.doc.helper.FormDataBuildHelper;
import com.power.doc.helper.JsonBuildHelper;
import com.power.doc.helper.ParamsBuildHelper;
import com.power.doc.model.*;
import com.power.doc.model.request.ApiRequestExample;
import com.power.doc.model.request.RequestMapping;
import com.power.doc.utils.DocClassUtil;
import com.power.doc.utils.DocUtil;
import com.thoughtworks.qdox.model.JavaAnnotation;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.JavaParameter;
import com.power.doc.utils.JavaClassUtil;
import com.thoughtworks.qdox.model.*;
import com.thoughtworks.qdox.model.expression.AnnotationValue;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.power.doc.constants.DocGlobalConstants.NO_COMMENTS_FOUND;
import static com.power.doc.constants.DocGlobalConstants.FILE_CONTENT_TYPE;
import static com.power.doc.constants.DocGlobalConstants.JSON_CONTENT_TYPE;
import static com.power.doc.constants.DocTags.IGNORE;
import static com.power.doc.helper.JsonBuildHelper.JSON_GET_PARAMS;
import static com.power.doc.helper.JsonBuildHelper.JSON_REQUEST_BODY;
/**
* @author yu 2019/12/21.
@ -114,23 +117,17 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate {
}
apiMethodDoc.setType(requestMapping.getMethodType());
apiMethodDoc.setUrl(requestMapping.getUrl());
apiMethodDoc.setServerUrl(projectBuilder.getServerUrl());
apiMethodDoc.setPath(requestMapping.getShortUrl());
// build request params
List<ApiParam> requestParams = requestParams(method, DocTags.PARAM, cls.getCanonicalName(), projectBuilder);
List<ApiParam> requestParams = requestParams(method, DocTags.PARAM, projectBuilder);
apiMethodDoc.setRequestParams(requestParams);
// build request json
HashMap<String, String> requestJson = JsonBuildHelper.buildReqJson(method, apiMethodDoc, requestMapping.isPostMethod(), projectBuilder);
//build request urlParams json
apiMethodDoc.setRequestUrlParam(requestJson.get(JsonBuildHelper.JSON_GET_PARAMS));
//build request body json
apiMethodDoc.setRequestBody(requestJson.get(JsonBuildHelper.JSON_REQUEST_BODY));
//build request-example json
if (requestJson.get(JSON_REQUEST_BODY) != null) {
apiMethodDoc.setRequestUsage(requestJson.get(JSON_GET_PARAMS) + "\n\n" + requestJson.get(JSON_REQUEST_BODY));
} else {
apiMethodDoc.setRequestUsage(requestJson.get(JSON_GET_PARAMS));
}
ApiRequestExample requestExample = buildReqJson(method, apiMethodDoc, requestMapping.isPostMethod(), projectBuilder);
String requestJson = requestExample.getExampleBody();
// set request example detail
apiMethodDoc.setRequestExample(requestExample);
apiMethodDoc.setRequestUsage(requestJson);
// build response usage
apiMethodDoc.setResponseUsage(JsonBuildHelper.buildReturnJson(method, projectBuilder));
// build response params
@ -139,9 +136,7 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate {
List<ApiReqHeader> allApiReqHeaders;
if (this.headers != null) {
allApiReqHeaders = Stream.of(this.headers, apiReqHeaders)
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
.flatMap(Collection::stream).distinct().collect(Collectors.toList());
} else {
allApiReqHeaders = apiReqHeaders;
}
@ -154,17 +149,186 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate {
return methodDocList;
}
/**
* Get tag
*
* @param javaMethod The JavaMethod method
* @param tagName The doc tag name
* @param className The class name
* @return String
*/
private List<ApiParam> requestParams(final JavaMethod javaMethod, final String tagName, final String className, ProjectDocConfigBuilder builder) {
private ApiRequestExample buildReqJson(JavaMethod method, ApiMethodDoc apiMethodDoc, Boolean isPostMethod, ProjectDocConfigBuilder configBuilder) {
List<JavaParameter> parameterList = method.getParameters();
if (parameterList.size() < 1) {
return ApiRequestExample.builder().setJsonBody(apiMethodDoc.getUrl());
}
Map<String, String> pathParamsMap = new LinkedHashMap<>();
Map<String, String> paramsComments = DocUtil.getParamsComments(method, DocTags.PARAM, null);
List<String> springMvcRequestAnnotations = SpringMvcRequestAnnotationsEnum.listSpringMvcRequestAnnotations();
List<FormData> formDataList = new ArrayList<>();
ApiRequestExample requestExample = ApiRequestExample.builder();
for (JavaParameter parameter : parameterList) {
JavaType javaType = parameter.getType();
String simpleTypeName = javaType.getValue();
String gicTypeName = javaType.getGenericCanonicalName();
String typeName = javaType.getFullyQualifiedName();
JavaClass javaClass = configBuilder.getJavaProjectBuilder().getClassByName(typeName);
String[] globGicName = DocClassUtil.getSimpleGicName(gicTypeName);
String paramName = parameter.getName();
if (DocClassUtil.isMvcIgnoreParams(typeName)) {
continue;
}
String comment = this.paramCommentResolve(paramsComments.get(paramName));
String mockValue = "";
if (DocClassUtil.isPrimitive(simpleTypeName)) {
mockValue = paramsComments.get(paramName);
if (Objects.nonNull(mockValue) && mockValue.contains("|")) {
mockValue = mockValue.substring(mockValue.lastIndexOf("|") + 1, mockValue.length());
} else {
mockValue = "";
}
if (StringUtil.isEmpty(mockValue)) {
mockValue = DocUtil.getValByTypeAndFieldName(simpleTypeName, paramName, true);
}
}
List<JavaAnnotation> annotations = parameter.getAnnotations();
boolean paramAdded = false;
for (JavaAnnotation annotation : annotations) {
String annotationName = annotation.getType().getSimpleName();
String fullName = annotation.getType().getSimpleName();
if (!springMvcRequestAnnotations.contains(fullName) || paramAdded) {
continue;
}
if (SpringMvcAnnotations.REQUEST_HERDER.equals(annotationName)) {
continue;
}
AnnotationValue annotationDefaultVal = annotation.getProperty(DocAnnotationConstants.DEFAULT_VALUE_PROP);
if (null != annotationDefaultVal) {
mockValue = StringUtil.removeQuotes(annotationDefaultVal.toString());
}
AnnotationValue annotationValue = annotation.getProperty(DocAnnotationConstants.VALUE_PROP);
if (null != annotationValue) {
paramName = StringUtil.removeQuotes(annotationValue.toString());
}
AnnotationValue annotationOfName = annotation.getProperty(DocAnnotationConstants.NAME_PROP);
if (null != annotationOfName) {
paramName = StringUtil.removeQuotes(annotationOfName.toString());
}
if (SpringMvcAnnotations.REQUEST_BODY.equals(annotationName) || DocGlobalConstants.REQUEST_BODY_FULLY.equals(annotationName)) {
apiMethodDoc.setContentType(JSON_CONTENT_TYPE);
if (DocClassUtil.isPrimitive(simpleTypeName)) {
StringBuilder builder = new StringBuilder();
builder.append("{\"")
.append(paramName)
.append("\":")
.append(DocUtil.handleJsonStr(mockValue))
.append("}");
requestExample.setJsonBody(builder.toString()).setJson(true);
paramAdded = true;
} else {
String json = JsonBuildHelper.buildJson(typeName, gicTypeName, false, 0, new HashMap<>(), configBuilder);
requestExample.setJsonBody(json).setJson(true);
paramAdded = true;
}
} else if (SpringMvcAnnotations.PATH_VARIABLE.contains(annotationName)) {
if (javaClass.isEnum()) {
Object value = JavaClassUtil.getEnumValue(javaClass, Boolean.TRUE);
mockValue = StringUtil.removeQuotes(String.valueOf(value));
}
pathParamsMap.put(paramName, mockValue);
paramAdded = true;
}
}
if (paramAdded) {
continue;
}
//file upload
if (gicTypeName.contains(DocGlobalConstants.MULTIPART_FILE_FULLY)) {
apiMethodDoc.setContentType(FILE_CONTENT_TYPE);
FormData formData = new FormData();
formData.setKey(paramName);
formData.setType("file");
formData.setDesc(comment);
formData.setValue(mockValue);
formDataList.add(formData);
} else if (DocClassUtil.isPrimitive(typeName)) {
FormData formData = new FormData();
formData.setKey(paramName);
formData.setDesc(comment);
formData.setType("text");
formData.setValue(mockValue);
formDataList.add(formData);
} else if (DocClassUtil.isArray(typeName) || DocClassUtil.isCollection(typeName)) {
String gicName = globGicName[0];
if (DocClassUtil.isArray(gicName)) {
gicName = gicName.substring(0, gicName.indexOf("["));
}
if (!DocClassUtil.isPrimitive(gicName)) {
throw new RuntimeException("FormData can't support binding Collection<T> on method "
+ method.getName() + "Check it in " + method.getDeclaringClass().getCanonicalName());
}
FormData formData = new FormData();
formData.setKey(paramName);
if (!paramName.contains("[]")) {
formData.setKey(paramName + "[]");
}
formData.setDesc(comment);
formData.setType("text");
formData.setValue(RandomUtil.randomValueByType(gicName));
formDataList.add(formData);
} else if (javaClass.isEnum()) {
// do nothing
Object value = JavaClassUtil.getEnumValue(javaClass, Boolean.TRUE);
String strVal = StringUtil.removeQuotes(String.valueOf(value));
FormData formData = new FormData();
formData.setKey(paramName);
formData.setType("text");
formData.setDesc(comment);
formData.setValue(strVal);
formDataList.add(formData);
} else {
formDataList.addAll(FormDataBuildHelper.getFormData(gicTypeName, new HashMap<>(), 0, configBuilder, ""));
}
}
requestExample.setFormDataList(formDataList);
String[] paths = apiMethodDoc.getPath().split(";");
String path = paths[0];
String body;
String exampleBody;
String url;
if (isPostMethod) {
//for post
path = DocUtil.formatAndRemove(path, pathParamsMap);
body = UrlUtil.urlJoin("", DocUtil.formDataToMap(formDataList)).replace("?", "");
body = StringUtil.removeQuotes(body);
url = apiMethodDoc.getServerUrl() + "/" + path;
url = UrlUtil.simplifyUrl(url);
if (requestExample.isJson()) {
if (StringUtil.isNotEmpty(requestExample.getJsonBody())) {
exampleBody = "curl -X POST -H 'Content-Type: application/json; charset=utf-8' -i " + url + " --data \'" + JsonFormatUtil.formatJson(requestExample.getJsonBody()) + "\n'";
} else {
exampleBody = "curl -X POST -i " + url;
}
} else {
if (StringUtil.isNotEmpty(body)) {
exampleBody = "curl -X POST -i " + url + " --data \'" + body + "'";
} else {
exampleBody = "curl -X POST -i " + url;
}
}
requestExample.setExampleBody(exampleBody).setJsonBody(body).setUrl(url);
} else {
// for get
pathParamsMap.putAll(DocUtil.formDataToMap(formDataList));
path = DocUtil.formatAndRemove(path, pathParamsMap);
url = UrlUtil.urlJoin(path, pathParamsMap);
url = StringUtil.removeQuotes(url);
url = apiMethodDoc.getServerUrl() + "/" + url;
url = UrlUtil.simplifyUrl(url);
exampleBody = "curl -X GET -i \'" + url + "\'";
requestExample.setExampleBody(exampleBody).setJsonBody("").setUrl(url);
}
return requestExample;
}
private List<ApiParam> requestParams(final JavaMethod javaMethod, final String tagName, ProjectDocConfigBuilder builder) {
boolean isStrict = builder.getApiConfig().isStrict();
Map<String, CustomRespField> responseFieldMap = new HashMap<>();
String className = javaMethod.getDeclaringClass().getCanonicalName();
Map<String, String> paramTagMap = DocUtil.getParamsComments(javaMethod, tagName, className);
List<JavaParameter> parameterList = javaMethod.getParameters();
if (parameterList.size() < 1) {
@ -183,16 +347,14 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate {
if (DocClassUtil.isMvcIgnoreParams(typeName)) {
continue out;
}
JavaClass javaClass = builder.getJavaProjectBuilder().getClassByName(fullTypeName);
if (!paramTagMap.containsKey(paramName) && DocClassUtil.isPrimitive(fullTypeName) && isStrict) {
throw new RuntimeException("ERROR: Unable to find javadoc @param for actual param \""
+ paramName + "\" in method " + javaMethod.getName() + " from " + className);
}
String comment = paramTagMap.get(paramName);
if (StringUtil.isEmpty(comment)) {
comment = NO_COMMENTS_FOUND;
}
String comment = this.paramCommentResolve(paramTagMap.get(paramName));
//file upload
if (typeName.contains(DocGlobalConstants.MULTIPART_FILE_FULLY)) {
ApiParam param = ApiParam.of().setField(paramName).setType("file")
@ -327,12 +489,6 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate {
return paramList;
}
/**
* check controller
*
* @param cls
* @return
*/
private boolean checkController(JavaClass cls) {
List<JavaAnnotation> classAnnotations = cls.getAnnotations();
for (JavaAnnotation annotation : classAnnotations) {

View File

@ -7,7 +7,7 @@ import com.power.common.util.RandomUtil;
import com.power.common.util.StringUtil;
import com.power.doc.constants.DocAnnotationConstants;
import com.power.doc.constants.DocGlobalConstants;
import com.power.doc.model.postman.request.body.FormData;
import com.power.doc.model.FormData;
import com.thoughtworks.qdox.model.DocletTag;
import com.thoughtworks.qdox.model.JavaAnnotation;
import com.thoughtworks.qdox.model.JavaField;
@ -293,7 +293,7 @@ public class DocUtil {
String value = docletTag.getValue();
if (StringUtil.isEmpty(value) && StringUtil.isNotEmpty(className)) {
throw new RuntimeException("ERROR: #" + javaMethod.getName()
+ "() - bad @" + tagName + " javadoc from " + className + ", must be add comment if you use it.");
+ "() - bad @" + tagName + " javadoc from " + javaMethod.getDeclaringClass().getCanonicalName() + ", must be add comment if you use it.");
}
String pName;
String pValue;
@ -390,15 +390,13 @@ public class DocUtil {
}
public static Map<String, String> formDataToMap(List<FormData> formDataList) {
Map<String, String> map = formDataList.stream()
.collect(Collectors.toMap(
FormData::getKey,
FormData::getValue,
(u, v) -> {
throw new IllegalStateException(String.format("Duplicate key %s", u));
},
LinkedHashMap::new
));
return map;
Map<String, String> formDataMap = new LinkedHashMap<>();
for (FormData formData : formDataList) {
if ("file".equals(formData.getType())) {
continue;
}
formDataMap.put(formData.getKey(), formData.getValue());
}
return formDataMap;
}
}

View File

@ -2,7 +2,7 @@ package com.power.doc.utils;
import com.power.common.util.RandomUtil;
import com.power.doc.builder.ProjectDocConfigBuilder;
import com.power.doc.model.postman.request.body.FormData;
import com.power.doc.model.FormData;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaField;
@ -27,85 +27,4 @@ public class JavaFieldUtil {
}
return false;
}
public static List<FormData> getFormData(String className, ProjectDocConfigBuilder builder, String pre) {
String simpleName = DocClassUtil.getSimpleName(className);
String[] globGicName = DocClassUtil.getSimpleGicName(className);
JavaClass cls = builder.getJavaProjectBuilder().getClassByName(simpleName);
List<JavaField> fields = JavaClassUtil.getFields(cls, 0);
List<FormData> formDataList = new ArrayList<>();
if(DocClassUtil.isPrimitive(simpleName)){
FormData formData = new FormData();
formData.setKey(pre);
formData.setType("text");
formData.setValue(RandomUtil.randomValueByType(className));
formDataList.add(formData);
return formDataList;
}
if (DocClassUtil.isCollection(simpleName) || DocClassUtil.isArray(simpleName)) {
String gicName = globGicName[0];
if (DocClassUtil.isArray(gicName)) {
gicName = gicName.substring(0, gicName.indexOf("["));
}
formDataList.addAll(getFormData(gicName, builder, pre+"[]"));
}
int n = 0;
out:
for (JavaField field : fields) {
String fieldName = field.getName();
String subTypeName = field.getType().getFullyQualifiedName();
String fieldGicName = field.getType().getGenericCanonicalName();
JavaClass javaClass = builder.getJavaProjectBuilder().getClassByName(subTypeName);
if ("this$0".equals(fieldName) ||
"serialVersionUID".equals(fieldName) ||
DocClassUtil.isIgnoreFieldTypes(subTypeName)) {
continue;
}
String typeSimpleName = field.getType().getSimpleName();
if(DocClassUtil.isMap(subTypeName)){
continue;
}
if (DocClassUtil.isPrimitive(subTypeName)) {
String fieldValue = DocUtil.getValByTypeAndFieldName(typeSimpleName, field.getName());
FormData formData = new FormData();
formData.setKey(pre+fieldName);
formData.setType("text");
formData.setValue(fieldValue);
formDataList.add(formData);
} else if (javaClass.isEnum()) {
Object value = JavaClassUtil.getEnumValue(javaClass, Boolean.FALSE);
FormData formData = new FormData();
formData.setKey(pre+fieldName);
formData.setType("text");
formData.setValue(String.valueOf(value));
formDataList.add(formData);
} else if (DocClassUtil.isCollection(subTypeName)) {
String gNameTemp = field.getType().getGenericCanonicalName();
String[] gNameArr = DocClassUtil.getSimpleGicName(gNameTemp);
if (gNameArr.length == 0) {
continue out;
}
String gName = DocClassUtil.getSimpleGicName(gNameTemp)[0];
if (!DocClassUtil.isPrimitive(gName)) {
if (!simpleName.equals(gName) && !gName.equals(simpleName)) {
if (gName.length() == 1) {
int len = globGicName.length;
if (len > 0) {
String gicName = (n < len) ? globGicName[n] : globGicName[len - 1];
if (!DocClassUtil.isPrimitive(gicName) && !simpleName.equals(gicName)) {
formDataList.addAll(getFormData(gicName, builder,pre+fieldName+"[0]."));
}
}
} else {
formDataList.addAll(getFormData(gName,builder, pre+fieldName+"[0]."));
}
}
}
} else {
formDataList.addAll(getFormData(fieldGicName,builder, pre+fieldName+"."));
}
}
return formDataList;
}
}