目录
2、从源码中找到以下三个文件,放到/resources文件下面
默认的接口文档是只有一级菜单
下面是通过修改之后的多级菜单,和正式的界面一样,方便查询
修改方法
1、在controller上加上注释前缀:服务:
/**
* 服务:客户管理
*
* @author honry.guan
* @created Create Time: 2020-06-03 06:04:55
*/
@RestController
@RequestMapping("/customer")
public class CustomerController {
2、从源码中找到以下三个文件,放到/resources文件下面
复制之后的文件:
修改api-controller.html.ftl文件
修改<div id="accordion" class="catalog">下面的代码模板,这里是使用的bootstrap的折叠插件,做好父子关系的联动就行
修改api-index.html.ftl文件
这里的<#list变量名字不一样,注意就行
修改css文件:
//修改的
.catalog .catalog-title {
border-bottom: 1px solid #EAEAEA;
padding: 1rem 1.25rem;
background: rgba(0,0,0,.075);
cursor: pointer;
color: #333;
font-weight: 600;
font-size: 16px;
}
//新增
.catalog .catalog-title-1 {
border-bottom: 1px solid #EAEAEA;
padding: 1rem 3.25rem;
background: rgba(0, 0, 0, .03);
cursor: pointer;
color: #777;
font-weight: 600;
font-size: 14px;
}
修改主函数:
public class ProductDoc {
public static void main(String[] args) {
DocsConfig config = new DocsConfig();
// 项目根目录
config.setProjectPath("D:\\Fj-code\\pushing_robot_server\\src\\main\\java\\com\\fj");
// 项目名称
config.setProjectName("push_robot_server");
// 声明该API的版本
config.setApiVersion("V1.0");
// 生成API 文档所在目录
config.setDocsPath("D:\\doc");
// 配置自动生成
config.setAutoGenerate(Boolean.TRUE);
// 执行生成文档
Docs.buildHtmlDocs(config);
//使用resources下的style.css替换默认的css
String cssFileName = "style.css";
File cssFile = new File("D:\\doc\\V1.0", cssFileName);
try {
File file = new File("src/main/resources/style.css");
InputStream in = new FileInputStream(file);
Utils.writeToDisk(cssFile, Utils.streamToString(in));
} catch (IOException e) {
e.printStackTrace();
}
}
}
以下是完整代码:
api-index.html.ftl
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>${projectName}API Documentation</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/google-code-prettify@1.0.5/bin/prettify.min.css">
<link rel="stylesheet" href="style.css">
</head>
<body onload="PR.prettyPrint()">
<nav class="navbar">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="index.html">
${projectName}
</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li><a href="https://github.com/YeDaxia/JApiDocs" target="_blank">GitHub</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">${currentApiVersion}<span class="caret"></span></a>
<ul class="dropdown-menu">
<#list apiVersionList as version>
<#if version != currentApiVersion>
<li><a href="../${version}/index.html">${version}</a></li>
</#if>
</#list>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div class="book with-summary">
<div class="book-summary">
<div class="search-box form-group">
<input type="text" class="form-control" id="inputSearch" placeholder="${i18n.getMessage('searchPlaceholder')}">
<span class="glyphicon glyphicon-search form-control-feedback" aria-hidden="true"></span>
</div>
<div id="accordion" class="catalog">
<div class="panel">
<div id="headingb" data-parent="#accordion" class="catalog-title" data-toggle="collapse"
aria-expanded="true" data-target="#collapseb" aria-controls="collapseb">
<i class="glyphicon glyphicon-th"></i> 记录
</div>
<div id="collapseb" class="collapse in " aria-labelledby="headingb">
<#list controllerNodeList as ctrolNode>
<#if ctrolNode.description?contains("记录:")>
<div class="panel">
<div id="heading${ctrolNode?index}b" data-parent="#collapseb" class="catalog-title-1" data-toggle="collapse"
aria-expanded="true" data-target="#collapse${ctrolNode?index}b" aria-controls="collapse${ctrolNode?index}b">
${ctrolNode.description?substring(3)}
</div>
<div id="collapse${ctrolNode?index}b" class="collapse <#if ctrolNode?index == 0>in </#if>" aria-labelledby="heading${ctrolNode?index}">
<#list ctrolNode.requestNodes as reqNode>
<a class="catalog-item" href="${reqNode.codeFileUrl}">
${reqNode.description}
</a>
</#list>
</div>
</div>
</#if>
</#list>
</div>
</div>
</div>
</div>
<div class="book-body">
<div class="body-inner">
<div class="book-header">
<div class="d-flex justify-content-between">
<a class="header-menu toggle-catalog" href="javascript:void(0)"><i
class="glyphicon glyphicon-align-justify"></i> ${i18n.getMessage('catalog')}</a>
</div>
</div>
<div class="page-wrapper">
<div class="page-inner">
<div class="main-content">
<img src="http://static.nowait.xin/pic/japidocs-logo.png" width="200" height="200">
<h4 style="margin: 20px">${i18n.getMessage('doc.generate.tip')}</h4>
<div class="list-group" style="min-width: 200px">
<#list controllerNodeList as ctrolNode>
<a href="${ctrolNode.docFileName}" class="list-group-item">${ctrolNode.description}</a>
</#list>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/autocomplete.js/0/autocomplete.jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/google-code-prettify@1.0.5/bin/prettify.min.js"></script>
<script>
var search_source_data = [
<#list controllerNodeList as ctrolNode>
<#list ctrolNode.requestNodes as reqNode>
{name: '${ctrolNode.description}.${reqNode.description}', url: '${reqNode.codeFileUrl}'},
</#list>
</#list>
];
$('.toggle-catalog').click(function () {
$('.book').toggleClass('with-summary');
});
$('#inputSearch').autocomplete({hint: false}, [
{
source: function (query, callback) {
var result = [];
for(var i = 0; i !== search_source_data.length; i++){
if(search_source_data[i].name.indexOf(query) !== -1){
result.push(search_source_data[i]);
}
}
callback(result);
},
displayKey: 'name',
templates: {
suggestion: function (suggestion) {
return suggestion.name;
}
}
}
]).on('autocomplete:selected', function (event, suggestion, dataset, context) {
self.location = suggestion.url;
});
</script>
</body>
</html>
api-controller.html.ftl
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>${controller.description}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/google-code-prettify@1.0.5/bin/prettify.min.css">
<link rel="stylesheet" href="style.css">
</head>
<body onload="PR.prettyPrint()">
<nav class="navbar">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="index.html">
${projectName}
</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right">
<li><a href="https://github.com/YeDaxia/JApiDocs" target="_blank">GitHub</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">${currentApiVersion}<span class="caret"></span></a>
<ul class="dropdown-menu">
<#list apiVersionList as version>
<#if version != currentApiVersion>
<li><a href="../${version}/index.html">${version}</a></li>
</#if>
</#list>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div class="book with-summary">
<div class="book-summary">
<div class="search-box form-group">
<input type="text" class="form-control" id="inputSearch" placeholder="${i18n.getMessage('searchPlaceholder')}">
<span class="glyphicon glyphicon-search form-control-feedback" aria-hidden="true"></span>
</div>
<div id="accordion" class="catalog">
<div class="panel">
<div id="headingb" data-parent="#accordion" class="catalog-title" data-toggle="collapse"
aria-expanded="true" data-target="#collapseb" aria-controls="collapseb">
<i class="glyphicon glyphicon-th"></i> 记录
</div>
<div id="collapseb" class="collapse in " aria-labelledby="headingb">
<#list controller.controllerNodes as ctrolNode>
<#if ctrolNode.description?contains("记录:")>
<div class="panel">
<div id="heading${ctrolNode?index}b" data-parent="#collapseb" class="catalog-title-1" data-toggle="collapse"
aria-expanded="true" data-target="#collapse${ctrolNode?index}b" aria-controls="collapse${ctrolNode?index}b">
${ctrolNode.description?substring(3)}
</div>
<div id="collapse${ctrolNode?index}b" class="collapse <#if ctrolNode?index == 0>in </#if>" aria-labelledby="heading${ctrolNode?index}">
<#list ctrolNode.requestNodes as reqNode>
<a class="catalog-item" href="${reqNode.codeFileUrl}">
${reqNode.description}
</a>
</#list>
</div>
</div>
</#if>
</#list>
</div>
</div>
<div class="panel">
<div id="headingc" data-parent="#accordion" class="catalog-title" data-toggle="collapse"
aria-expanded="true" data-target="#collapsec" aria-controls="collapsec">
<i class="glyphicon glyphicon-play-circle"></i> 设备
</div>
<div id="collapsec" class="collapse in " aria-labelledby="headingc">
<#list controller.controllerNodes as ctrolNode>
<#if ctrolNode.description?contains("设备:")>
<div class="panel">
<div id="heading${ctrolNode?index}c" data-parent="#collapseb" class="catalog-title-1" data-toggle="collapse"
aria-expanded="true" data-target="#collapse${ctrolNode?index}c" aria-controls="collapse${ctrolNode?index}c">
${ctrolNode.description?substring(3)}
</div>
<div id="collapse${ctrolNode?index}c" class="collapse <#if ctrolNode?index == 0>in </#if>" aria-labelledby="heading${ctrolNode?index}c">
<#list ctrolNode.requestNodes as reqNode>
<a class="catalog-item" href="${reqNode.codeFileUrl}">
${reqNode.description}
</a>
</#list>
</div>
</div>
</#if>
</#list>
</div>
</div>
</div>
</div>
<div class="book-body">
<div class="body-inner">
<div class="book-header">
<div class="d-flex justify-content-between">
<a class="header-menu toggle-catalog" href="javascript:void(0)"><i
class="glyphicon glyphicon-align-justify"></i> ${i18n.getMessage('catalog')}</a>
</div>
</div>
<div class="page-wrapper">
<div class="page-inner">
<div class="action-list">
<#list controller.requestNodes as reqNode>
<div class="action-item">
<h2 id="${reqNode.methodName}"><a href="#">${reqNode.description} <#if reqNode.deprecated><span class="badge">${i18n.getMessage('deprecated')}</span></#if></a></h2>
<p><strong>${i18n.getMessage('requestUrl')}</strong></p>
<p>
<code>${reqNode.url}</code>
<#list reqNode.method as method>
<span class="label label-default">${method}</span>
</#list>
</p>
<#if reqNode.paramNodes?size != 0>
<p><strong>${i18n.getMessage('requestParameters')}</strong></p>
<#assign isJsonReqBody = false/>
<#list reqNode.paramNodes as paramNode>
<#if paramNode.jsonBody>
<pre class="prettyprint lang-json">${paramNode.description}</pre>
<#assign isJsonReqBody = true/>
</#if>
</#list>
<#if !isJsonReqBody>
<table class="table table-bordered">
<tr>
<th>${i18n.getMessage('parameterName')}</th>
<th>${i18n.getMessage('parameterType')}</th>
<th>${i18n.getMessage('parameterNeed')}</th>
<th>${i18n.getMessage('description')}</th>
</tr>
<#list reqNode.paramNodes as paramNode>
<tr>
<td>${paramNode.name}</td>
<td>${paramNode.type}</td>
<td>${paramNode.required?string(i18n.getMessage('yes'),i18n.getMessage('no'))}</td>
<td>${paramNode.description}</td>
</tr>
</#list>
</table>
</#if>
</#if>
<#if reqNode.responseNode??>
<p><strong>${i18n.getMessage('responseResult')}</strong></p>
<pre class="prettyprint lang-json">${reqNode.responseNode.toJsonApi()}</pre>
<#if reqNode.androidCodePath??>
<div class="form-group">
<a type="button" class="btn btn-sm btn-default" href="${reqNode.androidCodePath}"><i class="fa fa-android" aria-hidden="true"></i> Android Model</a>
<a type="button" class="btn btn-sm btn-default" href="${reqNode.iosCodePath}"><i class="fa fa-apple" aria-hidden="true"></i> iOS Model</a>
</div>
</#if>
</#if>
</div>
<hr>
</#list>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
<script src="https://cdn.jsdelivr.net/autocomplete.js/0/autocomplete.jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/google-code-prettify@1.0.5/bin/prettify.min.js"></script>
<script>
var search_source_data = [
<#list controller.controllerNodes as ctrolNode>
<#list ctrolNode.requestNodes as reqNode>
{name: '${ctrolNode.description}.${reqNode.description}', url: '${reqNode.codeFileUrl}'},
</#list>
</#list>
];
$('.toggle-catalog').click(function () {
$('.book').toggleClass('with-summary');
});
$('#inputSearch').autocomplete({hint: false}, [
{
source: function (query, callback) {
var result = [];
for(var i = 0; i !== search_source_data.length; i++){
if(search_source_data[i].name.indexOf(query) !== -1){
result.push(search_source_data[i]);
}
}
callback(result);
},
displayKey: 'name',
templates: {
suggestion: function (suggestion) {
return suggestion.name;
}
}
}
]).on('autocomplete:selected', function (event, suggestion, dataset, context) {
self.location = suggestion.url;
});
</script>
</body>
</html>
style.css
body, html {
height: 100%;
}
.book{
position: relative;
width: 100%;
height: 100%;
}
.book.with-summary .book-summary {
left: 0;
}
.book-summary {
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-body {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
overflow-y: auto;
color: #333;
background: #fff;
-webkit-transition: left 250ms ease;
-moz-transition: left 250ms ease;
-o-transition: left 250ms ease;
transition: left 250ms ease;
}
.book-body .body-inner {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
overflow-y: auto;
padding-top: 10px;
}
.book-header {
overflow: visible;
height: 50px;
z-index: 2;
font-size: .85em;
color: #7e888b;
background: 0 0;
}
.book-header a.header-menu{
font-size: 18px;
color: #555555;
padding: 10px;
text-decoration: none;
}
.book-header a.header-menu:hover{
text-decoration: none;
color: #5cb85c;
}
.page-wrapper {
position: relative;
outline: 0;
}
.book .book-body .page-wrapper .page-inner {
position: relative;
left: 0px;
transition: 300ms ease left;
}
.page-inner {
position: relative;
max-width: 900px;
margin: 0 auto;
padding: 20px 15px 40px 15px;
}
@media (min-width: 600px){
.book.with-summary .book-body {
left: 300px;
}
}
@media (max-width: 600px){
.book-summary {
width: calc(100% - 60px);
bottom: 0;
left: -100%;
}
.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);
}
}
@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;
}
}
@media (max-width: 1240px){
.book-body .body-inner {
position: static;
min-height: calc(100% - 50px);
}
}
.navbar{
background: #5cb85c;
color: #FFF;
}
.navbar a{
color: #FFF;
}
.navbar-brand{
font-weight: 600;
}
@media (min-width: 768px){
.navbar {
border-radius: 0;
}
}
.catalog .panel{
margin-bottom: 0;
border-radius: 0;
border: none;
box-shadow: none;
-webkit-box-shadow: none;
}
.catalog .catalog-title {
border-bottom: 1px solid #EAEAEA;
padding: 1rem 1.25rem;
background: rgba(0,0,0,.075);
cursor: pointer;
color: #333;
font-weight: 600;
font-size: 16px;
}
.catalog .catalog-title-1 {
border-bottom: 1px solid #EAEAEA;
padding: 1rem 3.25rem;
background: rgba(0, 0, 0, .03);
cursor: pointer;
color: #777;
font-weight: 600;
font-size: 14px;
}
.catalog-item{
padding: 8px 15px;
margin-left: 30px;
color: #888;
border-bottom: solid #EEE 1px;
display: block;
}
.action-item h2 a{
color: #5cb85c;
}
a:hover{
color: #449d44;
}
.search-box{
position: relative;
margin: 10px;
}
.navbar{
margin-bottom: 0;
}
.main-content{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
margin-top: 20px;
}
/**third part*/
.algolia-autocomplete {
width: 100%;
}
.algolia-autocomplete .aa-input, .algolia-autocomplete .aa-hint {
width: 100%;
}
.algolia-autocomplete .aa-hint {
color: #888;
}
.algolia-autocomplete .aa-dropdown-menu {
width: 100%;
background-color: #fff;
border: 1px solid #EEE;
border-top: none;
}
.algolia-autocomplete .aa-dropdown-menu .aa-suggestion {
cursor: pointer;
padding: 5px 4px;
}
.algolia-autocomplete .aa-dropdown-menu .aa-suggestion.aa-cursor {
background-color: #449d44;
color: #FFF;
}
.algolia-autocomplete .aa-dropdown-menu .aa-suggestion em {
font-weight: bold;
font-style: normal;
}
/* Doxy pretty-printing styles. Used with prettify.js. */
pre .str, code .str { color: #fec243; } /* string - eggyolk gold */
pre .kwd, code .kwd { color: #8470FF; } /* keyword - light slate blue */
pre .com, code .com { color: #32cd32; font-style: italic; } /* comment - green */
pre .typ, code .typ { color: #6ecbcc; } /* type - turq green */
pre .lit, code .lit { color: #d06; } /* literal - cherry red */
pre .pun, code .pun { color: #8B8970; } /* punctuation - lemon chiffon4 */
pre .pln, code .pln { color: #f0f0f0; } /* plaintext - white */
pre .tag, code .tag { color: #9c9cff; } /* html/xml tag (bluey) */
pre .htm, code .htm { color: #dda0dd; } /* html tag light purply*/
pre .xsl, code .xsl { color: #d0a0d0; } /* xslt tag light purply*/
pre .atn, code .atn { color: #46eeee; font-weight: normal;} /* html/xml attribute name - lt turquoise */
pre .atv, code .atv { color: #EEB4B4; } /* html/xml attribute value - rosy brown2 */
pre .dec, code .dec { color: #3387CC; } /* decimal - blue */
a {
text-decoration: none;
}
pre.prettyprint, code.prettyprint {
font-family:'Droid Sans Mono','CPMono_v07 Bold','Droid Sans';
font-weight: bold;
font-size: 11pt;
background-color: #0f0f0f;
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
-o-border-radius: 8px;
-ms-border-radius: 8px;
-khtml-border-radius: 8px;
border-radius: 8px;
} /* background is black (well, just a tad less dark ) */
pre.prettyprint {
padding: 1em;
white-space: pre-wrap;
}
pre.prettyprint a, code.prettyprint a {
text-decoration:none;
}
/* Specify class=linenums on a pre to get line numbering; line numbers themselves are the same color as punctuation */
ol.linenums { margin-top: 0; margin-bottom: 0; color: #8B8970; } /* IE indents via margin-left */
li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8 { list-style-type: none }
/* Alternate shading for lines */
li.L1,li.L3,li.L5,li.L7,li.L9 { }
/* print is mostly unchanged from default at present */
@media print {
pre.prettyprint, code.prettyprint { background-color: #fff; }
pre .str, code .str { color: #088; }
pre .kwd, code .kwd { color: #006; font-weight: bold; }
pre .com, code .com { color: #oc3; font-style: italic; }
pre .typ, code .typ { color: #404; font-weight: bold; }
pre .lit, code .lit { color: #044; }
pre .pun, code .pun { color: #440; }
pre .pln, code .pln { color: #000; }
pre .tag, code .tag { color: #b66ff7; font-weight: bold; }
pre .htm, code .htm { color: #606; font-weight: bold; }
pre .xsl, code .xsl { color: #606; font-weight: bold; }
pre .atn, code .atn { color: #c71585; font-weight: normal; }
pre .atv, code .atv { color: #088; font-weight: normal; }
}