support html api doc

This commit is contained in:
oppofind 2019-09-21 22:53:58 +08:00
parent 07e7a7aa6a
commit fee078b72a
19 changed files with 918 additions and 61 deletions

View File

@ -4,6 +4,9 @@ import com.power.common.util.CollectionUtil;
import com.power.common.util.DateTimeUtil; import com.power.common.util.DateTimeUtil;
import com.power.common.util.FileUtil; import com.power.common.util.FileUtil;
import com.power.common.util.StringUtil; import com.power.common.util.StringUtil;
import com.power.doc.constants.GlobalConstants;
import com.power.doc.constants.Language;
import com.power.doc.constants.TemplateVariable;
import com.power.doc.model.ApiConfig; import com.power.doc.model.ApiConfig;
import com.power.doc.model.ApiDoc; import com.power.doc.model.ApiDoc;
import com.power.doc.model.ApiErrorCode; import com.power.doc.model.ApiErrorCode;
@ -12,10 +15,11 @@ import org.beetl.core.Template;
import java.util.List; import java.util.List;
import static com.power.doc.constants.GlobalConstants.FILE_SEPARATOR; import static com.power.doc.constants.GlobalConstants.*;
/** /**
* use to create markdown doc * use to create markdown doc
*
* @author yu 2019/09/20 * @author yu 2019/09/20
*/ */
public class ApiDocBuilder { public class ApiDocBuilder {
@ -42,6 +46,12 @@ public class ApiDocBuilder {
if (StringUtil.isEmpty(config.getOutPath())) { if (StringUtil.isEmpty(config.getOutPath())) {
throw new RuntimeException("doc output path can't be null or empty"); throw new RuntimeException("doc output path can't be null or empty");
} }
if (null != config.getLanguage()) {
System.setProperty(GlobalConstants.DOC_LANGUAGE, config.getLanguage().getCode());
} else {
//default is chinese
System.setProperty(GlobalConstants.DOC_LANGUAGE, Language.CHINESE.getCode());
}
SourceBuilder sourceBuilder = new SourceBuilder(config); SourceBuilder sourceBuilder = new SourceBuilder(config);
List<ApiDoc> apiDocList = sourceBuilder.getControllerApiData(); List<ApiDoc> apiDocList = sourceBuilder.getControllerApiData();
if (config.isAllInOne()) { if (config.isAllInOne()) {
@ -62,10 +72,10 @@ public class ApiDocBuilder {
FileUtil.mkdirs(outPath); FileUtil.mkdirs(outPath);
SourceBuilder sourceBuilder = new SourceBuilder(true); SourceBuilder sourceBuilder = new SourceBuilder(true);
ApiDoc doc = sourceBuilder.getSingleControllerApiData(controllerName); ApiDoc doc = sourceBuilder.getSingleControllerApiData(controllerName);
Template mapper = BeetlTemplateUtil.getByName("ApiDoc.btl"); Template mapper = BeetlTemplateUtil.getByName(API_DOC_TPL);
mapper.binding("desc", doc.getDesc()); mapper.binding(TemplateVariable.DESC.getVariable(), doc.getDesc());
mapper.binding("name", doc.getName()); mapper.binding(TemplateVariable.NAME.getVariable(), doc.getName());
mapper.binding("list", doc.getList());//类名 mapper.binding(TemplateVariable.LIST.getVariable(), doc.getList());//类名
FileUtil.writeFileNotAppend(mapper.render(), outPath + FILE_SEPARATOR + doc.getName() + "Api.md"); FileUtil.writeFileNotAppend(mapper.render(), outPath + FILE_SEPARATOR + doc.getName() + "Api.md");
} }
@ -78,10 +88,10 @@ public class ApiDocBuilder {
private static void buildApiDoc(List<ApiDoc> apiDocList, String outPath) { private static void buildApiDoc(List<ApiDoc> apiDocList, String outPath) {
FileUtil.mkdirs(outPath); FileUtil.mkdirs(outPath);
for (ApiDoc doc : apiDocList) { for (ApiDoc doc : apiDocList) {
Template mapper = BeetlTemplateUtil.getByName("ApiDoc.btl"); Template mapper = BeetlTemplateUtil.getByName(API_DOC_TPL);
mapper.binding("desc", doc.getDesc()); mapper.binding(TemplateVariable.DESC.getVariable(), doc.getDesc());
mapper.binding("name", doc.getName()); mapper.binding(TemplateVariable.NAME.getVariable(), doc.getName());
mapper.binding("list", doc.getList());//类名 mapper.binding(TemplateVariable.LIST.getVariable(), doc.getList());//类名
FileUtil.nioWriteFile(mapper.render(), outPath + FILE_SEPARATOR + doc.getName() + "Api.md"); FileUtil.nioWriteFile(mapper.render(), outPath + FILE_SEPARATOR + doc.getName() + "Api.md");
} }
} }
@ -95,9 +105,9 @@ public class ApiDocBuilder {
String outPath = config.getOutPath(); String outPath = config.getOutPath();
FileUtil.mkdirs(outPath); FileUtil.mkdirs(outPath);
Template tpl = BeetlTemplateUtil.getByName("AllInOne.btl"); Template tpl = BeetlTemplateUtil.getByName("AllInOne.btl");
tpl.binding("apiDocList", apiDocList); tpl.binding(TemplateVariable.API_DOC_LIST.getVariable(), apiDocList);
tpl.binding("errorCodeList", config.getErrorCodes()); tpl.binding(TemplateVariable.ERROR_CODE_LIST.getVariable(), config.getErrorCodes());
tpl.binding("revisionLogList", config.getRevisionLogs()); tpl.binding(TemplateVariable.VERSION_LIST.getVariable(), config.getRevisionLogs());
String version = DateTimeUtil.long2Str(System.currentTimeMillis(), "yyyyMMddHHmm"); String version = DateTimeUtil.long2Str(System.currentTimeMillis(), "yyyyMMddHHmm");
FileUtil.nioWriteFile(tpl.render(), outPath + FILE_SEPARATOR + "AllInOne-V" + version + ".md"); FileUtil.nioWriteFile(tpl.render(), outPath + FILE_SEPARATOR + "AllInOne-V" + version + ".md");
} }
@ -110,9 +120,9 @@ public class ApiDocBuilder {
*/ */
private static void buildErrorCodeDoc(List<ApiErrorCode> errorCodeList, String outPath) { private static void buildErrorCodeDoc(List<ApiErrorCode> errorCodeList, String outPath) {
if (CollectionUtil.isNotEmpty(errorCodeList)) { if (CollectionUtil.isNotEmpty(errorCodeList)) {
Template mapper = BeetlTemplateUtil.getByName("ErrorCodeList.btl"); Template mapper = BeetlTemplateUtil.getByName(ERROR_CODE_LIST_TPL);
mapper.binding("list", errorCodeList);//类名 mapper.binding(TemplateVariable.LIST.getVariable(), errorCodeList);//类名
FileUtil.nioWriteFile(mapper.render(), outPath + FILE_SEPARATOR + "ErrorCodeList.md"); FileUtil.nioWriteFile(mapper.render(), outPath + FILE_SEPARATOR + ERROR_CODE_LIST_MD);
} }
} }
} }

View File

@ -1,19 +1,26 @@
package com.power.doc.builder; package com.power.doc.builder;
import com.power.common.util.CollectionUtil;
import com.power.common.util.DateTimeUtil;
import com.power.common.util.FileUtil; import com.power.common.util.FileUtil;
import com.power.common.util.StringUtil; import com.power.common.util.StringUtil;
import com.power.doc.constants.GlobalConstants;
import com.power.doc.constants.Language;
import com.power.doc.constants.TemplateVariable;
import com.power.doc.model.ApiConfig; import com.power.doc.model.ApiConfig;
import com.power.doc.model.ApiDoc; import com.power.doc.model.ApiDoc;
import com.power.doc.model.ApiErrorCode;
import com.power.doc.utils.BeetlTemplateUtil; import com.power.doc.utils.BeetlTemplateUtil;
import com.power.doc.utils.MarkDownUtil;
import org.beetl.core.Template; import org.beetl.core.Template;
import java.io.File;
import java.util.List; import java.util.List;
import static com.power.doc.constants.GlobalConstants.FILE_SEPARATOR; import static com.power.doc.constants.GlobalConstants.*;
/** /**
* @author yu 2019/9/20. * @author yu 2019/9/20.
* @since 1.7+
*/ */
public class HtmlApiDocBuilder { public class HtmlApiDocBuilder {
@ -27,27 +34,44 @@ public class HtmlApiDocBuilder {
if (StringUtil.isEmpty(config.getOutPath())) { if (StringUtil.isEmpty(config.getOutPath())) {
throw new RuntimeException("doc output path can't be null or empty"); throw new RuntimeException("doc output path can't be null or empty");
} }
if (null != config.getLanguage()) {
System.setProperty(GlobalConstants.DOC_LANGUAGE, config.getLanguage().getCode());
} else {
//default is chinese
System.setProperty(GlobalConstants.DOC_LANGUAGE, Language.CHINESE.getCode());
}
SourceBuilder sourceBuilder = new SourceBuilder(config); SourceBuilder sourceBuilder = new SourceBuilder(config);
List<ApiDoc> apiDocList = sourceBuilder.getControllerApiData(); List<ApiDoc> apiDocList = sourceBuilder.getControllerApiData();
buildIndex(apiDocList, config.getOutPath()); buildIndex(apiDocList, config);
copyCss(config.getOutPath()); copyCss(config.getOutPath());
buildApiDoc(apiDocList, config.getOutPath());
buildErrorCodeDoc(config.getErrorCodes(), config.getOutPath());
} }
private static void copyCss(String outPath) { private static void copyCss(String outPath) {
Template indexCssTemplate = BeetlTemplateUtil.getByName("index.css"); Template indexCssTemplate = BeetlTemplateUtil.getByName(INDEX_CSS_TPL);
Template mdCssTemplate = BeetlTemplateUtil.getByName("markdown.css"); Template mdCssTemplate = BeetlTemplateUtil.getByName(MARKDOWN_CSS_TPL);
FileUtil.nioWriteFile(indexCssTemplate.render(), outPath + FILE_SEPARATOR + "index.css"); FileUtil.nioWriteFile(indexCssTemplate.render(), outPath + FILE_SEPARATOR + INDEX_CSS_TPL);
FileUtil.nioWriteFile(mdCssTemplate.render(), outPath + FILE_SEPARATOR + "markdown.css"); FileUtil.nioWriteFile(mdCssTemplate.render(), outPath + FILE_SEPARATOR + MARKDOWN_CSS_TPL);
} }
private static void buildIndex(List<ApiDoc> apiDocList, String outPath) { private static void buildIndex(List<ApiDoc> apiDocList, ApiConfig config) {
FileUtil.mkdirs(outPath); FileUtil.mkdirs(config.getOutPath());
Template indexTemplate = BeetlTemplateUtil.getByName("Index.btl"); Template indexTemplate = BeetlTemplateUtil.getByName(INDEX_TPL);
ApiDoc doc = apiDocList.get(0); ApiDoc doc = apiDocList.get(0);
String homePage = doc.getName(); String homePage = doc.getAlias();
indexTemplate.binding("home", homePage); indexTemplate.binding(TemplateVariable.HOME_PAGE.getVariable(), homePage);
indexTemplate.binding("apiDocList", apiDocList); indexTemplate.binding(TemplateVariable.API_DOC_LIST.getVariable(), apiDocList);
FileUtil.nioWriteFile(indexTemplate.render(), outPath + FILE_SEPARATOR + "api.html"); if (null != config.getLanguage()) {
if (Language.CHINESE.code.equals(config.getLanguage().getCode())) {
indexTemplate.binding(TemplateVariable.ERROR_LIST_TITLE.getVariable(), "A. 错误码列表");
} else {
indexTemplate.binding(TemplateVariable.ERROR_LIST_TITLE.getVariable(), "A. Error Code List");
}
} else {
indexTemplate.binding(TemplateVariable.ERROR_LIST_TITLE.getVariable(), "A. 错误码列表");
}
FileUtil.nioWriteFile(indexTemplate.render(), config.getOutPath() + FILE_SEPARATOR + "api.html");
} }
@ -59,12 +83,41 @@ public class HtmlApiDocBuilder {
*/ */
private static void buildApiDoc(List<ApiDoc> apiDocList, String outPath) { private static void buildApiDoc(List<ApiDoc> apiDocList, String outPath) {
FileUtil.mkdirs(outPath); FileUtil.mkdirs(outPath);
Template htmlApiDoc;
for (ApiDoc doc : apiDocList) { for (ApiDoc doc : apiDocList) {
Template mapper = BeetlTemplateUtil.getByName("ApiDoc.btl"); Template apiTemplate = BeetlTemplateUtil.getByName(API_DOC_TPL);
mapper.binding("desc", doc.getDesc()); apiTemplate.binding(TemplateVariable.DESC.getVariable(), doc.getDesc());
mapper.binding("name", doc.getName()); apiTemplate.binding(TemplateVariable.NAME.getVariable(), doc.getName());
mapper.binding("list", doc.getList());//类名 apiTemplate.binding(TemplateVariable.LIST.getVariable(), doc.getList());//类名
FileUtil.nioWriteFile(mapper.render(), outPath + FILE_SEPARATOR + doc.getName() + "Api.md");
String html = MarkDownUtil.toHtml(apiTemplate.render());
htmlApiDoc = BeetlTemplateUtil.getByName(HTML_API_DOC_TPL);
htmlApiDoc.binding(TemplateVariable.HTML.getVariable(), html);
htmlApiDoc.binding(TemplateVariable.TITLE.getVariable(),doc.getName());
htmlApiDoc.binding(TemplateVariable.CREATE_TIME.getVariable(), DateTimeUtil.long2Str(System.currentTimeMillis()
, DateTimeUtil.DATE_FORMAT_SECOND));
FileUtil.nioWriteFile(htmlApiDoc.render(), outPath + FILE_SEPARATOR + doc.getAlias() + ".html");
}
}
/**
* 构建错误码列表
*
* @param errorCodeList 错误列表
* @param outPath
*/
private static void buildErrorCodeDoc(List<ApiErrorCode> errorCodeList, String outPath) {
if (CollectionUtil.isNotEmpty(errorCodeList)) {
Template error = BeetlTemplateUtil.getByName(ERROR_CODE_LIST_TPL);
error.binding(TemplateVariable.LIST.getVariable(), errorCodeList);//类名
String errorHtml = MarkDownUtil.toHtml(error.render());
Template errorCodeDoc = BeetlTemplateUtil.getByName(HTML_API_DOC_TPL);
errorCodeDoc.binding(TemplateVariable.TITLE.getVariable(),"error code");
errorCodeDoc.binding(TemplateVariable.HTML.getVariable(), errorHtml);
errorCodeDoc.binding(TemplateVariable.CREATE_TIME.getVariable(), DateTimeUtil.long2Str(System.currentTimeMillis()
, DateTimeUtil.DATE_FORMAT_SECOND));
FileUtil.nioWriteFile(errorCodeDoc.render(), outPath + FILE_SEPARATOR + "error_code.html");
} }
} }
} }

View File

@ -1,9 +1,6 @@
package com.power.doc.builder; package com.power.doc.builder;
import com.power.common.util.CollectionUtil; import com.power.common.util.*;
import com.power.common.util.JsonFormatUtil;
import com.power.common.util.StringUtil;
import com.power.common.util.UrlUtil;
import com.power.doc.constants.AnnotationConstants; import com.power.doc.constants.AnnotationConstants;
import com.power.doc.constants.DocTags; import com.power.doc.constants.DocTags;
import com.power.doc.constants.GlobalConstants; import com.power.doc.constants.GlobalConstants;
@ -48,6 +45,7 @@ public class SourceBuilder {
private String packageMatch; private String packageMatch;
private List<ApiReqHeader> headers; private List<ApiReqHeader> headers;
private String appUrl; private String appUrl;
private AesInfo aesInfo;
/** /**
* if isStrict value is true,it while check all method * if isStrict value is true,it while check all method
@ -75,6 +73,7 @@ public class SourceBuilder {
this.appUrl = config.getServerUrl(); this.appUrl = config.getServerUrl();
} }
aesInfo = config.getAesInfo();
this.packageMatch = config.getPackageFilters(); this.packageMatch = config.getPackageFilters();
this.isStrict = config.isStrict(); this.isStrict = config.isStrict();
loadJavaFiles(config.getSourcePaths()); loadJavaFiles(config.getSourcePaths());
@ -154,22 +153,32 @@ public class SourceBuilder {
public List<ApiDoc> getControllerApiData() { public List<ApiDoc> getControllerApiData() {
List<ApiDoc> apiDocList = new ArrayList<>(); List<ApiDoc> apiDocList = new ArrayList<>();
int order = 0;
for (JavaClass cls : javaClasses) { for (JavaClass cls : javaClasses) {
if (checkController(cls)) { if (checkController(cls)) {
String controllerName = cls.getName(); String controllerName = cls.getName();
if (StringUtil.isNotEmpty(packageMatch)) { if (StringUtil.isNotEmpty(packageMatch)) {
if (DocUtil.isMatch(packageMatch, cls.getCanonicalName())) { if (DocUtil.isMatch(packageMatch, cls.getCanonicalName())) {
order++;
List<ApiMethodDoc> apiMethodDocs = buildControllerMethod(cls); List<ApiMethodDoc> apiMethodDocs = buildControllerMethod(cls);
ApiDoc apiDoc = new ApiDoc(); ApiDoc apiDoc = new ApiDoc();
apiDoc.setDesc(cls.getComment()); apiDoc.setOrder(order);
apiDoc.setName(controllerName); apiDoc.setName(controllerName);
apiDoc.setAlias(controllerName);
this.handControllerAlias(apiDoc);
apiDoc.setDesc(cls.getComment());
apiDoc.setList(apiMethodDocs); apiDoc.setList(apiMethodDocs);
apiDocList.add(apiDoc); apiDocList.add(apiDoc);
} }
} else { } else {
order++;
List<ApiMethodDoc> apiMethodDocs = buildControllerMethod(cls); List<ApiMethodDoc> apiMethodDocs = buildControllerMethod(cls);
ApiDoc apiDoc = new ApiDoc(); ApiDoc apiDoc = new ApiDoc();
apiDoc.setOrder(order);
apiDoc.setAlias(MD6Util.md6(controllerName));
apiDoc.setName(controllerName); apiDoc.setName(controllerName);
apiDoc.setAlias(controllerName);
this.handControllerAlias(apiDoc);
apiDoc.setDesc(cls.getComment()); apiDoc.setDesc(cls.getComment());
apiDoc.setList(apiMethodDocs); apiDoc.setList(apiMethodDocs);
apiDocList.add(apiDoc); apiDocList.add(apiDoc);
@ -215,11 +224,14 @@ public class SourceBuilder {
} }
List<JavaMethod> methods = cls.getMethods(); List<JavaMethod> methods = cls.getMethods();
List<ApiMethodDoc> methodDocList = new ArrayList<>(methods.size()); List<ApiMethodDoc> methodDocList = new ArrayList<>(methods.size());
int methodOrder = 0;
for (JavaMethod method : methods) { for (JavaMethod method : methods) {
if (StringUtil.isEmpty(method.getComment()) && isStrict) { if (StringUtil.isEmpty(method.getComment()) && isStrict) {
throw new RuntimeException("Unable to find comment for method " + method.getName() + " in " + cls.getCanonicalName()); throw new RuntimeException("Unable to find comment for method " + method.getName() + " in " + cls.getCanonicalName());
} }
methodOrder++;
ApiMethodDoc apiMethodDoc = new ApiMethodDoc(); ApiMethodDoc apiMethodDoc = new ApiMethodDoc();
apiMethodDoc.setOrder(methodOrder);
apiMethodDoc.setDesc(method.getComment()); apiMethodDoc.setDesc(method.getComment());
List<JavaAnnotation> annotations = method.getAnnotations(); List<JavaAnnotation> annotations = method.getAnnotations();
String url = null; String url = null;
@ -644,7 +656,7 @@ public class SourceBuilder {
} }
} }
if (DocClassUtil.isPrimitive(typeName)) { if (DocClassUtil.isPrimitive(typeName)) {
return DocUtil.jsonValueByType(typeName); return DocUtil.jsonValueByType(typeName).replace("\"", "");
} }
StringBuilder data0 = new StringBuilder(); StringBuilder data0 = new StringBuilder();
JavaClass cls = builder.getClassByName(typeName); JavaClass cls = builder.getClassByName(typeName);
@ -1102,4 +1114,22 @@ public class SourceBuilder {
} }
return fieldList; return fieldList;
} }
/**
* handle controller name
*
* @param apiDoc ApiDoc
*/
private void handControllerAlias(ApiDoc apiDoc) {
if (null != aesInfo && StringUtil.isNotEmpty(aesInfo.getKey())
&& StringUtil.isNotEmpty(aesInfo.getVector())) {
String name = AESUtil.encodeByCBC(apiDoc.getName(), aesInfo.getKey(), aesInfo.getVector());
int length = name.length();
if (name.length() < 32) {
apiDoc.setAlias(name);
} else {
apiDoc.setAlias(name.substring(length - 32, length));
}
}
}
} }

View File

@ -6,6 +6,22 @@ package com.power.doc.constants;
public class GlobalConstants { public class GlobalConstants {
public static final String FILE_SEPARATOR = System.getProperty("file.separator"); public static final String FILE_SEPARATOR = System.getProperty("file.separator");
public static final String DOC_LANGUAGE = "smart-doc_language";
public static final String API_DOC_TPL = "ApiDoc.btl";
public static final String HTML_API_DOC_TPL = "HtmlApiDoc.btl";
public static final String ERROR_CODE_LIST_TPL = "ErrorCodeList.btl";
public static final String ERROR_CODE_LIST_MD = "ErrorCodeList.md";
public static final String INDEX_TPL = "Index.btl";
public static final String INDEX_CSS_TPL = "index.css";
public static final String MARKDOWN_CSS_TPL = "markdown.css";
/** /**
* controller注解全名称 * controller注解全名称
*/ */

View File

@ -0,0 +1,20 @@
package com.power.doc.constants;
/**
* 语言支持
* @author yu 2019/9/21.
*/
public enum Language {
ENGLISH("en-US"),
CHINESE("zh-CN");
public String code;
Language(String code) {
this.code = code;
}
public String getCode(){
return this.code;
}
}

View File

@ -0,0 +1,30 @@
package com.power.doc.constants;
/**
* @author yu 2019/9/21.
*/
public enum TemplateVariable {
DESC("desc"),
NAME("name"),
LIST("list"),
API_DOC_LIST("apiDocList"),
ERROR_CODE_LIST("errorCodeList"),
VERSION_LIST("revisionLogList"),
HOME_PAGE("homePage"),
HTML("html"),
TITLE("title"),
ERROR_LIST_TITLE("errorListTitle"),
CREATE_TIME("createTime");
private String variable;
TemplateVariable(String variable) {
this.variable = variable;
}
public String getVariable(){
return this.variable;
}
}

View File

@ -0,0 +1,41 @@
package com.power.doc.model;
/**
* aes加密信息
* @since 1.7+
* @author yu 2019/9/21.
*/
public class AesInfo {
/**
* aes加密key
*/
private String key;
/**
* 加密初始向量
*/
private String vector;
public static AesInfo create() {
return new AesInfo();
}
public String getKey() {
return key;
}
public AesInfo setKey(String key) {
this.key = key;
return this;
}
public String getVector() {
return vector;
}
public AesInfo setVector(String vector) {
this.vector = vector;
return this;
}
}

View File

@ -1,6 +1,7 @@
package com.power.doc.model; package com.power.doc.model;
import com.power.common.util.CollectionUtil; import com.power.common.util.CollectionUtil;
import com.power.doc.constants.Language;
import java.util.List; import java.util.List;
@ -66,6 +67,19 @@ public class ApiConfig {
*/ */
private List<RevisionLog> revisionLogs; private List<RevisionLog> revisionLogs;
/**
* @since 1.7+
* aes加密信息
*/
private AesInfo aesInfo;
/**
* 语言
* @since 1.7+
*/
private Language language;
public String getServerUrl() { public String getServerUrl() {
return serverUrl; return serverUrl;
} }
@ -147,4 +161,19 @@ public class ApiConfig {
this.revisionLogs = CollectionUtil.asList(revisionLogs); this.revisionLogs = CollectionUtil.asList(revisionLogs);
} }
public AesInfo getAesInfo() {
return aesInfo;
}
public void setAesInfo(AesInfo aesInfo) {
this.aesInfo = aesInfo;
}
public Language getLanguage() {
return language;
}
public void setLanguage(Language language) {
this.language = language;
}
} }

View File

@ -4,12 +4,23 @@ import java.util.List;
public class ApiDoc { public class ApiDoc {
/**
* @since 1.7+
* 文档顺序
*/
public int order;
/** /**
* 类名 * 类名
*/ */
private String name; private String name;
/**
* @since 1.7+
* md5加密后的文件名(用于处理html)
*/
private String alias;
/** /**
* 方法文档列表 * 方法文档列表
*/ */
@ -44,5 +55,19 @@ public class ApiDoc {
this.desc = desc; this.desc = desc;
} }
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
} }

View File

@ -7,6 +7,11 @@ import java.io.Serializable;
*/ */
public class ApiMethodDoc implements Serializable { public class ApiMethodDoc implements Serializable {
/**
* @since 1.7+
*/
private int order;
private String desc; private String desc;
private String url; private String url;
@ -97,4 +102,12 @@ public class ApiMethodDoc implements Serializable {
public void setHeaders(String headers) { public void setHeaders(String headers) {
this.headers = headers; this.headers = headers;
} }
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
} }

View File

@ -22,6 +22,18 @@ public class ApiReqHeader {
*/ */
private String desc; private String desc;
/**
* @since 1.7.0
* 请求有是否必须
*/
private boolean required;
/**
* @since 1.7.0
* 起始版本
*/
private String since = "-";
public static ApiReqHeader header() { public static ApiReqHeader header() {
return new ApiReqHeader(); return new ApiReqHeader();
} }
@ -52,4 +64,22 @@ public class ApiReqHeader {
this.desc = desc; this.desc = desc;
return this; return this;
} }
public boolean isRequired() {
return required;
}
public ApiReqHeader setRequired(boolean required) {
this.required = required;
return this;
}
public String getSince() {
return since;
}
public ApiReqHeader setSince(String since) {
this.since = since;
return this;
}
} }

