­

Spring Boot 2.X(十五):集成 Swagger2 開發 API 文檔(在線+離線)

  • 2019 年 11 月 6 日
  • 筆記

前言

相信很多後端開發在項目中都會碰到要寫 api 文檔,不管是給前端、移動端等提供更好的對接,還是以後為了以後交接方便,都會要求寫 api 文檔。

而手寫 api 文檔的話有諸多痛點:

  • 文檔更新的時候,需要再次發送給對接人
  • 接口太對,手寫文檔很難管理
  • 接口返回的結果不明確
  • 不能直接在線測試接口,通常需要使用工具,如 postman 等

Swagger 就很好的解決了這個問題。

Swagger 簡介

Swagger 是一個規範和完整的框架,用於生成、描述、調用和可視化 RESTful 風格的 Web 服務。總體目標是使客戶端和文件系統作為服務器以同樣的速度來更新。文件的方法,參數和模型緊密集成到服務器端的代碼,允許API來始終保持同步。

官網:https://swagger.io

Swagger 使用

1.相關依賴

<!--swagger2 -->          <dependency>              <groupId>io.springfox</groupId>              <artifactId>springfox-swagger2</artifactId>              <version>2.9.2</version>          </dependency>          <dependency>              <groupId>io.springfox</groupId>              <artifactId>springfox-swagger-ui</artifactId>              <version>2.9.2</version>          </dependency>

2.Swagger 配置類

@Configuration  @EnableSwagger2  public class SwaggerConfig {      @Bean      public Docket buildDocket() {          return new Docket(DocumentationType.SWAGGER_2)          .apiInfo(buildApiInf()) //將api的元信息設置為包含在json resourcelisting響應中          //.host("127.0.0.1:8080") //設置ip和端口,或者域名          .select()  //啟動用於api選擇的生成器          //.apis(RequestHandlerSelectors.any())          .apis(RequestHandlerSelectors.basePackage("cn.zwqh.springboot.controller"))//指定controller路徑          .paths(PathSelectors.any()).build();      }        private ApiInfo buildApiInf() {            Contact contact=new Contact("朝霧輕寒","https://www.zwqh.top/","zwqh@clover1314.com");          return new ApiInfoBuilder()          .title("Swagger Demo Restful API Docs")//文檔標題          .description("Swagger 示例 Restful Api 文檔")//文檔描述          .contact(contact)//聯繫人          .version("1.0")//版本號          //.license("")//更新此API的許可證信息          //.licenseUrl("")//更新此API的許可證Url          //.termsOfServiceUrl("")//更新服務條款URL          .build();        }  }

3.Spring MVC 相關配置

@Configuration  public class WebMvcConfig extends WebMvcConfigurationSupport {      /**       * 靜態資源配置(默認)       */      @Override      public void addResourceHandlers(ResourceHandlerRegistry registry) {          registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");// 靜態資源路徑          registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");          registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");          super.addResourceHandlers(registry);      }      }

如果不添加此靜態資源配置會報錯,找不到相關路徑

4.Model 中使用 Swagger 註解

@ApiModel(value = "UserEntity", description = "用戶對象")  public class UserEntity implements Serializable{        /**       *       */      private static final long serialVersionUID = 5237730257103305078L;      @ApiModelProperty(value ="用戶id",name="id",dataType="Long",required = false,example = "1",hidden = false )      private Long id;      @ApiModelProperty(value ="用戶名",name="userName",dataType="String",required = false,example = "關羽" )      private String userName;      @ApiModelProperty(value ="用戶性別",name="userSex",dataType="String",required = false,example = "男" )      private String userSex;        public Long getId() {          return id;      }        public void setId(Long id) {          this.id = id;      }        public String getUserName() {          return userName;      }        public void setUserName(String userName) {          this.userName = userName;      }        public String getUserSex() {          return userSex;      }        public void setUserSex(String userSex) {          this.userSex = userSex;      }    }  

5. Controller 中使用 Swagger 註解

