diff --git a/solonhat-smartdoc/pom.xml b/solonhat-smartdoc/pom.xml
index 2a0392fab5ea36dad3cef314aeaecc67d7c69eb3..46686a02ce912afb5682d3f56221a75814f20464 100644
--- a/solonhat-smartdoc/pom.xml
+++ b/solonhat-smartdoc/pom.xml
@@ -13,12 +13,33 @@
solonhat-smartdoc
jar
-
+ solon smartdoc adapter
org.noear
solon
${solon.ver}
+
+
+
+ org.noear
+ solon-test
+ ${solon.ver}
+
+
+
+ org.noear
+ snack3
+ ${snack3.ver}
+
+
+
+
+
+ com.github.shalousun
+ smart-doc
+ 1.9.4
+
\ No newline at end of file
diff --git a/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/ChangeBodyFormat.java b/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/ChangeBodyFormat.java
new file mode 100644
index 0000000000000000000000000000000000000000..73e153bc09afd7fac25744dd0072d1980420b7e8
--- /dev/null
+++ b/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/ChangeBodyFormat.java
@@ -0,0 +1,25 @@
+package org.noear.solonhat.smartdoc;
+
+public class ChangeBodyFormat {
+
+ public static String urlParamToJson(String p){
+ if (p==null){
+ return "";
+ }
+ StringBuffer stringBuffer=new StringBuffer();
+ String[] split = p.split("&");
+ stringBuffer.append("{");
+ boolean b=false;
+ for (String s : split) {
+
+ String[] split1 = s.split("=");
+ stringBuffer.append("\""+split1[0]+"\":\""+(split1.length>1?split1[1]:"")+"\",");
+ b=true;
+ }
+ if (b) {
+ stringBuffer.deleteCharAt(stringBuffer.length() - 1);
+ }
+ stringBuffer.append("}");
+ return stringBuffer.toString();
+ }
+}
diff --git a/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/Constants.java b/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/Constants.java
new file mode 100644
index 0000000000000000000000000000000000000000..7568e0376f5d88e4a9c3ef1db00a69f31aad5403
--- /dev/null
+++ b/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/Constants.java
@@ -0,0 +1,20 @@
+package org.noear.solonhat.smartdoc;
+
+public class Constants {
+
+
+ public static final String REQUEST_MAPPING ="Mapping";
+ public static final String REQUEST_MAPPING_FULLY ="org.noear.solon.annotation.Mapping";
+
+ public static final String GET_MAPPING = "Get";
+ public static final String GET_MAPPING_FULLY ="org.noear.solon.annotation.Get" ;
+
+ public static final String POST_MAPPING ="Post" ;
+ public static final String POST_MAPPING_FULLY = "org.noear.solon.annotation.Post";
+ public static final String PUT_MAPPING = "Put";
+ public static final String PUT_MAPPING_FULLY = "org.noear.solon.annotation.Put";
+ public static final String PATCH_MAPPING = "Patch";
+ public static final String PATCH_MAPPING_FULLY = "org.noear.solon.annotation.Patch";
+ public static final String DELETE_MAPPING = "Delete";
+ public static final String DELETE_MAPPING_FULLY = "org.noear.solon.annotation.Delete";
+}
diff --git a/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/SolonDocBuildTemplate.java b/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/SolonDocBuildTemplate.java
new file mode 100644
index 0000000000000000000000000000000000000000..a05a666d4811576076a37740dba24445e85b22d6
--- /dev/null
+++ b/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/SolonDocBuildTemplate.java
@@ -0,0 +1,629 @@
+package org.noear.solonhat.smartdoc;
+
+import com.power.common.util.*;
+import com.power.doc.builder.ProjectDocConfigBuilder;
+import com.power.doc.constants.*;
+import com.power.doc.handler.SpringMVCRequestHeaderHandler;
+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.template.IDocBuildTemplate;
+import com.power.doc.utils.*;
+import com.thoughtworks.qdox.model.*;
+import com.thoughtworks.qdox.model.expression.AnnotationValue;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+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;
+
+
+/**
+ * @author yu 2019/12/21.
+ */
+public class SolonDocBuildTemplate implements IDocBuildTemplate {
+
+ private List headers;
+
+ /**
+ * api index
+ */
+ private final AtomicInteger atomicInteger = new AtomicInteger(1);
+
+ @Override
+ public List getApiData(ProjectDocConfigBuilder projectBuilder) {
+ ApiConfig apiConfig = projectBuilder.getApiConfig();
+ this.headers = apiConfig.getRequestHeaders();
+ List apiDocList = new ArrayList<>();
+ int order = 0;
+ Collection classes = projectBuilder.getJavaProjectBuilder().getClasses();
+ boolean setCustomOrder = false;
+ for (JavaClass cls : classes) {
+ String ignoreTag = JavaClassUtil.getClassTagsValue(cls, DocTags.IGNORE, Boolean.FALSE);
+ if (!checkController(cls) || StringUtil.isNotEmpty(ignoreTag)) {
+ continue;
+ }
+ if (StringUtil.isNotEmpty(apiConfig.getPackageFilters())) {
+ if (!DocUtil.isMatch(apiConfig.getPackageFilters(), cls.getCanonicalName())) {
+ continue;
+ }
+ }
+ String strOrder = JavaClassUtil.getClassTagsValue(cls, DocTags.ORDER, Boolean.TRUE);
+ order++;
+ if (ValidateUtil.isNonnegativeInteger(strOrder)) {
+ setCustomOrder = true;
+ order = Integer.parseInt(strOrder);
+ }
+ List apiMethodDocs = buildControllerMethod(cls, apiConfig, projectBuilder);
+ this.handleApiDoc(cls, apiDocList, apiMethodDocs, order, apiConfig.isMd5EncryptedHtmlName());
+ }
+ // sort
+ if (apiConfig.isSortByTitle()) {
+ Collections.sort(apiDocList);
+ } else if (setCustomOrder) {
+ // while set custom oder
+ return apiDocList.stream()
+ .sorted(Comparator.comparing(ApiDoc::getOrder))
+ .peek(p -> p.setOrder(atomicInteger.getAndAdd(1))).collect(Collectors.toList());
+ }
+ return apiDocList;
+ }
+
+ @Override
+ public ApiDoc getSingleApiData(ProjectDocConfigBuilder projectBuilder, String apiClassName) {
+ return null;
+ }
+
+ @Override
+ public boolean ignoreReturnObject(String typeName, List ignoreParams) {
+ if (JavaClassValidateUtil.isMvcIgnoreParams(typeName, ignoreParams)) {
+ return DocGlobalConstants.MODE_AND_VIEW_FULLY.equals(typeName);
+ }
+ return false;
+ }
+
+ private List buildControllerMethod(final JavaClass cls, ApiConfig apiConfig,
+ ProjectDocConfigBuilder projectBuilder) {
+ String clazName = cls.getCanonicalName();
+ boolean paramsDataToTree = projectBuilder.getApiConfig().isParamsDataToTree();
+ String classAuthor = JavaClassUtil.getClassTagsValue(cls, DocTags.AUTHOR, Boolean.TRUE);
+ List classAnnotations = cls.getAnnotations();
+ Map constantsMap = projectBuilder.getConstantsMap();
+ String baseUrl = "";
+ for (JavaAnnotation annotation : classAnnotations) {
+ String annotationName = annotation.getType().getValue();
+ if (Constants.REQUEST_MAPPING.equals(annotationName) ||
+ Constants.REQUEST_MAPPING_FULLY.equals(annotationName)) {
+ if (annotation.getNamedParameter("value") != null) {
+ baseUrl = StringUtil.removeQuotes(annotation.getNamedParameter("value").toString());
+ }
+ }
+ }
+ List methods = cls.getMethods();
+ List methodDocList = new ArrayList<>(methods.size());
+ int methodOrder = 0;
+ for (JavaMethod method : methods) {
+ if (method.isPrivate()) {
+ 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.setOrder(methodOrder);
+ apiMethodDoc.setName(method.getName());
+ apiMethodDoc.setDesc(method.getComment());
+ String methodUid = DocUtil.generateId(clazName + method.getName());
+ apiMethodDoc.setMethodId(methodUid);
+ String apiNoteValue = DocUtil.getNormalTagComments(method, DocTags.API_NOTE, cls.getName());
+ if (StringUtil.isEmpty(apiNoteValue)) {
+ apiNoteValue = method.getComment();
+ }
+ Map authorMap = DocUtil.getParamsComments(method, DocTags.AUTHOR, cls.getName());
+ String authorValue = String.join(", ", new ArrayList<>(authorMap.keySet()));
+ if (apiConfig.isShowAuthor() && StringUtil.isNotEmpty(authorValue)) {
+ apiMethodDoc.setAuthor(authorValue);
+ }
+ if (apiConfig.isShowAuthor() && StringUtil.isEmpty(authorValue)) {
+ apiMethodDoc.setAuthor(classAuthor);
+ }
+ apiMethodDoc.setDetail(apiNoteValue);
+ //handle request mapping
+ RequestMapping requestMapping = new SolonRequestMappingHandler()
+ .handle(projectBuilder.getServerUrl(), baseUrl, method, constantsMap);
+ //handle headers
+ List apiReqHeaders = new SpringMVCRequestHeaderHandler().handle(method);
+ apiMethodDoc.setRequestHeaders(apiReqHeaders);
+ if (Objects.nonNull(requestMapping)) {
+ if (null != method.getTagByName(IGNORE)) {
+ continue;
+ }
+ apiMethodDoc.setType(requestMapping.getMethodType());
+ apiMethodDoc.setUrl(requestMapping.getUrl());
+ apiMethodDoc.setServerUrl(projectBuilder.getServerUrl());
+ apiMethodDoc.setPath(requestMapping.getShortUrl());
+ apiMethodDoc.setDeprecated(requestMapping.isDeprecated());
+ // build request params
+ List requestParams = requestParams(method, projectBuilder);
+ if (paramsDataToTree) {
+ requestParams = ApiParamTreeUtil.apiParamToTree(requestParams);
+ }
+ apiMethodDoc.setRequestParams(requestParams);
+ List allApiReqHeaders;
+ if (this.headers != null) {
+ allApiReqHeaders = Stream.of(this.headers, apiReqHeaders)
+ .flatMap(Collection::stream).distinct().collect(Collectors.toList());
+ } else {
+ allApiReqHeaders = apiReqHeaders;
+ }
+ //reduce create in template
+ apiMethodDoc.setHeaders(this.createDocRenderHeaders(allApiReqHeaders, apiConfig.isAdoc()));
+ apiMethodDoc.setRequestHeaders(allApiReqHeaders);
+
+ // build request json
+ ApiRequestExample requestExample = buildReqJson(method, apiMethodDoc, requestMapping.getMethodType(),
+ projectBuilder);
+ String requestJson = requestExample.getExampleBody();
+ // set request example detail
+ apiMethodDoc.setRequestExample(requestExample);
+ apiMethodDoc.setRequestUsage(requestJson == null ? requestExample.getUrl() : requestJson);
+ // build response usage
+ apiMethodDoc.setResponseUsage(JsonBuildHelper.buildReturnJson(method, projectBuilder));
+ // build response params
+ List responseParams = buildReturnApiParams(method, projectBuilder);
+ if (paramsDataToTree) {
+ responseParams = ApiParamTreeUtil.apiParamToTree(responseParams);
+ }
+ apiMethodDoc.setResponseParams(responseParams);
+ methodDocList.add(apiMethodDoc);
+ }
+ }
+ return methodDocList;
+ }
+
+ private ApiRequestExample buildReqJson(JavaMethod method, ApiMethodDoc apiMethodDoc, String methodType,
+ ProjectDocConfigBuilder configBuilder) {
+ List parameterList = method.getParameters();
+ List reqHeaderList = apiMethodDoc.getRequestHeaders();
+
+ StringBuilder header = new StringBuilder(reqHeaderList.size());
+ for (ApiReqHeader reqHeader : reqHeaderList) {
+ header.append(" -H ").append("'").append(reqHeader.getName())
+ .append(":").append(reqHeader.getValue()).append("'");
+ }
+ if (parameterList.size() < 1) {
+ String format = String.format(DocGlobalConstants.CURL_REQUEST_TYPE, methodType,
+ header.toString(), apiMethodDoc.getUrl());
+ return ApiRequestExample.builder().setUrl(apiMethodDoc.getUrl()).setExampleBody(format);
+ }
+
+ Map constantsMap = configBuilder.getConstantsMap();
+ boolean requestFieldToUnderline = configBuilder.getApiConfig().isRequestFieldToUnderline();
+ Map replacementMap = configBuilder.getReplaceClassMap();
+ Map pathParamsMap = new LinkedHashMap<>();
+ Map paramsComments = DocUtil.getParamsComments(method, DocTags.PARAM, null);
+ List springMvcRequestAnnotations = SpringMvcRequestAnnotationsEnum.listSpringMvcRequestAnnotations();
+ List formDataList = new ArrayList<>();
+ ApiRequestExample requestExample = ApiRequestExample.builder();
+ out:
+ for (JavaParameter parameter : parameterList) {
+ JavaType javaType = parameter.getType();
+ String paramName = parameter.getName();
+ String typeName = javaType.getFullyQualifiedName();
+ String gicTypeName = javaType.getGenericCanonicalName();
+
+ String commentClass = paramsComments.get(paramName);
+ //ignore request params
+ if (Objects.nonNull(commentClass) && commentClass.contains(IGNORE)) {
+ continue;
+ }
+ String rewriteClassName = this.getRewriteClassName(replacementMap, typeName, commentClass);
+ // rewrite class
+ if (DocUtil.isClassName(rewriteClassName)) {
+ gicTypeName = rewriteClassName;
+ typeName = DocClassUtil.getSimpleName(rewriteClassName);
+ }
+ if (JavaClassValidateUtil.isMvcIgnoreParams(typeName, configBuilder.getApiConfig().getIgnoreRequestParams())) {
+ continue;
+ }
+ String simpleTypeName = javaType.getValue().toLowerCase();
+ typeName = DocClassUtil.rewriteRequestParam(typeName);
+ gicTypeName = DocClassUtil.rewriteRequestParam(gicTypeName);
+ JavaClass javaClass = configBuilder.getJavaProjectBuilder().getClassByName(typeName);
+ String[] globGicName = DocClassUtil.getSimpleGicName(gicTypeName);
+ String comment = this.paramCommentResolve(paramsComments.get(paramName));
+ String mockValue = "";
+ if ("POST".equals(methodType) ||"PUT".equals(methodType)) {
+ apiMethodDoc.setContentType(JSON_CONTENT_TYPE);
+ }
+ if (JavaClassValidateUtil.isPrimitive(typeName)) {
+ mockValue = paramsComments.get(paramName);
+ if (Objects.nonNull(mockValue) && mockValue.contains("|")) {
+ mockValue = mockValue.substring(mockValue.lastIndexOf("|") + 1);
+ } else {
+ mockValue = "";
+ }
+ if (StringUtil.isEmpty(mockValue)) {
+ mockValue = DocUtil.getValByTypeAndFieldName(simpleTypeName, paramName, Boolean.TRUE);
+ }
+ if ("POST".equals(methodType) ||"PUT".equals(methodType)){
+ apiMethodDoc.setContentType(JSON_CONTENT_TYPE);
+ StringBuilder builder ;
+ if (requestExample.getJsonBody()==null){
+ builder= new StringBuilder();
+ builder.append("{");
+ }else{
+ builder=new StringBuilder(requestExample.getJsonBody());
+ builder.delete(builder.length()-1,builder.length());
+ builder.append(",");
+ }
+
+ builder.append("\"")
+ .append(paramName)
+ .append("\":")
+ .append(DocUtil.handleJsonStr(mockValue))
+ .append("}");
+ requestExample.setJsonBody(JsonFormatUtil.formatJson(builder.toString())).setJson(true);
+
+ }
+ }
+ if (requestFieldToUnderline) {
+ paramName = StringUtil.camelToUnderline(paramName);
+ }
+ List annotations = parameter.getAnnotations();
+ boolean paramAdded = false;
+ for (JavaAnnotation annotation : annotations) {
+ String annotationName = annotation.getType().getValue();
+ String fullName = annotation.getType().getSimpleName();
+ if (!springMvcRequestAnnotations.contains(fullName) || paramAdded) {
+ continue;
+ }
+ if (SpringMvcAnnotations.REQUEST_HERDER.equals(annotationName)) {
+ continue out;
+ }
+ AnnotationValue annotationDefaultVal = annotation.getProperty(DocAnnotationConstants.DEFAULT_VALUE_PROP);
+ if (null != annotationDefaultVal) {
+ mockValue = StringUtil.removeQuotes(annotationDefaultVal.toString());
+ }
+ paramName = getParamName(paramName, annotation);
+ for (Map.Entry entry : constantsMap.entrySet()) {
+ String key = entry.getKey();
+ String value = entry.getValue();
+ // replace param
+ if (paramName.contains(key)) {
+ paramName = paramName.replace(key, value);
+ }
+ // replace mockValue
+ if (mockValue.contains(entry.getKey())) {
+ mockValue = mockValue.replace(key, value);
+ }
+ }
+ if (Constants.POST_MAPPING.equals(annotationName) ||Constants.POST_MAPPING.equals(annotationName)) {
+ apiMethodDoc.setContentType(JSON_CONTENT_TYPE);
+ if (JavaClassValidateUtil.isPrimitive(simpleTypeName)) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("{\"")
+ .append(paramName)
+ .append("\":")
+ .append(DocUtil.handleJsonStr(mockValue))
+ .append("}");
+ requestExample.setJsonBody(JsonFormatUtil.formatJson(builder.toString())).setJson(true);
+ } else {
+ String json = JsonBuildHelper.buildJson(typeName, gicTypeName, Boolean.FALSE, 0, new HashMap<>(), configBuilder);
+ requestExample.setJsonBody(JsonFormatUtil.formatJson(json)).setJson(true);
+ }
+ paramAdded = true;
+ } else if (Constants.GET_MAPPING.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 (JavaClassValidateUtil.isPrimitive(typeName)) {
+ FormData formData = new FormData();
+ formData.setKey(paramName);
+ formData.setDesc(comment);
+ formData.setType("text");
+ formData.setValue(mockValue);
+ formDataList.add(formData);
+ } else if (JavaClassValidateUtil.isArray(typeName) || JavaClassValidateUtil.isCollection(typeName)) {
+ String gicName = globGicName[0];
+ if (JavaClassValidateUtil.isArray(gicName)) {
+ gicName = gicName.substring(0, gicName.indexOf("["));
+ }
+ if (!JavaClassValidateUtil.isPrimitive(gicName)) {
+ throw new RuntimeException("Spring MVC can't support binding Collection 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, DocGlobalConstants.EMPTY));
+ }
+ }
+ requestExample.setFormDataList(formDataList);
+ String[] paths = apiMethodDoc.getPath().split(";");
+ String path = paths[0];
+ String body;
+ String exampleBody;
+ String url;
+ if (Methods.POST.getValue()
+ .equals(methodType) || Methods.PUT.getValue()
+ .equals(methodType)) {
+ //for post put
+
+ path = DocUtil.formatAndRemove(path, pathParamsMap);
+ body = UrlUtil.urlJoin(DocGlobalConstants.EMPTY, DocUtil.formDataToMap(formDataList))
+ .replace("?", DocGlobalConstants.EMPTY);
+ body = StringUtil.removeQuotes(body);
+ url = apiMethodDoc.getServerUrl() + "/" + path;
+ url = UrlUtil.simplifyUrl(url);
+ String format = String.format(DocGlobalConstants.CURL_REQUEST_TYPE, methodType, header.toString(), url);
+ format=format.replace("-X ANY","");
+ if (requestExample.isJson()) {
+ if (StringUtil.isNotEmpty(requestExample.getJsonBody())) {
+ exampleBody = String.format(DocGlobalConstants.CURL_POST_PUT_JSON, methodType, header.toString(), url,
+ requestExample.getJsonBody());
+ } else {
+ exampleBody = format;
+ }
+ } else {
+ if (StringUtil.isNotEmpty(body)) {
+// exampleBody = String.format(DocGlobalConstants.CURL_REQUEST_TYPE_DATA, methodType, header.toString(), url, body);
+ exampleBody = String.format(DocGlobalConstants.CURL_POST_PUT_JSON, methodType, header.toString(), url,
+ ChangeBodyFormat.urlParamToJson(body));
+// exampleBody+="\r\n OR \r\n"+exampleBody2;
+ } else {
+ exampleBody = format;
+ }
+ }
+ requestExample.setExampleBody(exampleBody).setUrl(url);
+ } else {
+ // for get delete
+ 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 = String.format(DocGlobalConstants.CURL_REQUEST_TYPE, methodType, header.toString(), url);
+ exampleBody=exampleBody.replace("-X ANY","");
+ requestExample.setExampleBody(exampleBody)
+ .setJsonBody(DocGlobalConstants.EMPTY)
+ .setUrl(url);
+ }
+ return requestExample;
+ }
+
+ private List requestParams(final JavaMethod javaMethod, ProjectDocConfigBuilder builder) {
+ boolean isStrict = builder.getApiConfig().isStrict();
+ Map responseFieldMap = new HashMap<>();
+ String className = javaMethod.getDeclaringClass().getCanonicalName();
+ Map replacementMap = builder.getReplaceClassMap();
+ Map paramTagMap = DocUtil.getParamsComments(javaMethod, DocTags.PARAM, className);
+ List parameterList = javaMethod.getParameters();
+ if (parameterList.size() < 1) {
+ return null;
+ }
+ Map constantsMap = builder.getConstantsMap();
+ boolean requestFieldToUnderline = builder.getApiConfig().isRequestFieldToUnderline();
+ List paramList = new ArrayList<>();
+ int requestBodyCounter = 0;
+ out:
+ for (JavaParameter parameter : parameterList) {
+ String paramName = parameter.getName();
+ String typeName = parameter.getType().getGenericCanonicalName();
+ String simpleName = parameter.getType().getValue().toLowerCase();
+ String fullTypeName = parameter.getType().getFullyQualifiedName();
+
+ String commentClass = paramTagMap.get(paramName);
+ String rewriteClassName = getRewriteClassName(replacementMap, fullTypeName, commentClass);
+ // rewrite class
+ if (DocUtil.isClassName(rewriteClassName)) {
+ typeName = rewriteClassName;
+ fullTypeName = DocClassUtil.getSimpleName(rewriteClassName);
+ }
+ if (JavaClassValidateUtil.isMvcIgnoreParams(typeName, builder.getApiConfig().getIgnoreRequestParams())) {
+ continue;
+ }
+ fullTypeName = DocClassUtil.rewriteRequestParam(fullTypeName);
+ typeName = DocClassUtil.rewriteRequestParam(typeName);
+ if (!paramTagMap.containsKey(paramName) && JavaClassValidateUtil.isPrimitive(fullTypeName) && isStrict) {
+ throw new RuntimeException("ERROR: Unable to find javadoc @param for actual param \""
+ + paramName + "\" in method " + javaMethod.getName() + " from " + className);
+ }
+ String comment = this.paramCommentResolve(paramTagMap.get(paramName));
+ if (requestFieldToUnderline) {
+ paramName = StringUtil.camelToUnderline(paramName);
+ }
+ //file upload
+ if (typeName.contains(DocGlobalConstants.MULTIPART_FILE_FULLY)) {
+ ApiParam param = ApiParam.of().setField(paramName).setType("file")
+ .setId(paramList.size() + 1)
+ .setDesc(comment).setRequired(true).setVersion(DocGlobalConstants.DEFAULT_VERSION);
+ paramList.add(param);
+ continue;
+ }
+ JavaClass javaClass = builder.getJavaProjectBuilder().getClassByName(fullTypeName);
+ List annotations = parameter.getAnnotations();
+ List groupClasses = JavaClassUtil.getParamGroupJavaClass(annotations);
+ String strRequired = "true";
+ boolean isPathVariable = false;
+ for (JavaAnnotation annotation : annotations) {
+ String annotationName = annotation.getType().getValue();
+ if (SpringMvcAnnotations.REQUEST_HERDER.equals(annotationName)) {
+ continue out;
+ }
+ if (SpringMvcAnnotations.REQUEST_PARAM.equals(annotationName) ||
+ DocAnnotationConstants.SHORT_PATH_VARIABLE.equals(annotationName)) {
+ if (DocAnnotationConstants.SHORT_PATH_VARIABLE.equals(annotationName)) {
+ isPathVariable = true;
+ }
+ paramName = getParamName(paramName, annotation);
+ for (Map.Entry entry : constantsMap.entrySet()) {
+ String key = entry.getKey();
+ String value = entry.getValue();
+ if (paramName.contains(key)) {
+ paramName = paramName.replace(key, value);
+ }
+ }
+
+ AnnotationValue annotationRequired = annotation.getProperty(DocAnnotationConstants.REQUIRED_PROP);
+ if (null != annotationRequired) {
+ strRequired = annotationRequired.toString();
+ }
+ }
+ if (SpringMvcAnnotations.REQUEST_BODY.equals(annotationName)) {
+ if (requestBodyCounter > 0) {
+ throw new RuntimeException("You have use @RequestBody Passing multiple variables for method "
+ + javaMethod.getName() + " in " + className + ",@RequestBody annotation could only bind one variables.");
+ }
+ requestBodyCounter++;
+ }
+ }
+ boolean required = Boolean.parseBoolean(strRequired);
+ if (isPathVariable) {
+ comment = comment + " (This is path param)";
+ }
+ if (JavaClassValidateUtil.isCollection(fullTypeName) || JavaClassValidateUtil.isArray(fullTypeName)) {
+ String[] gicNameArr = DocClassUtil.getSimpleGicName(typeName);
+ String gicName = gicNameArr[0];
+ if (JavaClassValidateUtil.isArray(gicName)) {
+ gicName = gicName.substring(0, gicName.indexOf("["));
+ }
+ if (JavaClassValidateUtil.isPrimitive(gicName)) {
+ String shortSimple = DocClassUtil.processTypeNameForParams(gicName);
+ ApiParam param = ApiParam.of().setField(paramName).setDesc(comment + ",[array of " + shortSimple + "]")
+ .setRequired(required)
+ .setPathParams(isPathVariable)
+ .setId(paramList.size() + 1)
+ .setType("array");
+ paramList.add(param);
+ } else {
+ if (requestBodyCounter > 0) {
+ //for json
+ paramList.addAll(ParamsBuildHelper.buildParams(gicNameArr[0], DocGlobalConstants.EMPTY, 0,
+ "true", responseFieldMap, Boolean.FALSE, new HashMap<>(), builder, groupClasses, 0));
+ } else {
+ throw new RuntimeException("Spring MVC can't support binding Collection on method "
+ + javaMethod.getName() + "Check it in " + javaMethod.getDeclaringClass().getCanonicalName());
+ }
+ }
+ } else if (JavaClassValidateUtil.isPrimitive(fullTypeName)) {
+ ApiParam param = ApiParam.of().setField(paramName)
+ .setType(DocClassUtil.processTypeNameForParams(simpleName))
+ .setId(paramList.size() + 1)
+ .setPathParams(isPathVariable)
+ .setDesc(comment).setRequired(required).setVersion(DocGlobalConstants.DEFAULT_VERSION);
+ paramList.add(param);
+ } else if (JavaClassValidateUtil.isMap(fullTypeName)) {
+ if (DocGlobalConstants.JAVA_MAP_FULLY.equals(typeName)) {
+ ApiParam apiParam = ApiParam.of().setField(paramName).setType("map")
+ .setId(paramList.size() + 1)
+ .setPathParams(isPathVariable)
+ .setDesc(comment).setRequired(required).setVersion(DocGlobalConstants.DEFAULT_VERSION);
+ paramList.add(apiParam);
+ continue;
+ }
+ String[] gicNameArr = DocClassUtil.getSimpleGicName(typeName);
+ 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()) {
+
+ String o = JavaClassUtil.getEnumParams(javaClass);
+ ApiParam param = ApiParam.of().setField(paramName)
+ .setId(paramList.size() + 1)
+ .setPathParams(isPathVariable)
+ .setType("enum").setDesc(StringUtil.removeQuotes(o)).setRequired(required).setVersion(DocGlobalConstants.DEFAULT_VERSION);
+ paramList.add(param);
+ } else {
+ paramList.addAll(ParamsBuildHelper.buildParams(typeName, DocGlobalConstants.EMPTY, 0, "true", responseFieldMap, Boolean.FALSE, new HashMap<>(), builder, groupClasses, 0));
+ }
+ }
+ return paramList;
+ }
+
+ private String getParamName(String paramName, JavaAnnotation annotation) {
+ 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());
+ }
+ return paramName;
+ }
+
+ private boolean checkController(JavaClass cls) {
+ List classAnnotations = cls.getAnnotations();
+ for (JavaAnnotation annotation : classAnnotations) {
+ String name = annotation.getType().getValue();
+ if (SpringMvcAnnotations.CONTROLLER.equals(name) || SpringMvcAnnotations.REST_CONTROLLER.equals(name)) {
+ return true;
+ }
+ }
+ // use custom doc tag to support Feign.
+ List docletTags = cls.getTags();
+ for (DocletTag docletTag : docletTags) {
+ String value = docletTag.getName();
+ if (DocTags.REST_API.equals(value)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private String getRewriteClassName(Map replacementMap, String fullTypeName, String commentClass) {
+ String rewriteClassName;
+ if (Objects.nonNull(commentClass) && !DocGlobalConstants.NO_COMMENTS_FOUND.equals(commentClass)) {
+ String[] comments = commentClass.split("\\|");
+ rewriteClassName = comments[comments.length - 1];
+ } else {
+ rewriteClassName = replacementMap.get(fullTypeName);
+ }
+ return rewriteClassName;
+ }
+}
diff --git a/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/SolonHtmlApiDocBuilder.java b/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/SolonHtmlApiDocBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..a9319af626d7d0b46be508790243d27df7f4e375
--- /dev/null
+++ b/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/SolonHtmlApiDocBuilder.java
@@ -0,0 +1,215 @@
+/*
+ * 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 org.noear.solonhat.smartdoc;
+
+import com.power.common.util.CollectionUtil;
+import com.power.common.util.DateTimeUtil;
+import com.power.common.util.FileUtil;
+import com.power.doc.builder.DocBuilderTemplate;
+import com.power.doc.builder.ProjectDocConfigBuilder;
+import com.power.doc.constants.DocGlobalConstants;
+import com.power.doc.constants.DocLanguage;
+import com.power.doc.constants.TemplateVariable;
+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.utils.BeetlTemplateUtil;
+import com.power.doc.utils.MarkDownUtil;
+import com.thoughtworks.qdox.JavaProjectBuilder;
+import org.apache.commons.lang3.StringUtils;
+import org.beetl.core.Template;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static com.power.doc.constants.DocGlobalConstants.*;
+
+/**
+ * @author yu 2019/9/20.
+ * @since 1.7+
+ */
+public class SolonHtmlApiDocBuilder {
+
+ private static long now = System.currentTimeMillis();
+
+ private static final String STR_TIME = DateTimeUtil.long2Str(now, DateTimeUtil.DATE_FORMAT_SECOND);
+
+ private static String INDEX_HTML = "index.html";
+
+
+ /**
+ * build controller api
+ *
+ * @param config config
+ */
+ public static void buildApiDoc(ApiConfig config) {
+ JavaProjectBuilder javaProjectBuilder = new JavaProjectBuilder();
+ buildApiDoc(config, javaProjectBuilder);
+ }
+
+ /**
+ * Only for smart-doc maven plugin and gradle plugin.
+ *
+ * @param config ApiConfig
+ * @param javaProjectBuilder ProjectDocConfigBuilder
+ */
+ public static void buildApiDoc(ApiConfig config, JavaProjectBuilder javaProjectBuilder) {
+ DocBuilderTemplate builderTemplate = new DocBuilderTemplate();
+ builderTemplate.checkAndInit(config);
+ config.setParamsDataToTree(false);
+ ProjectDocConfigBuilder configBuilder = new ProjectDocConfigBuilder(config, javaProjectBuilder);
+ IDocBuildTemplate docBuildTemplate = new SolonDocBuildTemplate();
+ List 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);
+ if (StringUtils.isNotEmpty(config.getAllInOneDocFileName())) {
+ INDEX_HTML = config.getAllInOneDocFileName();
+ }
+ builderTemplate.buildAllInOne(apiDocList, config, javaProjectBuilder, ALL_IN_ONE_HTML_TPL, INDEX_HTML);
+ } else {
+ List apiDocDictList = builderTemplate.buildDictionary(config, javaProjectBuilder);
+ buildIndex(apiDocList, config);
+ copyCss(config.getOutPath());
+ buildDoc(apiDocList, config);
+ buildErrorCodeDoc(config.getErrorCodes(), config.getOutPath());
+ buildDictionary(apiDocDictList, config.getOutPath());
+ }
+ }
+
+ private static void copyCss(String outPath) {
+ Template indexCssTemplate = BeetlTemplateUtil.getByName(INDEX_CSS_TPL);
+ Template mdCssTemplate = BeetlTemplateUtil.getByName(MARKDOWN_CSS_TPL);
+ FileUtil.nioWriteFile(indexCssTemplate.render(), outPath + FILE_SEPARATOR + INDEX_CSS_TPL);
+ FileUtil.nioWriteFile(mdCssTemplate.render(), outPath + FILE_SEPARATOR + MARKDOWN_CSS_TPL);
+ }
+
+ /**
+ * build api.html
+ *
+ * @param apiDocList list of api doc
+ * @param config ApiConfig
+ */
+ private static void buildIndex(List apiDocList, ApiConfig config) {
+ FileUtil.mkdirs(config.getOutPath());
+ Template indexTemplate = BeetlTemplateUtil.getByName(INDEX_TPL);
+ if (CollectionUtil.isEmpty(apiDocList)) {
+ return;
+ }
+ ApiDoc doc = apiDocList.get(0);
+ String homePage = doc.getAlias();
+ indexTemplate.binding(TemplateVariable.HOME_PAGE.getVariable(), homePage);
+ indexTemplate.binding(TemplateVariable.VERSION.getVariable(), now);
+ indexTemplate.binding(TemplateVariable.API_DOC_LIST.getVariable(), apiDocList);
+ indexTemplate.binding(TemplateVariable.ERROR_CODE_LIST.getVariable(), config.getErrorCodes());
+ indexTemplate.binding(TemplateVariable.DICT_LIST.getVariable(), config.getDataDictionaries());
+ if (CollectionUtil.isEmpty(config.getErrorCodes())) {
+ indexTemplate.binding(TemplateVariable.DICT_ORDER.getVariable(), apiDocList.size() + 1);
+ } else {
+ indexTemplate.binding(TemplateVariable.DICT_ORDER.getVariable(), apiDocList.size() + 2);
+ }
+ if (null != config.getLanguage()) {
+ if (DocLanguage.CHINESE.code.equals(config.getLanguage().getCode())) {
+ indexTemplate.binding(TemplateVariable.ERROR_LIST_TITLE.getVariable(), ERROR_CODE_LIST_CN_TITLE);
+ indexTemplate.binding(TemplateVariable.DICT_LIST_TITLE.getVariable(), DocGlobalConstants.DICT_CN_TITLE);
+ } else {
+ indexTemplate.binding(TemplateVariable.ERROR_LIST_TITLE.getVariable(), ERROR_CODE_LIST_EN_TITLE);
+ indexTemplate.binding(TemplateVariable.DICT_LIST_TITLE.getVariable(), DocGlobalConstants.DICT_EN_TITLE);
+ }
+ } else {
+ indexTemplate.binding(TemplateVariable.ERROR_LIST_TITLE.getVariable(), ERROR_CODE_LIST_CN_TITLE);
+ indexTemplate.binding(TemplateVariable.DICT_LIST_TITLE.getVariable(), DocGlobalConstants.DICT_CN_TITLE);
+ }
+ FileUtil.nioWriteFile(indexTemplate.render(), config.getOutPath() + FILE_SEPARATOR + "api.html");
+ }
+
+ /**
+ * build ever controller api
+ *
+ * @param apiDocList list of api doc
+ * @param config ApiConfig
+ */
+ private static void buildDoc(List apiDocList, ApiConfig config) {
+ FileUtil.mkdirs(config.getOutPath());
+ Template htmlApiDoc;
+ for (ApiDoc doc : apiDocList) {
+ Template apiTemplate = BeetlTemplateUtil.getByName(API_DOC_MD_TPL);
+ apiTemplate.binding(TemplateVariable.REQUEST_EXAMPLE.getVariable(), config.isRequestExample());
+ apiTemplate.binding(TemplateVariable.RESPONSE_EXAMPLE.getVariable(), config.isResponseExample());
+ apiTemplate.binding(TemplateVariable.DESC.getVariable(), doc.getDesc());
+ apiTemplate.binding(TemplateVariable.NAME.getVariable(), doc.getName());
+ apiTemplate.binding(TemplateVariable.LIST.getVariable(), doc.getList());//类名
+ Map templateVariables = new HashMap<>();
+ templateVariables.put(TemplateVariable.TITLE.getVariable(), doc.getDesc());
+ htmlApiDoc = initTemplate(apiTemplate, HTML_API_DOC_TPL, templateVariables);
+ FileUtil.nioWriteFile(htmlApiDoc.render(), config.getOutPath() + FILE_SEPARATOR + doc.getAlias() + ".html");
+ }
+ }
+
+ /**
+ * build error_code html
+ *
+ * @param errorCodeList list of error code
+ * @param outPath
+ */
+ private static void buildErrorCodeDoc(List errorCodeList, String outPath) {
+ if (CollectionUtil.isNotEmpty(errorCodeList)) {
+ Template errorTemplate = BeetlTemplateUtil.getByName(ERROR_CODE_LIST_MD_TPL);
+ errorTemplate.binding(TemplateVariable.LIST.getVariable(), errorCodeList);
+ Map templateVariables = new HashMap<>();
+ templateVariables.put(TemplateVariable.TITLE.getVariable(), ERROR_CODE_LIST_EN_TITLE);
+ Template errorCodeDoc = initTemplate(errorTemplate, HTML_API_DOC_TPL, templateVariables);
+ FileUtil.nioWriteFile(errorCodeDoc.render(), outPath + FILE_SEPARATOR + "error_code.html");
+ }
+ }
+
+ /**
+ * build dictionary
+ *
+ * @param apiDocDictList dictionary list
+ * @param outPath
+ */
+ private static void buildDictionary(List apiDocDictList, String outPath) {
+ if (CollectionUtil.isNotEmpty(apiDocDictList)) {
+ Template template = BeetlTemplateUtil.getByName(DICT_LIST_MD_TPL);
+ template.binding(TemplateVariable.DICT_LIST.getVariable(), apiDocDictList);
+ Map templateVariables = new HashMap<>();
+ templateVariables.put(TemplateVariable.TITLE.getVariable(), DICT_EN_TITLE);
+ Template dictTpl = initTemplate(template, HTML_API_DOC_TPL, templateVariables);
+ FileUtil.nioWriteFile(dictTpl.render(), outPath + FILE_SEPARATOR + "dict.html");
+ }
+ }
+
+ private static Template initTemplate(Template template, String templateName, Map templateVariables) {
+ String errorHtml = MarkDownUtil.toHtml(template.render());
+ Template template1 = BeetlTemplateUtil.getByName(templateName);
+ template1.binding(TemplateVariable.VERSION.getVariable(), now);
+ template1.binding(TemplateVariable.HTML.getVariable(), errorHtml);
+ template1.binding(TemplateVariable.CREATE_TIME.getVariable(), STR_TIME);
+ template1.binding(templateVariables);
+ return template1;
+ }
+}
diff --git a/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/SolonRequestMappingHandler.java b/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/SolonRequestMappingHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..dbd31b070d0a6e466d0be6382f6905712be1d506
--- /dev/null
+++ b/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/SolonRequestMappingHandler.java
@@ -0,0 +1,120 @@
+/*
+ * 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 org.noear.solonhat.smartdoc;
+
+import com.power.common.util.StringUtil;
+import com.power.common.util.UrlUtil;
+import com.power.doc.constants.DocAnnotationConstants;
+import com.power.doc.constants.Methods;
+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;
+import com.thoughtworks.qdox.model.JavaMethod;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static com.power.doc.constants.DocTags.IGNORE;
+
+/**
+ * @author 馒头虫 2021/11/16.
+ */
+public class SolonRequestMappingHandler {
+
+ /**
+ * handle spring request mapping
+ *
+ * @param serverUrl server url
+ * @param controllerBaseUrl spring mvc controller base url
+ * @param method JavaMethod
+ * @param constantsMap project constant container
+ * @return RequestMapping
+ */
+ public RequestMapping handle(String serverUrl, String controllerBaseUrl, JavaMethod method, Map constantsMap) {
+ List annotations = method.getAnnotations();
+ String url;
+ String methodType = "ANY";
+ String shortUrl = null;
+ String mediaType = null;
+
+ boolean deprecated = false;
+ for (JavaAnnotation annotation : annotations) {
+ String annotationName = annotation.getType().getName();
+ Object produces = annotation.getNamedParameter("produces");
+ if (produces != null) {
+ mediaType = produces.toString();
+ }
+ if (DocAnnotationConstants.DEPRECATED.equals(annotationName)) {
+ deprecated = true;
+ }
+ if (Constants.REQUEST_MAPPING.equals(annotationName) || Constants.REQUEST_MAPPING_FULLY.equals(annotationName)) {
+ shortUrl = DocUtil.handleMappingValue(annotation);
+
+ }
+ if (Constants.GET_MAPPING.equals(annotationName) || Constants.GET_MAPPING_FULLY.equals(annotationName)) {
+ methodType = Methods.GET.getValue();
+ } else if (Constants.POST_MAPPING.equals(annotationName) || Constants.POST_MAPPING_FULLY.equals(annotationName)) {
+ methodType = Methods.POST.getValue();
+ mediaType="application/json;charset=UTF-8";
+ } else if (Constants.PUT_MAPPING.equals(annotationName) || Constants.PUT_MAPPING_FULLY.equals(annotationName)) {
+ mediaType="application/json;charset=UTF-8";
+ methodType = Methods.PUT.getValue();
+ } else if (Constants.PATCH_MAPPING.equals(annotationName) || Constants.PATCH_MAPPING_FULLY.equals(annotationName)) {
+ methodType = Methods.PATCH.getValue();
+ } else if (Constants.DELETE_MAPPING.equals(annotationName) || Constants.DELETE_MAPPING_FULLY.equals(annotationName)) {
+ methodType = Methods.DELETE.getValue();
+ }
+ }
+ if (shortUrl != null) {
+ if (null != method.getTagByName(IGNORE)) {
+ return null;
+ }
+ shortUrl = StringUtil.removeQuotes(shortUrl);
+ String[] urls = shortUrl.split(",");
+ if (urls.length > 1) {
+ url = DocUrlUtil.getMvcUrls(serverUrl, controllerBaseUrl, Arrays.asList(urls));
+ shortUrl = DocUrlUtil.getMvcUrls("", controllerBaseUrl, Arrays.asList(urls));
+ } else {
+ url = UrlUtil.simplifyUrl(serverUrl + "/" + controllerBaseUrl + "/" + shortUrl);
+ shortUrl = UrlUtil.simplifyUrl("/" + controllerBaseUrl + "/" + shortUrl);
+ }
+ for (Map.Entry entry : constantsMap.entrySet()) {
+ String key = entry.getKey();
+ String value = entry.getValue();
+ if (url.contains(key)) {
+ url = url.replace(key, value);
+ url = url.replace("+", "");
+ }
+ if (shortUrl.contains(key)) {
+ shortUrl = shortUrl.replace(key, value);
+ shortUrl = shortUrl.replace("+", "");
+ }
+ }
+ return RequestMapping.builder().setMediaType(mediaType).setMethodType(methodType)
+ .setUrl(StringUtil.trim(url)).setShortUrl(StringUtil.trim(shortUrl)).setDeprecated(deprecated);
+ }
+ return null;
+ }
+}
diff --git a/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/integration/XPluginImp.java b/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/integration/XPluginImp.java
deleted file mode 100644
index e04e786084e572fb6d8dfb753e8a5f6a287a207a..0000000000000000000000000000000000000000
--- a/solonhat-smartdoc/src/main/java/org/noear/solonhat/smartdoc/integration/XPluginImp.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.noear.solonhat.smartdoc.integration;
-
-
-import org.noear.solon.SolonApp;
-import org.noear.solon.core.Plugin;
-
-/**
- * @author noear 2021/11/18 created
- */
-public class XPluginImp implements Plugin {
- @Override
- public void start(SolonApp app) {
-
- }
-}
diff --git a/solonhat-smartdoc/src/main/resources/META-INF/solon/solonhat.smartdoc.properties b/solonhat-smartdoc/src/main/resources/META-INF/solon/solonhat.smartdoc.properties
deleted file mode 100644
index 481ddf37e5ae3c5230caaca8cc0ed6da2c675351..0000000000000000000000000000000000000000
--- a/solonhat-smartdoc/src/main/resources/META-INF/solon/solonhat.smartdoc.properties
+++ /dev/null
@@ -1 +0,0 @@
-solon.plugin=org.noear.solonhat.swagger2.XPluginImp
\ No newline at end of file
diff --git a/solonhat-smartdoc/src/readme.md b/solonhat-smartdoc/src/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..c665001e05c3dc8fd66104617a8f1ba169f5962a
--- /dev/null
+++ b/solonhat-smartdoc/src/readme.md
@@ -0,0 +1,18 @@
+# solonhat smartdoc 使用说明
+- smartdoc是一个无代码侵入的文档生成工具,生成的文档是静态html/md 对项目运行无任何不良影响
+- 目前版本暂只支持html生成
+## 引用
+ 引用时,scope可设置为test,package时不用打包进去
+## 使用
+ copy Doc.java到你的项目中的test代码目录,运行 的Doc.testBuilderControllersApi
+
+## 输出
+ 生成html及css文件
+## 配置
+- config.setServerUrl("http://localhost:8089") 设置服务URL,用于生成请求示例
+- config.setOutPath(DocGlobalConstants.HTML_DOC_OUT_PATH); 设置输出路径,默认src/main/resources/static/doc
+
+
+## 示例
+ https://gitee.com/mantouchong/solonhat-smartdoc-test
+
\ No newline at end of file