View File

@ -5,6 +5,7 @@ import com.power.common.util.DateTimeUtil;
import com.power.common.util.IDCardUtil; import com.power.common.util.IDCardUtil;
import com.power.common.util.RandomUtil; import com.power.common.util.RandomUtil;
import com.power.common.util.StringUtil; import com.power.common.util.StringUtil;
import com.power.doc.constants.GlobalConstants;
import com.thoughtworks.qdox.model.JavaAnnotation; import com.thoughtworks.qdox.model.JavaAnnotation;
import java.util.*; import java.util.*;
@ -17,7 +18,7 @@ import java.util.*;
*/ */
public class DocUtil { public class DocUtil {
private static Faker faker = new Faker(new Locale("zh-CN")); private static Faker faker = new Faker(new Locale(System.getProperty(GlobalConstants.DOC_LANGUAGE)));
private static Faker enFaker = new Faker(new Locale("en-US")); private static Faker enFaker = new Faker(new Locale("en-US"));

View File

@ -0,0 +1,37 @@
package com.power.doc.utils;
import com.vladsch.flexmark.ext.tables.TablesExtension;
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.parser.ParserEmulationProfile;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.data.MutableDataSet;
import java.util.Arrays;
/**
* @since 1.7+
* @author yu 2019/9/21.
*/
public class MarkDownUtil {
/**
* markdown to html
*
* @param content markdown contents
* @return parse html contents
*/
public static String toHtml(String content) {
MutableDataSet options = new MutableDataSet();
options.setFrom(ParserEmulationProfile.MARKDOWN);
// enable table parse!
options.set(Parser.EXTENSIONS, Arrays.asList(TablesExtension.create()));
Parser parser = Parser.builder(options).build();
HtmlRenderer renderer = HtmlRenderer.builder(options).build();
Node document = parser.parse(content);
return renderer.render(document);
}
}

View File

@ -27,16 +27,16 @@ for(doc in api.list){
<%if(isNotEmpty(doc.headers)){%> <%if(isNotEmpty(doc.headers)){%>
**Request-headers:** **Request-headers:**
Name | Type|Description Header | Type|Description|Required|Since
---|---|--- ---|---|---|---|----
${doc.headers} ${doc.headers}
<%}%> <%}%>
<%if(isNotEmpty(doc.requestParams)){%> <%if(isNotEmpty(doc.requestParams)){%>
**Request-parameters:** **Request-parameters:**
Parameter | Type|Description|Required Parameter | Type|Description|Required|Since
---|---|---|--- ---|---|---|---|---
${doc.requestParams} ${doc.requestParams}
<%}%> <%}%>
@ -49,8 +49,8 @@ ${doc.requestUsage}
<%if(isNotEmpty(doc.responseParams)){%> <%if(isNotEmpty(doc.responseParams)){%>
**Response-fields:** **Response-fields:**
Field | Type|Description Field | Type|Description|Since
---|---|--- ---|---|---|---
${doc.responseParams} ${doc.responseParams}
<%}%> <%}%>

View File

@ -4,17 +4,17 @@
for(doc in list){ for(doc in list){
%> %>
## ${doc.desc} ## ${doc.desc}
**URL:** ${doc.url} **URL:** `${doc.url}`
**Type:** ${doc.type} **Type:** `${doc.type}`
**Content-Type:** ${doc.contentType} **Content-Type:** `${doc.contentType}`
<%if(isNotEmpty(doc.headers)){%> <%if(isNotEmpty(doc.headers)){%>
**Request-headers:** **Request-headers:**
Name | Type|Description Header | Type|Description|Required|Since
---|---|--- ---|---|---|---|----
${doc.headers} ${doc.headers}
<%}%> <%}%>

View File

@ -0,0 +1,24 @@
<!doctype html>
<html>
<head>
<meta charset='UTF-8'>
<meta name='viewport' content='width=device-width initial-scale=1'>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<link rel="stylesheet" href="markdown.css"/>
<title>${title}</title>
</head>
<body>
<div class="markdown-body">
${html}
<footer class="page-footer">
<span class="copyright">Generated by smart-doc at ${createTime}</span>
<span class="footer-modification">Suggestions, contact, support and error reporting on
<a href="https://gitee.com/sunyurepository/smart-doc" target="_blank">Gitee</a> or
<a href="https://github.com/shalousun/smart-doc" target="_blank">Github</a>
</span>
</footer>
</div>
</body>
</html>

View File

@ -3,38 +3,45 @@
<head> <head>
<meta charset='UTF-8'> <meta charset='UTF-8'>
<meta name='viewport' content='width=device-width initial-scale=1'> <meta name='viewport' content='width=device-width initial-scale=1'>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<link rel="stylesheet" href="index.css"/> <link rel="stylesheet" href="index.css"/>
<title>api doc</title>
</head> </head>
<div class="book without-animation with-summary font-size-2 font-family-1"> <div class="book without-animation with-summary font-size-2 font-family-1">
<div class="book-summary"> <div class="book-summary">
<div id="book-search-input"><input type="text" placeholder="Type to search"></div> <div id="book-search-input"><input type="text" placeholder="Type to search"></div>
<nav role="navigation"> <nav role="navigation">
<ul class="summary"> <ul class="summary">
<li><a href="${home}.html" target="_blank" class="custom-link">Home</a></li> <li><ul id="reference">API Reference</ul></li>
<li class="divider"></li> <li class="divider"></li>
<% <%
for(api in apiDocList){ for(api in apiDocList){
%> %>
<li class="chapter " data-level="${api.name}" data-path="${api.name}.html"> <li class="chapter " data-level="${api.alias}" data-path="${api.alias}.html">
<a href="${api.name}.html" target="book_iframe">${api.desc}</a> <a href="${api.alias}.html" target="book_iframe">${api.order}. ${api.desc}</a>
<ul class="articles"> <ul class="articles">
<% <%
for(doc in api.list){ for(doc in api.list){
%> %>
<li class="chapter " data-level="${api.name}" data-path="${api.name}.html"> <li class="chapter " data-level="${api.alias}" data-path="${api.alias}.html">
<a href="${api.name}.html" target="book_frame">${doc.desc}</a></li> <a href="${api.alias}.html" target="book_iframe">${api.order}.${doc.order} ${doc.desc}</a></li>
<%}%> <%}%>
</ul> </ul>
</li> </li>
<%}%> <%}%>
<li class="chapter " data-level="error_code" data-path="error_code.html">
<a href="error_code.html" target="book_iframe">${errorListTitle}</a>
</li>
<li class="divider"></li> <li class="divider"></li>
<li><a href="https://www.gitbook.com" target="blank" class="gitbook-link">Published with GitBook</a> <li class="footer_link"><a href="https://github.com/shalousun/smart-doc" target="blank" class="gitbook-link">Created by smart-doc</a>
</li> </li>
</ul> </ul>
</nav> </nav>
</div> </div>
<div id="book-body" class="book-body" height="100%"> <div id="book-body" class="book-body" height="100%">
<iframe src="TestControllerApi.html" frameborder="0" id="book_iframe" name="book_frame" width="100%"></iframe> <iframe src="${homePage}.html" frameborder="0" id="book_iframe" name="book_iframe" width="100%"></iframe>
</div> </div>
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
@ -43,6 +50,7 @@
ifm.height = document.documentElement.clientHeight ifm.height = document.documentElement.clientHeight
} }
changeFrameHeight(); changeFrameHeight();
setInterval(function(){changeFrameHeight(); }, 500);
</script> </script>
</body> </body>
</html> </html>

View File

@ -1 +1,228 @@
.book-summary{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;position:absolute;top:0;left:-300px;bottom:0;z-index:1;overflow-y:auto;width:300px;color:#364149;background:#fafafa;border-right:1px solid rgba(0,0,0,.07);-webkit-transition:left 250ms ease;-moz-transition:left 250ms ease;-o-transition:left 250ms ease;transition:left 250ms ease}.book-summary ul.summary{list-style:none;margin:0;padding:0;-webkit-transition:top .5s ease;-moz-transition:top .5s ease;-o-transition:top .5s ease;transition:top .5s ease}.book-summary ul.summary li{list-style:none}.book-summary ul.summary li.header{padding:10px 15px;padding-top:20px;text-transform:uppercase;color:#939da3}.book-summary ul.summary li.divider{height:1px;margin:7px 0;overflow:hidden;background:rgba(0,0,0,.07)}.book-summary ul.summary li i.fa-check{display:none;position:absolute;right:9px;top:16px;font-size:9px;color:#3c3}.book-summary ul.summary li.done>a{color:#364149;font-weight:400}.book-summary ul.summary li.done>a i{display:inline}.book-summary ul.summary li a,.book-summary ul.summary li span{display:block;padding:10px 15px;border-bottom:0;color:#364149;background:0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;position:relative}.book-summary ul.summary li a:hover{text-decoration:underline}.book-summary ul.summary li a:focus{outline:0}.book-summary ul.summary li.active>a{color:#008cff;background:0;text-decoration:none}.book-summary ul.summary li ul{padding-left:20px}@media(max-width:600px){.book-summary{width:calc(100% - 60px);bottom:0;left:-100%}}.book.with-summary .book-summary{left:0}.book.without-animation .book-summary{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;transition:none!important}.book{position:relative;width:100%;height:100%}@media(min-width:600px){.book.with-summary .book-body{left:300px}}@media(max-width:600px){.book.with-summary{overflow:hidden}.book.with-summary .book-body{-webkit-transform:translate(calc(100% - 60px),0);-moz-transform:translate(calc(100% - 60px),0);-ms-transform:translate(calc(100% - 60px),0);-o-transform:translate(calc(100% - 60px),0);transform:translate(calc(100% - 60px),0)}}.book.without-animation .book-body{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;transition:none!important}.book-body{position:absolute;top:0;right:0;left:0;bottom:0;overflow-y:auto;color:#000;background:#fff;-webkit-transition:left 250ms ease;-moz-transition:left 250ms ease;-o-transition:left 250ms ease;transition:left 250ms ease}@media(max-width:1240px){.book-body{-webkit-transition:-webkit-transform 250ms ease;-moz-transition:-moz-transform 250ms ease;-o-transition:-o-transform 250ms ease;transition:transform 250ms ease;padding-bottom:20px}}#book-search-input{padding:6px;background:0;transition:top .5s ease;border-bottom:1px solid rgba(0,0,0,.07);border-top:1px solid rgba(0,0,0,.07);margin-bottom:10px;margin-top:-1px}#book-search-input input,#book-search-input input:focus,#book-search-input input:hover{width:100%;background:0;border:1px solid transparent;box-shadow:none;outline:0;line-height:22px;padding:7px 7px;color:inherit}a{text-decoration:none}body,html{height:100%}html{font-size:62.5%}body{margin:0}body{text-rendering:optimizeLegibility;font-smoothing:antialiased;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;letter-spacing:.2px;text-size-adjust:100%;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} .book-summary {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
top: 0;
left: -300px;
bottom: 0;
z-index: 1;
overflow-y: auto;
width: 300px;
color: #364149;
background: #fafafa;
border-right: 1px solid rgba(0, 0, 0, .07);
-webkit-transition: left 250ms ease;
-moz-transition: left 250ms ease;
-o-transition: left 250ms ease;
transition: left 250ms ease
}
.book-summary ul.summary {
list-style: none;
margin: 0;
padding: 0;
-webkit-transition: top .5s ease;
-moz-transition: top .5s ease;
-o-transition: top .5s ease;
transition: top .5s ease
}
.book-summary ul.summary li {
list-style: none
}
.book-summary ul.summary li.header {
padding: 10px 15px;
padding-top: 20px;
text-transform: uppercase;
color: #939da3
}
.book-summary ul.summary li.divider {
height: 1px;
margin: 7px 0;
overflow: hidden;
background: rgba(0, 0, 0, .07)
}
.book-summary ul.summary li i.fa-check {
display: none;
position: absolute;
right: 9px;
top: 16px;
font-size: 9px;
color: #3c3
}
.book-summary ul.summary li.done > a {
color: #364149;
font-weight: 400
}
.book-summary ul.summary li.done > a i {
display: inline
}
.book-summary ul.summary li a, .book-summary ul.summary li span {
display: block;
padding: 10px 15px;
border-bottom: 0;
color: #364149;
background: 0;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
position: relative
}
.book-summary ul.summary li a:hover {
text-decoration: underline
}
.book-summary ul.summary li a:focus {
outline: 0
}
.book-summary ul.summary li.active > a {
color: #008cff;
background: 0;
text-decoration: none
}
.book-summary ul.summary li ul {
padding-left: 20px
}
@media (max-width: 600px) {
.book-summary {
width: calc(100% - 60px);
bottom: 0;
left: -100%
}
}
.book.with-summary .book-summary {
left: 0
}
.book.without-animation .book-summary {
-webkit-transition: none !important;
-moz-transition: none !important;
-o-transition: none !important;
transition: none !important
}
.book {
position: relative;
width: 100%;
height: 100%
}
@media (min-width: 600px) {
.book.with-summary .book-body {
left: 300px
}
}
@media (max-width: 600px) {
.book.with-summary {
overflow: hidden
}
.book.with-summary .book-body {
-webkit-transform: translate(calc(100% - 60px), 0);
-moz-transform: translate(calc(100% - 60px), 0);
-ms-transform: translate(calc(100% - 60px), 0);
-o-transform: translate(calc(100% - 60px), 0);
transform: translate(calc(100% - 60px), 0)
}
}
.book.without-animation .book-body {
-webkit-transition: none !important;
-moz-transition: none !important;
-o-transition: none !important;
transition: none !important
}
.book-body {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
overflow-y: auto;
color: #000;
background: #fff;
-webkit-transition: left 250ms ease;
-moz-transition: left 250ms ease;
-o-transition: left 250ms ease;
transition: left 250ms ease
}
@media (max-width: 1240px) {
.book-body {
-webkit-transition: -webkit-transform 250ms ease;
-moz-transition: -moz-transform 250ms ease;
-o-transition: -o-transform 250ms ease;
transition: transform 250ms ease;
padding-bottom: 20px
}
}
#book-search-input {
padding: 6px;
background: 0;
transition: top .5s ease;
border-bottom: 1px solid rgba(0, 0, 0, .07);
border-top: 1px solid rgba(0, 0, 0, .07);
margin-bottom: 10px;
margin-top: -1px
}
#book-search-input input, #book-search-input input:focus, #book-search-input input:hover {
width: 100%;
background: 0;
border: 1px solid transparent;
box-shadow: none;
outline: 0;
line-height: 22px;
padding: 7px 7px;
color: inherit
}
a {
text-decoration: none
}
body, html {
height: 100%
}
html {
font-size: 62.5%
}
body {
margin: 0
}
body {
text-rendering: optimizeLegibility;
font-smoothing: antialiased;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
letter-spacing: .2px;
text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%
}
#reference {
padding-top: 10px;
padding-bottom: 10px;
padding-left: 15px;
}
.footer_link {
margin-bottom: 45px;
}

File diff suppressed because one or more lines are too long