  @RestController  @RequestMapping("/api")  @Api(tags = { "接口分組1", "接口分組2" })  public class ApiController {        @Autowired      private UserDao userDao;        @GetMapping("/getAllUser")      @ApiOperation(value = "獲取所有用戶", notes = "", httpMethod = "GET", tags = "接口分組3")      public List<UserEntity> getAll() {          return userDao.getAll();      }        @GetMapping("/getUserById")      @ApiOperation(value = "根據id獲取用戶", notes = "id必傳", httpMethod = "GET")      @ApiImplicitParam(name = "id", value = "用戶id",example = "1", required = true, dataType = "long", paramType = "query")      public UserEntity getOne(Long id) {          return userDao.getOne(id);      }        @PostMapping("/getUserByNameAndSex")      @ApiOperation(value = "根據name和sex獲取用戶", notes = "", httpMethod = "POST")      @ApiImplicitParams({              @ApiImplicitParam(name = "userName", value = "用戶名", example = "關羽", required = true, dataType = "string", paramType = "query"),              @ApiImplicitParam(name = "userSex", value = "用戶性別", example = "男", required = true, dataType = "string", paramType = "query") })      public UserEntity getUserByNameAndSex(String userName, String userSex) {          return userDao.getUserByNameAndSex(userName, userSex);      }        @PostMapping("/insertUser")      @ApiOperation(value = "新增用戶", notes = "傳json,數據放body", httpMethod = "POST")      @ApiImplicitParams({              @ApiImplicitParam(name = "body", value = "用戶對象json", example = "{userName:'朝霧輕寒',userSex:'男'}", required = true) })      public String insertUser(@RequestBody String body) {          System.out.println(body);          UserEntity user = JSON.parseObject(body, UserEntity.class);          userDao.insertUser(user);          return "{code:0,msg:'success'}";      }        @PostMapping("/updateUser")      @ApiOperation(value = "修改用戶", notes = "傳json,數據放body", httpMethod = "POST")      @ApiImplicitParams({              @ApiImplicitParam(name = "body", value = "用戶對象json", example = "{id:23,userName:'朝霧輕寒',userSex:'女'}", required = true) })      public String updateUser(@RequestBody String body) {          System.out.println(body);          UserEntity user = JSON.parseObject(body, UserEntity.class);          userDao.updateUser(user);          return "{code:0,msg:'success'}";      }        @PostMapping("/deleteUser")      @ApiOperation(value = "刪除用戶", notes = "id必傳", httpMethod = "POST")      public String deleteUser(@ApiParam(name = "id", value = "用戶id", required = true) Long id) {          userDao.deleteUser(id);          return "{code:0,msg:'success'}";      }  }

5.測試

訪問 http://127.0.0.1:8080/swagger-ui.html 進行接口在線測試

Swagger 常用註解

1.@Api

用於類,表示標識這個類是swagger的資源。屬性如下:

  • tags 表示說明,tags如果有多個值,會生成多個列表
  • value 表示說明,可以使用tags替代

2.@ApiOperation

用於方法,表示一個http請求的操作。屬性如下:

  • value 用於方法描述
  • notes 用於提示內容
  • tags 用於API文檔控制的標記列表,視情況而用,可以進行獨立分組

3.@ApiParam

用於方法、參數、字段說明;表示對參數的添加元數據。

  • name 參數名
  • value 參數說明
  • required 是否必填

4.@ApiModel

用於類,表示對類進行說明,用於參數用實體類接受。

  • value 對象名
  • description 描述

5.@ApiModelProperty

用於方法、字段,表示對model屬性的說明或者數據操作更改。

  • value 字段說明
  • name 重寫屬性名
  • dataType 重寫屬性數據類型
  • required 是否必填
  • example 舉例說明
  • hidden 隱藏

6.@ApiIgnore

用於類、方法、方法參數,表示這個方法或者類被忽略,不在swagger-ui.html上顯示。

7.@ApiImplicitParam

用於方法,表示單獨的請求參數。

  • name 參數名
  • value 參數說明
  • dataType 數據類型
  • paramType 參數類型
  • example 舉例說明

8.@ApiImplicitParams

用於方法,包含多個 @ApiImplicitParam。

9.@ApiResponses @ApiResponse

用於類或者方法,描述操作的可能響應。

  • code 響應的HTTP狀態代碼
  • message 響應附帶的可讀消息

10.@ResponseHeader

用於方法,響應頭設置。

