Java文档自动化生成
Java文档自动化生成
0. 问题
我们组作为基础数据组,很多服务大都是对外提供基础数据的操作, 接口非常多, 接入方也非常多。
现在提供接口文档的方式是 在wiki中开一个页面,用来手写这个服务的接口文档, 比如像下面这样:
package xxxx.xxxx
public interface XxxxSoaService {
/**
* 根据XxxID查询
*
* @param Xxxx参数
* @return Xxxx信息
*/
XxxxDTO getXxxxInfo(long Xxxx);
}
public class XxxxDTO {
/**
* XxxxID
*/
private long Xxxxx;
/**
* Xxxx名称
*/
private String name;
/**
* Xxxx有效无效状态
*/
private DataStatusDTO dataStatusDTO;
/**
* Xxxx类型
*/
private ShopTypeDTO shopTypeDTO;
}
public enum DataStatusDTO {
VALID(1, "有效"),
INVALID(0, "无效");
private int code;
private String description;
}
public enum ShopTypeDTO {
NORMAL(0, "正式"),
TEST(100, "测试");
private int code;
private String description;
}
每次给外部提供一个新接口,都要手写这些东西, 每次更新了接口信息,也要手动更新wiki里面的文档, 如果忘记更新了,那么就会坑别人。 着实费事!
1. 设想
如果每次编写完代码并提交代码后, 文档会自动生成到一个地方并且通过web的方式展现出来,那该多好, 以后的接口文档里面就可以写成这样子:
# 服务依赖说明
## ALPHA
## BETA
## PROD
# 服务集群说明
巴拉巴拉
# 包依赖
巴拉巴拉
# 接口定义
## XXXX功能接口
`xxxx.xxxx.XxxxSoaService.getXxxxInfo` 详情见下面JavaDoc
# JavaDoc
url: xxxxxxxx
只需要在文档里面给出服务依赖相关的内容, 和某个功能的接口是什么, 具体接口详情看javadoc就好了
期望具体生成文档的流程自动化成下面的样子
开发人员在个人PC上面push代码到gitlab, gitlab通知Server生成文档, server生成文档后部署页面,最终将web页面展现给个人PC
2. 研究
针对上面的问题,有几个点需要确认, 如果确认好下面这几个点, 整个流程就通了
2.1 push 代码到gitlab后,gitlab怎么将信号给到server?
这一点有两种办法:
一种是通过jenkins, 我之前也玩过,具体玩法可以参考以前写的一篇博客:http://int32.me/blog/2017/09/18/jenkins/, 这种玩法需要安装jenkins, 而且比较笨重
另一种是通过gitlab自带的CI/CD工具 runner, 具体什么是runner可以参考下面几篇文章:
- https://www.cnblogs.com/cnundefined/p/7095368.html
- https://blog.csdn.net/u011215669/article/details/80446624
- https://www.jianshu.com/p/306cf4c6789a
2.2 server接受到信号后怎么根据信号生成文档?
当server接受到信号后,怎么生成文档呢? 我最终选择javadoc形式, 但是javadoc必须要有java代码才能生成文档, 所以就好从gitlab上把java代码clone下来, 不过不需要担心这个, 因为 gitlab的CI/CD 和 jenkins都有这样的功能, 把代码clone到一个临时空间, 当执行完所有动作后便将代码删除。
那么新的问题来了, 如何根据java代码生成java doc, 这个也好解决, 因为我们项目都是gradle的项目, 所以根据gradle集成的doc命令就可以将java代码生成javadoc
2.3 生成文档后怎么将文档部署成web页面?
这个最终我选择了nginx, 因为javadoc是现成的html文档, 所以怎么将html文档显示出来就是要考虑的了, 而nginx正好能做到这一点。
在考虑这一问题的时候, 如果要简单方便, 就将生成的javadoc文档直接放在nginx读取的目录下就行了, 但是这块可以做的更好, 比如有所有文档根据 项目 → 分支 → 文档 的顺序存放,然后提供一个索引页面
这样每次生成文档, 都是生成在项目/分支下, 每个人的文档都不会相互冲突, 方便管理查看。 这个也有办法接口, 使用nginx天生的文件服务的功能。
3. 开做
3.1 找个服务器安装gitlab runner
这里只给出centos的安装方式
# 1 下载runner
` sudo wget -O /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64`
# 2 修改权限
`sudo chmod +x /usr/local/bin/gitlab-runner`
# 3 创建用户
`sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash`
# 4 安装server
`sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner`
# 5 起送runenr
`sudo gitlab-runner start`
# 6 注册runner
`sudo gitlab-runner register`
# 7 根据提示输入相关信息
这里url 和 token 可以在gitlab->Project->Settings->CI/CD -> runner信息中找到
3.2 将项目注册到自己的runner上
上面runner注册成功后, 便能发现自己的项目上会出现刚刚注册的runner
3.3 修改gradle文件, 方便生成javadoc
configurations {
doc {
transitive false
}
}
javadoc {
options.charSet = 'UTF-8'
source configurations.doc.collect { zipTree(it) }
options.memberLevel = JavadocMemberLevel.PRIVATE
include '**/*.java'
options.addStringOption('Xdoclint:none', '-quiet')
}
将api模块(如果么有api模块,在总项目目录下配置即可)中的 build.gradle 文件增加如上内容。
增加之后, 进入该模块目录,运行 gradle javadoc 看下是否可以生成javadoc文件
3.4 将生成文档的步骤自动化起来
上面的步骤都完成后,我们就开始想办法把生成文档的步骤自动化起来:
在项目根目录下增加 .gitlab-ci.yml, 内容如下:
stages:
- gendoc
genJavaDoc:
stage: gendoc
script:
- "ls -al"
- "export APPID=appid_xx" # appid_xx 唯一标示 可以修改成自己的
- "export API_PATH=api_modle" # api_modle api模块的路径 根据自己项目填写
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# No need to change the following Env Variables
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- "export ROOT_FOLDER=/data/javadoc" #javadoc的根目录
- "export PROJECT_FOLDER=$ROOT_FOLDER/$APPID" # 项目目录
- "export CURRENT_GIT_BRANCH=$CI_BUILD_REF_NAME" # 当前分支
- "export TARGET_DOC_FOLDER=$PROJECT_FOLDER/${CURRENT_GIT_BRANCH//\\//-}" # 文档目录 我把分支中的/替换成了-
- "cd $API_PATH" # 进入api模块的路径
- "gradle clean javadoc" # 运行 gradle clean javadoc 生成文档
- "mkdir -p $TARGET_DOC_FOLDER"
- "rm -rf $TARGET_DOC_FOLDER/*"
- "mv ./build/docs/javadoc/* $TARGET_DOC_FOLDER" # 把生成出来的文档移动到对应的文档目录
tags:
- gc-java-doc
配置完这些, 基本可以做到 对这个项目push代码, 然后会在服务器对应的目录下生成文档了,但是还不能被查看到
3.5 配置nginx文件服务
server {
listen 80;
autoindex on; # 开启文件目录索引
autoindex_exact_size on; # 展示文件大小
autoindex_localtime on; # 展示文件时间
location / {
root /data/javadoc/; # 目录
}
}
现在的页面应该长这个样子
3.6 构建一个索引界面
我们做个页面优化下:
在doc根目录 /data/javadoc 下面建立 index.html.template
这个文件, 内容如下
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- import CSS -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
<div id="app">
<el-container>
<el-header class="doc-header" height="150px">
<div class="header-title">
店铺信息组JavaDoc
</div>
<div class="header-desc">
</div>
</el-header>
<div class="spilt-line"></div>
<el-container>
<div class="appid">
<el-aside width="300px">
<el-menu :default-active="activityIndex" class="el-menu-vertical-demo" v-for="(item, index) in file_dir" @select="handleSelect">
<el-menu-item :index="index+''">
<i class="el-icon-menu"></i>
<span slot="title"></span>
</el-menu-item>
</el-menu>
</el-aside>
</div>
<div class="appid_branch">
<el-main>
<el-table :data="activity_appid_branch_info" style="width: 100%">
<el-table-column label="分支" >
<template class="branc_name" slot-scope="scope">
<a :href="activity_appid_info+'/'+scope.row.name"></a>
</template>
</el-table-column>
</el-table>
</el-main>
</div>
</el-container>
</el-container>
</div>
</body>
<!-- import Vue before Element -->
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<!-- import JavaScript -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script>
new Vue({
el: '#app',
data: function() {
return {
file_dir: GC_JAVA_DOC_FILE_DIR,
activityIndex: '0'
}
},
computed: {
activity_appid_branch_info: function () {
console.log(this.activityIndex)
return this.file_dir[parseInt(this.activityIndex)]['branch']
},
activity_appid_info: function() {
console.log(this.activityIndex)
return this.file_dir[parseInt(this.activityIndex)]['appid']
}
},
methods: {
handleSelect(key, keyPath) {
this.activityIndex = key+''
}
}
})
</script>
<style scop>
#app {
width: 100%;
}
.spilt-line {
height: 1px;
width: 100%;
background-color: #e6e6e6;
margin: 0px 0px 30px 0px;
}
.doc-header {
margin: 10px;
position: relative;
}
.header-title {
text-align: center;
font-size: 30px;
}
.header-desc {
font-size: 15px;
position: absolute;
bottom: 0px;
}
.appid_branch {
width: 100%;
text-align: center;
}
.branc_name {
width: 100%;
text-align: center;
}
el-table-column {
font-size: 100px;
width: 100%;
text-align: center;
}
</style>
</html>
再加一个replace_template.py
文件, 内容如下:
#! -*- coding:utf8 -*-
import sys
import os
import json
reload(sys)
sys.setdefaultencoding("utf-8")
def replace(file_dir):
index_template_file = open("index.html.template", "r")
index_file = open("index.html", "w+")
print 'relace:', file_dir
while True:
line = index_template_file.readline()
if not line or len(line) < 1:
break
line = line.replace("GC_JAVA_DOC_FILE_DIR", json.dumps(file_dir))
index_file.write(line)
index_file.flush()
def list_dir(root_path):
'''
build dir struct
'''
result = []
file_names = os.listdir(root_path)
for file_name in file_names:
file_path = root_path + '/' + file_name
if os.path.isdir(file_path):
one_info = {}
one_info['appid'] = file_name
one_info['branch'] = []
child_file_names = os.listdir(file_path)
for child_file_name in child_file_names:
one_info['branch'].append({"name": child_file_name})
result.append(one_info)
return result
if __name__ == "__main__":
file_dir = list_dir('.')
replace(file_dir)
然后修改 .gitlab-ci.yml
stages:
- gendoc
genJavaDoc:
stage: gendoc
script:
- "ls -al"
- "export APPID=appid_xx" # appid_xx 唯一标示 可以修改成自己的
- "export API_PATH=api_modle" # api_modle api模块的路径 根据自己项目填写
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# No need to change the following Env Variables
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- "export ROOT_FOLDER=/data/javadoc" #javadoc的根目录
- "export PROJECT_FOLDER=$ROOT_FOLDER/$APPID" # 项目目录
- "export CURRENT_GIT_BRANCH=$CI_BUILD_REF_NAME" # 当前分支
- "export TARGET_DOC_FOLDER=$PROJECT_FOLDER/${CURRENT_GIT_BRANCH//\\//-}" # 文档目录 我把分支中的/替换成了-
- "cd $API_PATH" # 进入api模块的路径
- "gradle clean javadoc" # 运行 gradle clean javadoc 生成文档
- "mkdir -p $TARGET_DOC_FOLDER"
- "rm -rf $TARGET_DOC_FOLDER/*"
- "mv ./build/docs/javadoc/* $TARGET_DOC_FOLDER" # 把生成出来的文档移动到对应的文档目录
- "cd $ROOT_FOLDER" # 进入项目根目录
- "python replace_template.py" # 运行这个python脚本
tags:
- gc-java-doc
好大功告成,看下面的结果