编写文档

This commit is contained in:
tanghc
2019-03-23 18:01:48 +08:00
parent 1c97e7f28e
commit 08bf664117
42 changed files with 968 additions and 33 deletions

9
doc/README.md Normal file
View File

@@ -0,0 +1,9 @@
# 开发文档
配合gitee pages服务使用gitee pages服务指定docs目录。
## 本地查看开发文档
- 前提先安装好npm[npm安装教程](https://blog.csdn.net/zhangwenwu2/article/details/52778521)。建议使用淘宝镜像。
- 安装docsify执行npm命令`npm i docsify-cli -g --registry=https://registry.npm.taobao.org`
- cd到当前目录运行命令`docsify serve docs`,然后访问:`http://localhost:3000`即可查看。

1
doc/docs/README.md Normal file
View File

@@ -0,0 +1 @@
# 开发文档

1
doc/docs/_config.yml Normal file
View File

@@ -0,0 +1 @@
include: [_navbar,_sidebar]

12
doc/docs/_coverpage.md Normal file
View File

@@ -0,0 +1,12 @@
![logo](_media/icon.svg)
# docsify <small>4.6.10</small>
> A magical documentation site generator.
* Simple and lightweight (~19kB gzipped)
* No statically built html files
* Multiple themes
[GitHub](https://github.com/QingWei-Li/docsify/)
[Get Started](#docsify)

3
doc/docs/_navbar.md Normal file
View File

@@ -0,0 +1,3 @@
- 关于
- [帮助](/zh-cn/)
- [API](/)

6
doc/docs/_sidebar.md Normal file
View File

@@ -0,0 +1,6 @@
* 文档目录
* [错误处理](files/1004_错误处理.md?t=1553335182242)
* [新增接口](files/1002_新增接口.md?t=1553335182268)
* [快速体验](files/1001_快速体验.md?t=1553335182268)
* [业务参数校验](files/1003_业务参数校验.md?t=1553335182268)

View File

@@ -0,0 +1,20 @@
# 快速体验
> 运行环境JDK8Maven3Zookeeper
- 安装并启动zookeeper[安装教程](http://zookeeper.apache.org/doc/r3.4.13/zookeeperStarted.html)
- IDE打开项目(IDEA下可以打开根pom.xml然后open as project)
- 启动注册中心sop-registry运行SopRegistryApplication.java
- 启动微服务sop-story-web(运行SopStoryApplication.java)
- 启动网关sop-gateway运行SopGatewayApplication.java
- 找到sop-test打开测试用例进行接口调用测试运行com.gitee.sop.AlipayClientPostTest.testPost()
确保注册中心先启动
## 使用admin
- 找到`sop-admin/sop-admin-server`工程,运行`com.gitee.sop.adminserver.SopAdminServerApplication.java`
- 找到`sop-admin/sop-admin-front/index.html`文件在IDEA下直接右键--Run'index.html'
- 如果没有用到IDEA则需要把sop-admin-front放到静态服务器中然后访问index.html

View File

@@ -0,0 +1,140 @@
# 新增接口
以story服务为例新增一个获取故事内容接口
- 在controller下新建一个类StoryDemoController.java
- 加上`@RestController`注解
```java
@RestController
public class StoryDemoController {
}
```
- 新增一个接口
```java
@ApiMapping(value = "story.demo.get")
public Story getStory() {
Story story = new Story();
story.setId(1);
story.setName("白雪公主");
return story;
}
```
这里的`@ApiMapping`注解作用同`@RequestMapping`注解,可以理解为是它的扩展
value就是接口名对应客户端的`method`参数
如果要加上版本号,指定`version`参数:`@ApiMapping(value = "story.demo.get", version = "2.0")`
- 重启story服务这样接口就可以使用了。
## 测试接口
- 在sop-test工程下新建一个测试用例`StoryDemoTest`继承TestBase
```java
public class StoryDemoTest extends TestBase {
String url = "http://localhost:8081/api"; // zuul
String appId = "alipay_test";
// 私钥
String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXJv1pQFqWNA/++OYEV7WYXwexZK/J8LY1OWlP9X0T6wHFOvxNKRvMkJ5544SbgsJpVcvRDPrcxmhPbi/sAhdO4x2PiPKIz9Yni2OtYCCeaiE056B+e1O2jXoLeXbfi9fPivJZkxH/tb4xfLkH3bA8ZAQnQsoXA0SguykMRZntF0TndUfvDrLqwhlR8r5iRdZLB6F8o8qXH6UPDfNEnf/K8wX5T4EB1b8x8QJ7Ua4GcIUqeUxGHdQpzNbJdaQvoi06lgccmL+PHzminkFYON7alj1CjDN833j7QMHdPtS9l7B67fOU/p2LAAkPMtoVBfxQt9aFj7B8rEhGCz02iJIBAgMBAAECggEARqOuIpY0v6WtJBfmR3lGIOOokLrhfJrGTLF8CiZMQha+SRJ7/wOLPlsH9SbjPlopyViTXCuYwbzn2tdABigkBHYXxpDV6CJZjzmRZ+FY3S/0POlTFElGojYUJ3CooWiVfyUMhdg5vSuOq0oCny53woFrf32zPHYGiKdvU5Djku1onbDU0Lw8w+5tguuEZ76kZ/lUcccGy5978FFmYpzY/65RHCpvLiLqYyWTtaNT1aQ/9pw4jX9HO9NfdJ9gYFK8r/2f36ZE4hxluAfeOXQfRC/WhPmiw/ReUhxPznG/WgKaa/OaRtAx3inbQ+JuCND7uuKeRe4osP2jLPHPP6AUwQKBgQDUNu3BkLoKaimjGOjCTAwtp71g1oo+k5/uEInAo7lyEwpV0EuUMwLA/HCqUgR4K9pyYV+Oyb8d6f0+Hz0BMD92I2pqlXrD7xV2WzDvyXM3s63NvorRooKcyfd9i6ccMjAyTR2qfLkxv0hlbBbsPHz4BbU63xhTJp3Ghi0/ey/1HQKBgQC2VsgqC6ykfSidZUNLmQZe3J0p/Qf9VLkfrQ+xaHapOs6AzDU2H2osuysqXTLJHsGfrwVaTs00ER2z8ljTJPBUtNtOLrwNRlvgdnzyVAKHfOgDBGwJgiwpeE9voB1oAV/mXqSaUWNnuwlOIhvQEBwekqNyWvhLqC7nCAIhj3yvNQKBgQCqYbeec56LAhWP903Zwcj9VvG7sESqXUhIkUqoOkuIBTWFFIm54QLTA1tJxDQGb98heoCIWf5x/A3xNI98RsqNBX5JON6qNWjb7/dobitti3t99v/ptDp9u8JTMC7penoryLKK0Ty3bkan95Kn9SC42YxaSghzqkt+uvfVQgiNGQKBgGxU6P2aDAt6VNwWosHSe+d2WWXt8IZBhO9d6dn0f7ORvcjmCqNKTNGgrkewMZEuVcliueJquR47IROdY8qmwqcBAN7Vg2K7r7CPlTKAWTRYMJxCT1Hi5gwJb+CZF3+IeYqsJk2NF2s0w5WJTE70k1BSvQsfIzAIDz2yE1oPHvwVAoGAA6e+xQkVH4fMEph55RJIZ5goI4Y76BSvt2N5OKZKd4HtaV+eIhM3SDsVYRLIm9ZquJHMiZQGyUGnsvrKL6AAVNK7eQZCRDk9KQz+0GKOGqku0nOZjUbAu6A2/vtXAaAuFSFx1rUQVVjFulLexkXR3KcztL1Qu2k5pB6Si0K/uwQ=";
@Test
public void testDemo() throws Exception {
// 公共请求参数
Map<String, String> params = new HashMap<String, String>();
params.put("app_id", appId);
// 这里对应@ApiMapping.value属性
params.put("method", "story.demo.get");
params.put("format", "json");
params.put("charset", "utf-8");
params.put("sign_type", "RSA2");
params.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
// 这里对应@ApiMapping.version属性
params.put("version", "1.0");
// 业务参数
Map<String, String> bizContent = new HashMap<>();
params.put("biz_content", JSON.toJSONString(bizContent));
System.out.println("----------- 请求信息 -----------");
System.out.println("请求参数:" + buildParamQuery(params));
System.out.println("商户秘钥:" + privateKey);
String content = AlipaySignature.getSignContent(params);
System.out.println("待签名内容:" + content);
String sign = AlipaySignature.rsa256Sign(content, privateKey, "utf-8");
System.out.println("签名(sign)" + sign);
params.put("sign", sign);
System.out.println("----------- 返回结果 -----------");
String responseData = post(url, params);// 发送请求
System.out.println(responseData);
}
}
```
- 请求成功后,控制台会打印:
```
----------- 请求信息 -----------
请求参数charset=utf-8&biz_content={}&method=story.demo.get&format=json&app_id=alipay_test&sign_type=RSA2&version=1.0&timestamp=2019-03-23 15:41:22
商户秘钥MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXJv1pQFqWNA/++OYEV7WYXwexZK/J8LY1OWlP9X0T6wHFOvxNKRvMkJ5544SbgsJpVcvRDPrcxmhPbi/sAhdO4x2PiPKIz9Yni2OtYCCeaiE056B+e1O2jXoLeXbfi9fPivJZkxH/tb4xfLkH3bA8ZAQnQsoXA0SguykMRZntF0TndUfvDrLqwhlR8r5iRdZLB6F8o8qXH6UPDfNEnf/K8wX5T4EB1b8x8QJ7Ua4GcIUqeUxGHdQpzNbJdaQvoi06lgccmL+PHzminkFYON7alj1CjDN833j7QMHdPtS9l7B67fOU/p2LAAkPMtoVBfxQt9aFj7B8rEhGCz02iJIBAgMBAAECggEARqOuIpY0v6WtJBfmR3lGIOOokLrhfJrGTLF8CiZMQha+SRJ7/wOLPlsH9SbjPlopyViTXCuYwbzn2tdABigkBHYXxpDV6CJZjzmRZ+FY3S/0POlTFElGojYUJ3CooWiVfyUMhdg5vSuOq0oCny53woFrf32zPHYGiKdvU5Djku1onbDU0Lw8w+5tguuEZ76kZ/lUcccGy5978FFmYpzY/65RHCpvLiLqYyWTtaNT1aQ/9pw4jX9HO9NfdJ9gYFK8r/2f36ZE4hxluAfeOXQfRC/WhPmiw/ReUhxPznG/WgKaa/OaRtAx3inbQ+JuCND7uuKeRe4osP2jLPHPP6AUwQKBgQDUNu3BkLoKaimjGOjCTAwtp71g1oo+k5/uEInAo7lyEwpV0EuUMwLA/HCqUgR4K9pyYV+Oyb8d6f0+Hz0BMD92I2pqlXrD7xV2WzDvyXM3s63NvorRooKcyfd9i6ccMjAyTR2qfLkxv0hlbBbsPHz4BbU63xhTJp3Ghi0/ey/1HQKBgQC2VsgqC6ykfSidZUNLmQZe3J0p/Qf9VLkfrQ+xaHapOs6AzDU2H2osuysqXTLJHsGfrwVaTs00ER2z8ljTJPBUtNtOLrwNRlvgdnzyVAKHfOgDBGwJgiwpeE9voB1oAV/mXqSaUWNnuwlOIhvQEBwekqNyWvhLqC7nCAIhj3yvNQKBgQCqYbeec56LAhWP903Zwcj9VvG7sESqXUhIkUqoOkuIBTWFFIm54QLTA1tJxDQGb98heoCIWf5x/A3xNI98RsqNBX5JON6qNWjb7/dobitti3t99v/ptDp9u8JTMC7penoryLKK0Ty3bkan95Kn9SC42YxaSghzqkt+uvfVQgiNGQKBgGxU6P2aDAt6VNwWosHSe+d2WWXt8IZBhO9d6dn0f7ORvcjmCqNKTNGgrkewMZEuVcliueJquR47IROdY8qmwqcBAN7Vg2K7r7CPlTKAWTRYMJxCT1Hi5gwJb+CZF3+IeYqsJk2NF2s0w5WJTE70k1BSvQsfIzAIDz2yE1oPHvwVAoGAA6e+xQkVH4fMEph55RJIZ5goI4Y76BSvt2N5OKZKd4HtaV+eIhM3SDsVYRLIm9ZquJHMiZQGyUGnsvrKL6AAVNK7eQZCRDk9KQz+0GKOGqku0nOZjUbAu6A2/vtXAaAuFSFx1rUQVVjFulLexkXR3KcztL1Qu2k5pB6Si0K/uwQ=
待签名内容app_id=alipay_test&biz_content={}&charset=utf-8&format=json&method=story.demo.get&sign_type=RSA2&timestamp=2019-03-23 15:41:22&version=1.0
签名(sign)YMbxTPdovi6htcn1K3USTS6/Tbg6MOAMigG6x/kG0kQFCYH8ljvxXzcY86UT056nUG3OXxnj0xkw07eV6E03HMlu7bn3/jrT3PCcV3YguhA92aWz720x2xJWdfXY13OUPS9VOCC9zIVxu6EBD+PoZ7ojYChYvOfCR5I8bR/oOc0ZLjK63PWTBdf0eFS4sybXzRf81uNLMROsMhmBDDy0Fhml3ml77qzWBIpsmq5ECZ+89rMPbkNhAUcnFAe7ik7xZIL6WcUhAOhKVa8ZQK1GMjoGnAbGRed1FbuOHZGubgffg4/vMqrY10Bcy6h9jt/zK5w9L3HVgK3aPgQlfP16Gg==
----------- 返回结果 -----------
{"story_demo_get_response":{"msg":"Success","code":"10000","name":"白雪公主","id":1},"sign":"YMbxTPdovi6htcn1K3USTS6/Tbg6MOAMigG6x/kG0kQFCYH8ljvxXzcY86UT056nUG3OXxnj0xkw07eV6E03HMlu7bn3/jrT3PCcV3YguhA92aWz720x2xJWdfXY13OUPS9VOCC9zIVxu6EBD+PoZ7ojYChYvOfCR5I8bR/oOc0ZLjK63PWTBdf0eFS4sybXzRf81uNLMROsMhmBDDy0Fhml3ml77qzWBIpsmq5ECZ+89rMPbkNhAUcnFAe7ik7xZIL6WcUhAOhKVa8ZQK1GMjoGnAbGRed1FbuOHZGubgffg4/vMqrY10Bcy6h9jt/zK5w9L3HVgK3aPgQlfP16Gg=="}
```
## 开放现有接口
如果想把现有项目中的接口开放出去,提供给客户调用,具体操作如下:
以springboot项目为例springmvc目前暂不支持以后可以支持。
- 将现有项目注册到注册中心
- 在现有接口方法上加上一个注解`@ApiAbility`,如下面这个接口
```java
// 遗留接口具备开放平台能力
@ApiAbility
@RequestMapping("getStory2")
public Story getStory2_0() {
Story story = new Story();
story.setId(1);
story.setName("海底小纵队(默认版本号)");
return story;
}
```
这种情况下,老接口依然能正常访问,同时开放平台也能访问进来。
**注意** 此时的开放接口对应的接口名为:类@RequestMapping.value + "." + 方法@RequestMapping.value
举个列子:
```java
@RequestMapping("goods")
public class MyController {
@ApiAbility
@RequestMapping("listGoods")
public Object fun() {
}
}
```
fun接口对应的路径为`/goods/listGoods`
那么对应开放平台的接口名会转换成:`goods.listGoods`客户端的method参数要填`goods.listGoods`
当然也可以直接把@RequestMapping替换成`@ApiMapping`并指定接口名,这样的话不能兼容以前的访问形式。

View File

@@ -0,0 +1,72 @@
# 业务参数校验
业务参数校验采用JSR-303方式关于JSR-303介绍可以参考这篇博文[JSR 303 - Bean Validation 介绍及最佳实践](https://www.ibm.com/developerworks/cn/java/j-lo-jsr303/)
在参数中使用注解即可框架会自动进行验证。如下面一个添加商品接口它的参数是GoodsParam
```java
@ApiMapping(value = "goods.add")
public void addGoods(GoodsParam param) {
...
}
```
在GoodsParam中添加JSR-303注解:
```java
@Data
public class GoodsParam {
@NotEmpty(message = "商品名称不能为空")
private String goods_name;
}
```
如果不传商品名称则返回
```
{"goods_add_response":{"msg":"Success","code":"10000","sub_msg":"商品名称不能为空","sub_code":"isv.invalid-parameter"},"sign":"Eh3Z5CxDCHsb4MyYFVxsPSmBpwVi1LISJdOkrzglxXoqG7RVyEOt4ef1kNpznUvMI3FDQU1suR7Rsmx6NjGdEVS6NSH2Kt0d8TFBRpLhWz8hApnxOtgzqMqbYeMuJie7X5gF6m8hTnvuuxF21IrkixMe+lyBcXw7dk0C3w1SwdEZkHQ+xC+M4bLqAZt5/3kl79/FWSMFJWHiZmg5YeEi8e8XhYCNcz+xlJRJL0x2Y87fFxqSY0UYWNxbQHgdVI8xRfn1n31nzkcLxiAtTh4LPtNRrG7w7absK/C1Oi/vczuBlFeq2EWUsYVWOVpKiJifUwvYVUUsztSLElzplzOjbg=="}
```
## 参数校验国际化
国际化的配置方式如下:
```java
@NotEmpty(message = "{goods.remark.notNull}")
private String goods_remark;
```
国际化资源文件`bizerror_en.properties`中添加:
```
goods.remark.notNull=The goods_remark can not be null
```
bizerror_zh_CN.properties中添加
```
# 商品备注不能为空
goods.remark.notNull=\u5546\u54c1\u5907\u6ce8\u4e0d\u80fd\u4e3a\u7a7a
```
## 参数校验国际化传参
下面校验商品评论的长度要求大于等于3且小于等于20。数字3和20要填充到国际化资源中去。
```
// 传参的格式:{xxx}=value1,value2...
@Length(min = 3, max = 20, message = "{goods.comment.length}=3,20")
private String goods_comment;
```
bizerror_en.properties:
```
goods.comment.length=The goods_comment length must >= {0} and <= {1}
```
bizerror_zh_CN.properties中添加
```
# 商品评论长度必须在{0}和{1}之间
goods.comment.length=\u5546\u54c1\u8bc4\u8bba\u957f\u5ea6\u5fc5\u987b\u5728{0}\u548c{1}\u4e4b\u95f4
```
这样value1value2会分别填充到{0},{1}中

View File

@@ -0,0 +1,91 @@
# 错误处理
SOP对错误处理已经封装好了简单做法是`throw ServiceException`在最顶层的Controller会做统一处理。例如
```java
if(StringUtils.isEmpty(param.getGoods_name())) {
throw new ServiceException("goods_name不能为null");
}
```
为了保证编码风格的一致性推荐统一使用ServiceException
## i18n国际化
SOP支持国际化消息。通过Request对象中的getLocale()来决定具体返回那种语言客户端通过设置Accept-Language头部来决定返回哪种语言中文是zh英文是en。
SOP通过模块化来管理国际化消息这样做的好处结构清晰维护方便。下面就来讲解如何设置国际化消息。
以story服务为例假设我们要对商品模块进行设置步骤如下
-`resource/i18n/isp`目录下新建goods_error_zh_CN.properties属性文件
属性文件的文件名有规律, **i18n/isp/goods_error** 表示模块路径, **_zh_CN.properties** 表示中文错误消息。如果要使用英文错误,则新建一个`goods_error_en.properties`即可。
- 在goods_error_zh_CN.properties中配置错误信息
```
# 商品名字不能为空
isp.goods_error_100=\u5546\u54C1\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
```
isp.goods_error_为固定前缀100为错误码这两个值后续会用到。
接下来是把属性文件加载到国际化容器当中。
- 添加国际化配置在OpenServiceConfig中的static块中添加代码如下
```java
@Configuration
public class OpenServiceConfig extends AlipayServiceConfiguration {
static {
ServiceConfig.getInstance().getI18nModules().add("i18n/isp/goods_error");
}
}
```
- 新建一个枚举用来定义错误
```java
// 按模块来定义异常消息,团队开发可以分开进行
public enum GoodsErrorEnum {
/** 参数错误 */
NO_GOODS_NAME("100"),
;
private ServiceErrorMeta errorMeta;
StoryErrorEnum(String subCode) {
this.errorMeta = new ServiceErrorMeta("isp.goods_error_", subCode);
}
public ServiceErrorMeta getErrorMeta() {
return errorMeta;
}
}
```
接下来就可以使用了
```java
if (StringUtils.isEmpty(param.getGoods_name())) {
throw GoodsErrorEnum.NO_GOODS_NAME.getErrorMeta().getException();
}
```
### 国际化消息传参
即代码中变量传入到properties文件中去做法是采用{0},{1}占位符。0代表第一个参数1表示第二个参数。
```
# 商品名称太短,不能小于{0}个字
isp.goods_error_101=\u5546\u54C1\u540D\u79F0\u592A\u77ED\uFF0C\u4E0D\u80FD\u5C0F\u4E8E{0}\u4E2A\u5B57
```
```java
if (param.getGoods_name().length() <= 3) {
throw GoodsErrorEnum.LESS_GOODS_NAME_LEN.getErrorMeta().getException(3);
}
```
直接放进getException(Object... params)方法参数中,因为是可变参数,可随意放。

68
doc/docs/index.html Normal file
View File

@@ -0,0 +1,68 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SOP开发文档</title>
<link rel="icon" href="_media/favicon.ico">
<meta name="google-site-verification" content="6t0LoIeFksrjF4c9sqUEsVXiQNxLp2hgoqo0KryT-sE" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="keywords" content="doc,docs,documentation,gitbook,creator,generator,github,jekyll,github-pages">
<meta name="description" content="A magical documentation generator.">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css" title="vue" >
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/dark.css" title="dark" disabled>
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/buble.css" title="buble" disabled>
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/pure.css" title="pure" disabled>
<style>
nav.app-nav li ul {
min-width: 100px;
}
/* 显示区域宽度 */
.markdown-section{
max-width: 90%;
}
.sidebar li {
margin: 0px 0;
}
</style>
</head>
<body>
<div id="app">加载中 ...</div>
<script>
window.$docsify = {
auto2top: true,
coverpage: false,
executeScript: true,
loadSidebar: true,
loadNavbar: false,
mergeNavbar: true,
maxLevel: 4,
subMaxLevel: 2,
ga: 'UA-106147152-1',
name: '',
search: {
noData: {
'/zh-cn/': '没有结果!',
'/': '没有结果!'
},
paths: 'auto',
placeholder: {
'/zh-cn/': '搜索',
'/': '搜索'
}
},
formatUpdated: '{MM}/{DD} {HH}:{mm}'
}
</script>
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
<script src="//unpkg.com/docsify/lib/plugins/ga.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-markdown.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-java.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-json.min.js"></script>
</body>
</html>

View File

49
doc/pom.xml Normal file
View File

@@ -0,0 +1,49 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gitee.sop</groupId>
<artifactId>doc</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<!-- Generic properties -->
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 打包时跳过测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>

1
doc/run.sh Normal file
View File

@@ -0,0 +1 @@
docsify serve docs

55
doc/server.js Normal file
View File

@@ -0,0 +1,55 @@
const liveServer = require('live-server')
const isSSR = !!process.env.SSR
const middleware = []
if (isSSR) {
const Renderer = require('./packages/docsify-server-renderer/build.js')
const renderer = new Renderer({
template: `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>docsify</title>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="/themes/vue.css" title="vue">
</head>
<body>
<!--inject-app-->
<!--inject-config-->
<script src="/lib/docsify.js"></script>
</body>
</html>`,
config: {
name: 'docsify',
repo: 'docsifyjs/docsify',
basePath: 'https://docsify.js.org/',
loadNavbar: true,
loadSidebar: true,
subMaxLevel: 3,
auto2top: true,
alias: {
'/de-de/changelog': '/changelog',
'/zh-cn/changelog': '/changelog',
'/changelog':
'https://raw.githubusercontent.com/docsifyjs/docsify/master/CHANGELOG'
}
},
path: './'
})
middleware.push(function(req, res, next) {
if (/\.(css|js)$/.test(req.url)) {
return next()
}
renderer.renderToString(req.url).then(html => res.end(html))
})
}
const params = {
port: 3000,
watch: ['lib', 'docs', 'themes'],
middleware
}
liveServer.start(params)

View File

@@ -0,0 +1,39 @@
package com.gitee.sop.doc;
import java.io.File;
import java.io.FileOutputStream;
/**
* 生成_sidebar.md文件直接运行即可
* @author tanghc
*/
public class SidebarTest {
static String format = " * [%s](files/%s?t=%s)\r\n";
static String sidebar_format = "* 文档目录\r\n\r\n%s";
public static void main(String[] args) throws Exception {
String path = SidebarTest.class.getClassLoader().getResource("").getPath();
String root = path.substring(0, path.indexOf("doc")) + "doc";
String fileDir = root + "/docs/files";
File dir = new File(fileDir);
File[] files = dir.listFiles();
StringBuilder output = new StringBuilder();
for (File file : files) {
String filename = file.getName();
String title = filename.substring(filename.indexOf("_") + 1, filename.length() - 3);
String line = String.format(format, title, filename, System.currentTimeMillis());
output.append(line);
}
String sidebarContent = String.format(sidebar_format, output.toString());
System.out.println(sidebarContent);
String sidebarFilepath = root + "/docs/_sidebar.md";
FileOutputStream out = new FileOutputStream(new File(sidebarFilepath));
out.write(sidebarContent.getBytes());
out.close();
}
}