用Api2Doc代替Swagger2生成 Restful API 文档

背景介绍

在进行前后端分离式开发项目过程中,需要有效的沟通。接口文档因为更新的不及时,也难免存在错误,使沟通的成本大大增加。因此,业界就出现了一些根据代码自动生成 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依赖


  com.github.terran4j
  terran4j-commons-api2doc
  1.0.2

启用 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 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代替Swagger2生成 Restful API 文档_第1张图片
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那样在页面中进行测试,不过可以借助其他的工具进行测试。

你可能感兴趣的:(用Api2Doc代替Swagger2生成 Restful API 文档)