zoukankan      html  css  js  c++  java
  • 可无注解的 SpringBoot API文档生成工具

    JApiDocs是一个无需额外注解、开箱即用的SpringBoot接口文档生成工具。

    前言

    编写和维护API文档,对于后端程序员来说,是一件恼人但又不得不做的事情,我们都不喜欢写文档,除非项目前后端代码都是自己写的,否则API文档将是前后端协作不可或缺的沟通载体。
    最佳实践是:先把接口设计好,在Mock的方法上写注释来生成API文档,这样做到前后端根据API文档并行开发。

    为什么引入JApiDocs

    相比Swagger要写一堆注解,Spring Rest Docs需要写测试用例,才能生成API文档,JApiDocs只要Controller类和方法的Java注释写完即可手动生成多种格式的API文档。
    如下的简单一个参数的方法,Swagger要写两行又臭又长的注解,稍不留神就写错。

     
    Swagger注解示例

    先睹为快

    没有对比就没有伤害,看一下我的java代码,没有任何多余的注解,只有常规的java规范方法注释。

        /**
         * 示例生成api文档方法
         *
         * @param productId 年龄
         * @param guo       姓氏
         * @return 商品库存DTO
         */
        @PostMapping("/apiDocDemo")
        public ProductReduceStockDTO apiDocDemo(@RequestParam Long productId, @RequestParam String guo) {
            return new ProductReduceStockDTO().setProductId(productId);
        }
    
    生成后的Java API Doc如图:
     
    API Doc效果图

    快速上手

    第一步

    添加依赖

    <dependency>
      <groupId>io.github.yedaxia</groupId>
      <artifactId>japidocs</artifactId>
      <version>1.4</version>
    </dependency>
    

    第二步

    配置参数
    你可以在任意一个类添加main方法,运行下面的代码:

    DocsConfig config = new DocsConfig();
    config.setProjectPath("your springboot project path"); // 项目根目录
    config.setProjectName("ProjectName"); // 项目名称
    config.setApiVersion("V1.0");       // 声明该API的版本
    config.setDocsPath("your api docs path"); // 生成API 文档所在目录
    config.setAutoGenerate(Boolean.TRUE);  // 配置自动生成
    Docs.buildHtmlDocs(config); // 执行生成文档
    

    如果没有意外,执行完上面的代码后,你就可以在配置的目录中看到生成的文档了。

    编码规范

    JApiDocs是通过解析Java源码来实现的,要使得JApiDocs正确工作,需要你在项目中的Controller书写遵循一定的编码规范。

    1. 添加必要的代码注释

    其中类注释会对应到一级接口分组,你也可以通过@description来指定分组名称;JApiDocs 会通过 @param 来寻找接口参数和进一步解析参数的内容。

    package cn.iocoder.springboot.lab52.productservice.controller;
    
    import cn.iocoder.springboot.lab52.productservice.dto.ProductReduceStockDTO;
    import cn.iocoder.springboot.lab52.productservice.service.ProductService;
    import io.github.yedaxia.apidocs.Docs;
    import io.github.yedaxia.apidocs.DocsConfig;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    
    /**
     * @description 商品相关操作控制器
     * @ClassName: ProductController
     * @author: 郭秀志 jbcode@126.com
     * @date: 2020/6/23 20:56
     * @Copyright:
     */
    @RestController
    @RequestMapping("/product")
    public class ProductController {
    
        private Logger logger = LoggerFactory.getLogger(ProductController.class);
    
        @Autowired
        private ProductService productService;
    
    
        /**
         * 减库存操作
         *
         * @param productReduceStockDTO 商品及库存的DTO,用于减库存。
         * @param guo                   示例参数无意义。
         * @return
         */
        @PostMapping("/reduce-stock")
        public Boolean reduceStock(@RequestBody ProductReduceStockDTO productReduceStockDTO, @RequestParam String guo) {
            logger.info(guo + "[reduceStock] 收到减少库存请求, 商品:{}, 价格:{}", productReduceStockDTO.getProductId(),
                    productReduceStockDTO.getAmount());
            try {
                productService.reduceStock(productReduceStockDTO.getProductId(), productReduceStockDTO.getAmount());
                // 正常扣除库存,返回 true
                return true;
            } catch (Exception e) {
                // 失败扣除库存,返回 false
                return false;
            }
        }
    
        /**
         * 示例生成api文档方法
         *
         * @param productId 年龄
         * @param guo       姓氏
         * @return 商品库存DTO
         */
        @PostMapping("/apiDocDemo")
        public ProductReduceStockDTO apiDocDemo(@RequestParam Long productId, @RequestParam String guo) {
            return new ProductReduceStockDTO().setProductId(productId);
        }
    
        public static void main(String[] args) {
            DocsConfig config = new DocsConfig();
            config.setProjectPath("D:\dev\GitRepository\seata-at-httpclient-demo\seata-at-httpclient-demo-product-service"); // 项目根目录
            config.setProjectName("商品服务"); // 项目名称
            config.setApiVersion("V1.0");       // 声明该API的版本
            config.setDocsPath("d:\Japidoc"); // 生成API 文档所在目录
            config.setAutoGenerate(Boolean.TRUE);  // 配置自动生成
            Docs.buildHtmlDocs(config); // 执行生成文档
        }
    }
    
    
    /**
     * 商品减少库存 DTO
     */
    public class ProductReduceStockDTO {
    
        /**
         * 商品编号
         */
        private Long productId;
        /**
         * 数量
         */
        private Integer amount;
        省略getter、setter方法,属性的注释将在文档中被使用.......
    

    如果提交的表单是 application/x-www-form-urlencoded 类型的key/value格式,你可以在 SpringBoot 端通过在 @param 参数后添加字段解释或者在相关的JavaBean对象里面添加解释:

    // 直接在java的 @param 注解中
    
    // 在FormBean对象中
    public class UserListForm extends PageForm{
        private Integer status; //用户状态
        private String name; //用户名
    }
    

    这种格式对于到文档中的参数描述将是表格的形式:

    参数名类型必须描述
    status int 用户状态
    name string 用户名

    如果提交的表单是 application/json 类型的json数据格式,对应 SpringBoot 中的 @RequestBody 注解,在文档中则是 json 格式显示:

    {
      "id": "long //用户ID",
      "name": "string //用户名",
      "phone": "long //电话",
      "avatar": "string //头像",
      "gender": "byte //性别"
    }
    

    2. 接口声明返回对象

    我们知道,如果Controller声明了@RestController,SpringBoot会把返回的对象直接序列成Json数据格式返回给前端。 JApiDocs也利用了这一特性来解析接口返回的结果,但由于JApiDocs是静态解析源码的,因此你要明确指出返回对象的类型信息,JApiDocs支持继承、泛型、循环嵌套等复杂的类解析。

    比如的apiDocDemo接口:

    
        /**
         * 示例生成api文档方法
         *
         * @param productId 年龄
         * @param guo       姓氏
         * @return 商品库存DTO
         */
        @PostMapping("/apiDocDemo")
        public ProductReduceStockDTO apiDocDemo(@RequestParam Long productId, @RequestParam String guo) {
            return new ProductReduceStockDTO().setProductId(productId);
        }
    

    ProductReduceStockDTO表明了该接口返回的数据结构,经过JApiDocs处理后是这样的:

    {
      "productId": "long //商品编号",
      "amount": "int //数量"
    }
    

    如果你不是通过返回对象的形式,你也可以通过JApiDocs提供的@ApiDoc注解来声明返回类型,你可以参考@ApiDoc章节的相关配置内容。

    3. @ApiDoc

    JApiDocs 默认只导出声明了@ApiDoc的接口,我们前面通过设置 config.setAutoGenerate(Boolean.TRUE) 来解除了这个限制。

    如果你不希望把所有的接口都导出,你可以把autoGenerate设置关闭,在相关Controller类或者接口方法上通过添加@ApiDoc来确定哪些接口需要导出。

    @ApiDoc声明在接口方法上的时候,它还拥有一些更灵活的设置,下面我们来看一下:

    • result: 这个可以直接声明返回的对象类型,如果你声明了,将会覆盖SpringBoot的返回对象
    • url: 请求URL,扩展字段,用于支持非SpringBoot项目
    • method: 请求方法,扩展字段,用于支持非SpringBoot项目

    例子:

    @ApiDoc(result = AdminVO.class, url = "/api/v1/admin/login2", method = "post")
    

    4. @Ignore

    如果你不想导出对象里面的某个字段,可以给这个字段加上@Ignore注解,这样JApiDocs导出文档的时候就会自动忽略掉了:

    例子:

    public class UserForm{
        @Ignore
        private Byte gender; //性别
    }
    

    导出更多格式

    导出markdown

    config.addPlugin(new MarkdownDocPlugin());
    

    导出 pdf 或者 word

    你可以通过 pandoc 把 markdown 格式转成 pdf 或者 word 格式。



  • 相关阅读:
    《javascript高级程序设计》第六章总结
    电子邮件写信页面开发代码
    JSON和XML的比较
    2014前端工程师基础课程作业
    cookie 和session 的区别详解
    substring()、slice()和substr()方法辨析
    Number()、parseInt()和parseFloat()辨析
    《javascript高级程序设计》第十三章知识点
    angular debounce 搜索去抖动/防抖
    js四舍五入保留两位小数的方法
  • 原文地址:https://www.cnblogs.com/sea520/p/13195612.html
Copyright © 2011-2022 走看看