  • name 響應頭名稱
  • description 頭描述
  • response 默認響應類 void
  • responseContainer 參考ApiOperation中配置

Swagger 導出離線 api 文檔

1.導出 AsciiDocs、Markdown、Confluence 格式文檔

添加依賴

<!-- swagger2markup 相關依賴 -->          <dependency>              <groupId>io.github.swagger2markup</groupId>              <artifactId>swagger2markup</artifactId>              <version>1.3.3</version>          </dependency>

轉換工具類

public class SwaggerUtils {        private static final String url = "http://127.0.0.1:8080/v2/api-docs";      /**       * 生成AsciiDocs格式文檔       * @throws MalformedURLException       */      public static void generateAsciiDocs() throws MalformedURLException {          Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()                  .withMarkupLanguage(MarkupLanguage.ASCIIDOC)                  .withOutputLanguage(Language.ZH)                  .withPathsGroupedBy(GroupBy.TAGS)                  .withGeneratedExamples()                  .withoutInlineSchema().build();            Swagger2MarkupConverter.from(new URL(url))                  .withConfig(config)                  .build()                  .toFolder(Paths.get("./docs/asciidoc/generated"));      }      /**       * 生成AsciiDocs格式文檔,並匯總成一個文件       * @throws MalformedURLException       */      public static void generateAsciiDocsToFile() throws MalformedURLException {          Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()                  .withMarkupLanguage(MarkupLanguage.ASCIIDOC)                  .withOutputLanguage(Language.ZH)                  .withPathsGroupedBy(GroupBy.TAGS)                  .withGeneratedExamples()                  .withoutInlineSchema()                  .build();            Swagger2MarkupConverter.from(new URL(url))                  .withConfig(config)                  .build()                  .toFile(Paths.get("./docs/asciidoc/generated/all"));      }        /**       * 生成Markdown格式文檔       * @throws MalformedURLException       */      public static void generateMarkdownDocs() throws MalformedURLException {          Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()                  .withMarkupLanguage(MarkupLanguage.MARKDOWN)                  .withOutputLanguage(Language.ZH)                  .withPathsGroupedBy(GroupBy.TAGS)                  .withGeneratedExamples()                  .withoutInlineSchema()                  .build();            Swagger2MarkupConverter.from(new URL(url))                  .withConfig(config)                  .build()                  .toFolder(Paths.get("./docs/markdown/generated"));      }      /**       * 生成Markdown格式文檔,並匯總成一個文件       * @throws MalformedURLException       */      public static void generateMarkdownDocsToFile() throws MalformedURLException {          Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()                  .withMarkupLanguage(MarkupLanguage.MARKDOWN)                  .withOutputLanguage(Language.ZH)                  .withPathsGroupedBy(GroupBy.TAGS)                  .withGeneratedExamples()                  .withoutInlineSchema()                  .build();            Swagger2MarkupConverter.from(new URL(url))                  .withConfig(config)                  .build()                  .toFile(Paths.get("./docs/markdown/generated/all"));      }        /**       * 生成Confluence格式文檔       * @throws MalformedURLException       */      public static void generateConfluenceDocs() throws MalformedURLException {          Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()                  .withMarkupLanguage(MarkupLanguage.CONFLUENCE_MARKUP)                  .withOutputLanguage(Language.ZH)                  .withPathsGroupedBy(GroupBy.TAGS)                  .withGeneratedExamples()                  .withoutInlineSchema()                  .build();            Swagger2MarkupConverter.from(new URL(url))                  .withConfig(config)                  .build()                  .toFolder(Paths.get("./docs/confluence/generated"));      }        /**       * 生成Confluence格式文檔,並匯總成一個文件       * @throws MalformedURLException       */      public static void generateConfluenceDocsToFile() throws MalformedURLException {          Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()                  .withMarkupLanguage(MarkupLanguage.CONFLUENCE_MARKUP)                  .withOutputLanguage(Language.ZH)                  .withPathsGroupedBy(GroupBy.TAGS)                  .withGeneratedExamples()                  .withoutInlineSchema()                  .build();            Swagger2MarkupConverter.from(new URL(url))                  .withConfig(config)                  .build()                  .toFile(Paths.get("./docs/confluence/generated/all"));      }      }

使用測試 Controller

@RestController  @RequestMapping("/export")  @ApiIgnore  public class ExportController {          @RequestMapping("/ascii")      public String exportAscii() throws MalformedURLException{          SwaggerUtils.generateAsciiDocs();          return "success";      }        @RequestMapping("/asciiToFile")      public String asciiToFile() throws MalformedURLException{          SwaggerUtils.generateAsciiDocsToFile();          return "success";      }        @RequestMapping("/markdown")      public String exportMarkdown() throws MalformedURLException{          SwaggerUtils.generateMarkdownDocs();          return "success";      }        @RequestMapping("/markdownToFile")      public String exportMarkdownToFile() throws MalformedURLException{          SwaggerUtils.generateMarkdownDocsToFile();          return "success";      }        @RequestMapping("/confluence")      public String confluence() throws MalformedURLException{          SwaggerUtils.generateConfluenceDocs();          return "success";      }        @RequestMapping("/confluenceToFile")      public String confluenceToFile() throws MalformedURLException{          SwaggerUtils.generateConfluenceDocsToFile();          return "success";      }  }  

2.導出 html、pdf、xml 格式

添加依賴

<!--離線文檔 -->          <dependency>              <groupId>org.springframework.restdocs</groupId>              <artifactId>spring-restdocs-mockmvc</artifactId>              <scope>test</scope>          </dependency>          <!--springfox-staticdocs 生成靜態文檔 -->          <dependency>              <groupId>io.springfox</groupId>              <artifactId>springfox-staticdocs</artifactId>              <version>2.6.1</version>          </dependency>
<build>          <pluginManagement>              <plugins>                  <plugin>                      <groupId>org.springframework.boot</groupId>                      <artifactId>spring-boot-maven-plugin</artifactId>                  </plugin>                  <plugin>                      <groupId>io.github.swagger2markup</groupId>                      <artifactId>swagger2markup-maven-plugin</artifactId>                      <version>1.3.1</version>                      <configuration>                          <swaggerInput>http://127.0.0.1:8080/v2/api-docs</swaggerInput>                          <outputDir>./docs/asciidoc/generated</outputDir>                          <config>                              <swagger2markup.markupLanguage>ASCIIDOC</swagger2markup.markupLanguage>                          </config>                      </configuration>                  </plugin>                  <plugin>                      <groupId>org.asciidoctor</groupId>                      <artifactId>asciidoctor-maven-plugin</artifactId>                      <version>1.5.3</version>                      <!-- <version>2.0.0-RC.1</version> -->                      <!-- Include Asciidoctor PDF for pdf generation -->                      <dependencies>                          <dependency>                              <groupId>org.asciidoctor</groupId>                              <artifactId>asciidoctorj-pdf</artifactId>                              <version>1.5.0-alpha.10.1</version>                          </dependency>                          <dependency>                              <groupId>org.jruby</groupId>                              <artifactId>jruby-complete</artifactId>                              <version>1.7.21</version>                          </dependency>                      </dependencies>                      <configuration>                          <sourceDirectory>./docs/asciidoc/generated</sourceDirectory>                          <outputDirectory>./docs/asciidoc/html</outputDirectory>                          <backend>html</backend>                          <!-- <outputDirectory>./docs/asciidoc/pdf</outputDirectory>                          <backend>pdf</backend> -->                          <headerFooter>true</headerFooter>                          <doctype>book</doctype>                          <sourceHighlighter>coderay</sourceHighlighter>                          <attributes>                              <!-- 菜單欄在左邊 -->                              <toc>left</toc>                              <!-- 多標題排列 -->                              <toclevels>3</toclevels>                              <!-- 自動打數字序號 -->                              <sectnums>true</sectnums>                          </attributes>                      </configuration>                  </plugin>              </plugins>          </pluginManagement>        </build>  

可以修改此處 html 和 pdf,通過 mvn asciidoctor:process-asciidoc 可以導出相應格式文件

<outputDirectory>./docs/asciidoc/html</outputDirectory>                          <backend>html</backend>

執行 mvn asciidoctor:process-asciidoc 後再執行 mvn generate-resources,可在 targt/generated-docs 目錄下生成 xml 格式文件。

完整代碼

github

碼雲