<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SpringBoot 如何生成接口文檔,老鳥們都這么玩的!

          共 13462字,需瀏覽 27分鐘

           ·

          2021-09-13 16:37

          為什么要用Swagger ?

          作為一名程序員,我們最討厭兩件事:1. 別人不寫注釋。2. 自己寫注釋。
          而作為一名接口開發(fā)者,我們同樣討厭兩件事:1. 別人不寫接口文檔,文檔不及時更新。2. 需要自己寫接口文檔,還需要及時更新。
          相信無論是前端還是后端開發(fā),都或多或少地被接口文檔折磨過。前端經(jīng)常抱怨后端給的接口文檔與實際情況不一致。后端又覺得編寫及維護接口文檔會耗費不少精力,經(jīng)常來不及更新。
          而隨著Springboot、Springcloud等微服務(wù)的流行,每個項目都有成百上千個接口調(diào)用,這時候再要求人工編寫接口文檔并且保證文檔的實時更新幾乎是一件不可能完成的事,所以這時候我們迫切需要一個工具,一個能幫我們自動化生成接口文檔以及自動更新文檔的工具。它就是Swagger。
          Swagger 提供了一個全新的維護 API 文檔的方式,有4大優(yōu)點:
          1. 自動生成文檔:只需要少量的注解,Swagger 就可以根據(jù)代碼自動生成 API 文檔,很好的保證了文檔的時效性。
          2. 跨語言性,支持 40 多種語言。
          3. Swagger UI 呈現(xiàn)出來的是一份可交互式的 API 文檔,我們可以直接在文檔頁面嘗試 API 的調(diào)用,省去了準備復雜的調(diào)用參數(shù)的過程。
          4. 還可以將文檔規(guī)范導入相關(guān)的工具(例如 SoapUI), 這些工具將會為我們自動地創(chuàng)建自動化測試。
          現(xiàn)在我們知道了Swagger的作用,接下來將其集成到我們項目中。

           

          Swagger集成

          集成Swagger很簡單,只需要簡單三步。

          第一步:引入依賴包

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

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

          第二步:修改配置文件

          1. application.properties 加入配置

          # 用于控制是否開啟Swagger,生產(chǎn)環(huán)境記得關(guān)閉Swagger,將值設(shè)置為 false
          springfox.swagger2.enabled = true

          2.增加一個swagger配置類

          @Configuration
          @EnableSwagger2
          @ConditionalOnClass(Docket.class)
          public class SwaggerConfig 
          {
            
              private static final String VERSION = "1.0";

              @Value("${springfox.swagger2.enabled}")
              private Boolean swaggerEnabled;

              @Bean
              public Docket createRestApi(){
                  return new Docket(DocumentationType.SWAGGER_2)
                          .enable(swaggerEnabled)
                          .groupName("SwaggerDemo")
                          .apiInfo(apiInfo())
                          .select()
                          .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                          .paths(PathSelectors.any())
                          .build()
          ;
              }

              /**
               * 添加摘要信息
               */

              private ApiInfo apiInfo() {
                  return new ApiInfoBuilder()
                          .title("接口文檔")
                          .contact(new Contact("JAVA日知錄","http://javadaily.cn","[email protected]"))
                          .description("Swagger接口文檔")
                          .version(VERSION)
                          .build();
              }

          }

          這里通過.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))標明給加上@Api注解的類自動生成接口文檔。

          第三步,配置API接口

          @RestController
          @Api(tags = "參數(shù)校驗")
          @Slf4j
          @Validated
          public class ValidController {

              @PostMapping("/valid/test1")
              @ApiOperation("RequestBody校驗")
              public String test1(@Validated @RequestBody ValidVO validVO){
                  log.info("validEntity is {}", validVO);
                  return "test1 valid success";
              }

              @ApiOperation("Form校驗")
              @PostMapping(value = "/valid/test2")
              public String test2(@Validated ValidVO validVO){
                  log.info("validEntity is {}", validVO);
                  return "test2 valid success";
              }

              @ApiOperation("單參數(shù)校驗")
              @PostMapping(value = "/valid/test3")
              public String test3(@Email String email){
                  log.info("email is {}", email);
                  return "email valid success";
              }
          }

          通過@Api注解標注需要生成接口文檔,通過@ApiOperation注解標注接口名。
          同時我們給ValidVO也加上對應(yīng)的注解

          @Data
          @ApiModel(value = "參數(shù)校驗類")
          public class ValidVO {

              @ApiModelProperty("ID")
              private String id;

              @ApiModelProperty(value = "應(yīng)用ID",example = "cloud")
              private String appId;

              @NotEmpty(message = "級別不能為空")
              @ApiModelProperty(value = "級別")
              private String level;

              @ApiModelProperty(value = "年齡")
              private int age;
              
              ...

          }

          通過@ApiModel標注這是一個參數(shù)實體,通過@ApiModelProperty標注字段說明。

          Unable to infer base url

          簡單三步,我們項目就集成了Swagger接口文檔,趕緊啟動服務(wù),訪問http://localhost:8080/swagger-ui.html體驗一下。
          好吧,出了點小問題,不過不用慌。
          出現(xiàn)這個問題的原因是因為我們加上了ResponseBodyAdvice統(tǒng)一處理返回值/響應(yīng)體,導致給Swagger的返回值也包裝了一層,UI頁面無法解析。可以通過http://localhost:8080/v2/api-docs?group=SwaggerDemo觀察Swagger返回的json數(shù)據(jù)。
          既然知道了問題原因那就很好解決了,我們只需要在ResponseBodyAdvice處理類中只轉(zhuǎn)換我們自己項目的接口即可。

          @RestControllerAdvice(basePackages = "com.jianzh5.blog")
          @Slf4j
          public class ResponseAdvice implements ResponseBodyAdvice<Object{
            ...
          }   

          通過添加basePackage屬性限定統(tǒng)一返回值的范圍,這樣就不影響Swagger了。
          重啟服務(wù)器再次訪問swagger接口地址,就可以看到接口文檔頁面了。

          For input string: ""

          Swagger2.9.2有個bug,就是當我們參數(shù)實體有int類型的參數(shù)時,打開Swagger接口頁面時后端會一直提示異常:

          java.lang.NumberFormatException: For input string: ""
           at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
           at java.base/java.lang.Long.parseLong(Long.java:702)
           at java.base/java.lang.Long.valueOf(Long.java:1144)

          有兩種解決方案:
          1. 給int類型的字段使用@ApiModelPorperty注解時添加example屬性
          @ApiModelProperty(value = "年齡",example = "10")
          private int age;

          1. 去除原swagger中的swagger-modelsswagger-annotations,自行引入高版本的annotations和models

          <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
            <exclusions>
              <exclusion>
                <groupId>io.swagger</groupId>
                <artifactId>swagger-annotations</artifactId>
              </exclusion>
              <exclusion>
                <groupId>io.swagger</groupId>
                <artifactId>swagger-models</artifactId>
              </exclusion>
            </exclusions>
          </dependency>

          <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>1.5.22</version>
          </dependency>
          <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>1.5.22</version>
          </dependency>

          集成Swagger過程中雖然會出現(xiàn)兩個小問題,解決后我們就可以愉快享受Swagger給我們帶來的便利了。

           

          Swagger美化

          Swagger原生UI有點丑,我們可以借助Swagger的增強工具knife4j優(yōu)化一下。

          第一步:引入依賴包

           <!--整合Knife4j-->
          <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>2.0.4</version>
          </dependency>

          由于knife4j中已經(jīng)帶了swagger-annotationsswagger-models的依賴,所以我們可以把上文中手動添加的兩個依賴刪除。

          第二步:啟用knife4j增強

          @Configuration
          @EnableSwagger2
          @ConditionalOnClass(Docket.class)
          @EnableKnife4j
          public class SwaggerConfig 
          {
            ...
          }

          通過上面兩步我們就完成了Swagger的美化,通過瀏覽器訪問http://localhost:8080/doc.html即可看到效果。

           

          Swagger參數(shù)分組

          看到這里的同學心理肯定會想,就這?這就是老鳥的做法?跟我們新手也沒啥區(qū)別呀!
          別急,我們先來看一個效果。
          首先我們定義了兩個接口,一個新增,一個編輯

          @ApiOperation("新增")
          @PostMapping(value = "/valid/add")
          public String add(@Validated(value = {ValidGroup.Crud.Create.class}) ValidVO validVO){
            log.info("validEntity is {}", validVO);
            return "test3 valid success";
          }


          @ApiOperation("更新")
          @PostMapping(value = "/valid/update")
          public String update(@Validated(value = ValidGroup.Crud.Update.class) ValidVO validVO){
            log.info("validEntity is {}", validVO);
            return "test4 valid success";
          }

          注意看,這里用的是同一個實體ValidVO來接收前端參數(shù),只不過使用了參數(shù)校驗中的分組,然后我們打開kife4j頁面觀察兩者的接口文檔有何不同。
          新增:
          編輯:
          通過上面可以看到,雖然用于接受參數(shù)的實體一樣,但是當分組不一樣時展示給前端的參數(shù)也不一樣,這就是Swagger的分組功能
          當然原生的Swagger是不支持分組功能的,我們需要對Swagger進行擴展。我已經(jīng)將代碼上傳到了github上,由于代碼量比較多這里就不展示了,大家可以自行查閱。
          引入擴展類后還需要在Swagger配置類SwaggerConfig中注入對應(yīng)的Bean。

          @Configuration
          @EnableSwagger2
          @ConditionalOnClass(Docket.class)
          @EnableKnife4j
          public class SwaggerConfig 
          {
              ...

              @Bean
              @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1000)
              public GroupOperationModelsProviderPlugin groupOperationModelsProviderPlugin() {
                  return new GroupOperationModelsProviderPlugin();
              }

              @Bean
              @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1000)
              public GroupModelBuilderPlugin groupModelBuilderPlugin() {
                  return new GroupModelBuilderPlugin();
              }

              @Bean
              @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1000)
              public GroupModelPropertyBuilderPlugin groupModelPropertyBuilderPlugin() {
                  return new GroupModelPropertyBuilderPlugin();
              }

              @Bean
              @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1000)
              public GroupExpandedParameterBuilderPlugin groupExpandedParameterBuilderPlugin() {
                  return new GroupExpandedParameterBuilderPlugin();
              }

              @Bean
              @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1000)
              public GroupOperationBuilderPlugin groupOperationBuilderPlugin() {
                  return new GroupOperationBuilderPlugin();
              }

              @Bean
              @Primary
              @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1000)
              public GroupModelAttributeParameterExpander groupModelAttributeParameterExpander(FieldProvider fields, AccessorsProvider accessors, EnumTypeDeterminer enumTypeDeterminer) {
                  return new GroupModelAttributeParameterExpander(fields, accessors, enumTypeDeterminer);
              }


          }

          分組使用說明

          1.在bean對象的屬性里配置如下注釋

          @Null(groups = ValidGroup.Crud.Create.class)
          @NotNull(groups 
          = ValidGroup.Crud.Update.class,message "應(yīng)用ID不能為空")
          @ApiModelProperty(value = "應(yīng)用ID",example = "cloud")
          private String appId;

          當新增場景的時候,appId為空,不需要傳值;當修改場景的時候,appId不能為空,需要傳值 ;其他沒有配置組的皆為默認組(Default)
          2.在接口參數(shù)的時候加入組規(guī)則校驗

           @ApiOperation("新增")
           @PostMapping(value = "/valid/add")
           public String add(@Validated(value = {ValidGroup.Crud.Create.class}) ValidVO validVO){
            log.info("validEntity is {}", validVO);
            return "test3 valid success";
           }

          當前接口會針對默認組的bean屬性進行校驗,同時針對保存常見的屬性進行校驗。

           

          小結(jié)

          Swagger集成相對來說還是很簡單的,雖然在集成過程中也出現(xiàn)了幾個小問題,不過也很容易就解決了。今天文章的重點內(nèi)容是Swagger分組功能,跟之前的參數(shù)校驗文章一樣,很多同學遇到這種分組場景時往往會選擇創(chuàng)建多個實體類,雖然也能解決問題,只不過總是有點別扭。
          不過遺憾的是,本文中Swagger的分組擴展只支持Swagger2,至于新版本Swagger3就不怎么友好了。


          有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)

          歡迎大家關(guān)注Java之道公眾號


          好文章,我在看??

          瀏覽 44
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  AAA免费看 | 黄色a级三级毛片免费 | 黑人大操逼 | 成人久久大香蕉 | 青青草成人免费观看 |