背景介绍
在进行前后端分离式开发项目过程中, 需要有效的沟通. 接口文档因为更新的不及时, 也难免存在错误, 使沟通的成本大大增加. 因此, 业界就出现了一些根据代码自动生成 Restful API 文档的开源项目, 与 Spring Boot 结合比较好的是 Swagger2,Swagger2 通过读取 Controller 代码中的注解信息, 来自动生成 API 文档, 可以节省大量的手工编写文档的工作量. 我之前也是用的 Swagger2, 但发现 Swagger2 也有好多地方用得不爽, 如注解非常臃肿, 页面排版不太友好. 想学习使用 Swagger2 的请参考 Spring-Boot - 项目中使用 Swagger2.Api2Doc 专注于 Restful API 文档的自动生成, 它的原理与 Swagger2 是类似的, 都是通过反射, 分析 Controller 中的信息生成文档, 但它要比 Swagger2 好很多, 最大的不同是 Api2Doc 比 Swagger2 要少写很多代码.
使用 Api2Doc
创建 SpringBoot 工程
具体创建步骤略, 可参考使用 STS 创建 Spring-Boot - 项目.
在工程中引入 Maven 依赖
- <dependency>
- <groupId>com.GitHub.terran4j</groupId>
- <artifactId>terran4j-commons-api2doc</artifactId>
- <version>1.0.2</version>
- </dependency>
启用 Api2Doc 服务
在有 @SpringBootApplication 注解的类上, 添加 @EnableApi2Doc
注解, 以启用 Api2Doc 服务.
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import com.terran4j.commons.api2doc.config.EnableApi2Doc;
- @EnableApi2Doc
- @SpringBootApplication
- public class Application {
- public static void main(String[] args) {
- SpringApplication.run(Application.class, args);
- }
- }
具体示例
给 Controller 类上添加文档注解
- package cn.com.yd.exam.controller;
- import java.util.List;
- import org.springframework.web.bind.annotation.DeleteMapping;
- import org.springframework.Web.bind.annotation.GetMapping;
- import org.springframework.Web.bind.annotation.PathVariable;
- import org.springframework.Web.bind.annotation.PostMapping;
- import org.springframework.Web.bind.annotation.RequestMapping;
- import org.springframework.Web.bind.annotation.RequestParam;
- import org.springframework.Web.bind.annotation.RestController;
- import com.terran4j.commons.api2doc.annotations.Api2Doc;
- import com.terran4j.commons.api2doc.annotations.ApiComment;
- import com.terran4j.commons.api2doc.annotations.ApiError;
- import cn.com.yd.exam.bean.User;
- import cn.com.yd.exam.bean.UserType;
- @Api2Doc(id = "demo1", name = "用户接口", order = 1)
- @ApiComment(seeClass = User.class)
- @RestController
- @RequestMapping(value = "/apis/v1/demo/users")
- public class UserController {
- @Api2Doc(order = 1)
- @ApiComment("添加一个新的用户.")
- @ApiError(value = "user.exists", comment = "此用户已经存在!")
- @PostMapping(name = "新增用户",value="")
- public User addUser(
- @ApiComment("用户所在部门名称") @RequestParam(required = true) String dept,
- @ApiComment("用户名称") @RequestParam(required = true) String name,
- @ApiComment("用户密码") @RequestParam(required = true) String password,
- @ApiComment("用户类型") @RequestParam(required = true) UserType type) {
- User user = new User();
- user.setDept(dept).setName(name).setPassword(password).setType(type);
- return user; // TODO: 还未实现.
- }
- @Api2Doc(order = 2)
- @ApiComment("根据用户 id, 删除指定的用户")
- @ApiError(value = "user.not.found", comment = "此用户不存在!")
- @ApiError(value = "admin.cant.delete", comment = "不允许删除管理员用户!")
- @DeleteMapping(name = "删除指定用户", value = "/{id}")
- public void delete(@PathVariable("id") Long id) {
- }
- @Api2Doc(order = 3)
- @ApiComment("根据用户 id, 查询此用户的信息")
- @ApiError(value = "user.not.found", comment = "此用户不存在!")
- @GetMapping(name = "查询单个用户", value = "{id}")
- public User getUser(@PathVariable("id") Long id) {
- return null; // TODO: 还未实现.
- }
- @Api2Doc(order = 4)
- @ApiComment("查询所有用户, 按注册时间进行排序.")
- @GetMapping(name = "查询用户列表",value="")
- public List<User> getUsers() {
- return null; // TODO: 还未实现.
- }
- }
User 类定义
- package cn.com.yd.exam.bean;
- import java.util.Date;
- import com.terran4j.commons.api2doc.annotations.ApiComment;
- import com.terran4j.commons.restpack.RestPackIgnore;
- import lombok.Data;
- import lombok.experimental.Accessors;
- @Data
- @Accessors(chain = true)
- public class User {
- @ApiComment(value = "用户 id", sample = "123")
- private Long id;
- @ApiComment(value = "用户名", sample = "terran4j")
- private String name;
- @ApiComment(value = "账号密码, 字母与数字的组合, 区分大小写, 8-12 位", sample = "sdfi23skvs")
- private String password;
- @ApiComment(value = "用户所在的部门", sample = "研发组")
- private String dept;
- @ApiComment(value = "用户类型", sample = "admin")
- private UserType type;
- @ApiComment(value = "是否已删除", sample = "true")
- @RestPackIgnore
- private Boolean deleted;
- @ApiComment(value = "创建时间, 也是注册时间.",sample="2018-12-12")
- private Date createTime;
- }
UserType 枚举定义
- package cn.com.yd.exam.bean;
- import com.terran4j.commons.api2doc.annotations.ApiComment;
- public enum UserType {
- @ApiComment("管理员")
- admin,
- @ApiComment("普通用户")
- user
- }
运行效果
在浏览器中输入 http://localhost:8080/api2doc/home.html , 即可访问 ApiDoc 接口文档, 如下图
api2doc.PNG
一些细节的设置
设置接口文档的标题
可在 application.properties 中进行接口文档的标题和图标的设置, 图标为一个全路径 URL, 或本站点相对路径 URL 都行.
- # 中文标题出现乱码的问题, 故此设置成英文的了
- api2doc.title=Financial Information System APIs Document
- # 图标为一个全路径 URL, 或本站点相对路径 URL 都行
- api2doc.icon=https://spring.io/img/homepage/icon-spring-framework.svg
开启和关闭 Api2Doc 服务
由于 Api2Doc 服务没有访问权限校验, 建议仅在受信任的网络环境如公司内网中才启用 Api2Doc 服务. 可在 application.properties 中配置 api2doc.enabled 属性, 以开启或关闭 Api2Doc 服务, api2doc.enabled=true 或者不写表示启用.
api2doc.enabled=false
定制欢迎页面
每次访问文档页面 http://localhost:8080/api2doc/home.HTML 时,
中间的内容是非常简单的一句:
欢迎使用 Api2Doc !
这似乎有点不太好, 我们可以编写自己的欢迎页.
方法很简单, 在 src/main/resources 目录下创建 api2doc 目录, 然后在 api2doc 目录下创建一个名为
welcome.md 的文件 (这个名称是固定的), 然后用 md 语法编写内容就可以.
给文档菜单项排序
可以用 @Api2Doc 中的 order 属性给菜单项排序, order 的值越小该菜单项就越排在前面.@Api2Doc 既可以用在类上又可以用在方法上.
@Api2Doc(order = 4)
Api2Doc 注解详解
@Api2Doc
@Api2Doc 用于对文档的生成进行控制.
@Api2Doc 修饰在类上, 表示这个类会参与到文档生成过程中, Api2Doc 服务会扫描 Spring 容器中所有的 Controller 类, 只有类上有 @Api2Doc 的类, 才会被生成文档, 一个类对应于文档页面左侧的一级菜单项,@Api2Doc 的 name 属性则表示这个菜单项的名称.
@Api2Doc 也可以修饰在方法, 不过在方法上的 @Api2Doc 通常是可以省略, Api2Doc 服务会扫描这个类的所有带有 @RequestMapping 的方法, 每个这样的方法对应文档页面的左侧的二级菜单项, 菜单项的名称取 @RequestMapping 的 name 属性, 当然您仍然可以在方法上用 @Api2Doc 的 name 属性进行重定义.
@ApiComment
@ApiComment 用于对 API 进行说明, 它可以修饰在很多地方:
修饰在类上, 表示对这组 API 接口进行说明;
修饰在方法上, 表示对这个 API 接口进行说明;
修饰在参数上, 表示对这个 API 接口的请求参数进行说明;
修饰在返回类型的属性上, 表示对这个 API 接口的返回字段进行说明;
修饰在枚举项上, 表示对枚举项进行说明;
如果相同名称, 相同意义的属性或参数字段, 其说明已经在别的地方定义过了,
可以用 @ApiComment 的 seeClass 属性表示采用指定类的同名字段上的说明信息.
@ApiError
@ApiError 用于定义错误码, 有的 API 方法在执行业务逻辑时会产生错误, 出错后会在返回报文包含错误码, 以方便客户端根据错误码作进一步的处理, 因此也需要在 API 文档上体现错误码的说明.
Api2Doc 的缺点
Api2Doc 的缺点是不能像 Swagger 那样在页面中进行测试, 不过可以借助其他的工具进行测试.
来源: http://www.jianshu.com/p/281df3ecd3b0