javascript
SpringBoot 如何生成接口文档,老鸟们都这么玩的!
為什么要用Swagger ?
“
作為一名程序員,我們最討厭兩件事:1. 別人不寫注釋。2. 自己寫注釋。
而作為一名接口開發者,我們同樣討厭兩件事:1. 別人不寫接口文檔,文檔不及時更新。2. 需要自己寫接口文檔,還需要及時更新。
”
相信無論是前端還是后端開發,都或多或少地被接口文檔折磨過。前端經常抱怨后端給的接口文檔與實際情況不一致。后端又覺得編寫及維護接口文檔會耗費不少精力,經常來不及更新。
而隨著Springboot、Springcloud等微服務的流行,每個項目都有成百上千個接口調用,這時候再要求人工編寫接口文檔并且保證文檔的實時更新幾乎是一件不可能完成的事,所以這時候我們迫切需要一個工具,一個能幫我們自動化生成接口文檔以及自動更新文檔的工具。它就是Swagger。
Swagger 提供了一個全新的維護 API 文檔的方式,有4大優點:
自動生成文檔:只需要少量的注解,Swagger 就可以根據代碼自動生成 API 文檔,很好的保證了文檔的時效性。
跨語言性,支持 40 多種語言。
Swagger UI 呈現出來的是一份可交互式的 API 文檔,我們可以直接在文檔頁面嘗試 API 的調用,省去了準備復雜的調用參數的過程。
還可以將文檔規范導入相關的工具(例如 SoapUI), 這些工具將會為我們自動地創建自動化測試。
現在我們知道了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>第二步:修改配置文件
application.properties 加入配置
2.增加一個swagger配置類
@Configuration @EnableSwagger2 @ConditionalOnClass(Docket.class) public?class?SwaggerConfig?{private?static?final?String?VERSION?=?"1.0";@Value("${springfox.swagger2.enabled}")private?Boolean?swaggerEnabled;@Beanpublic?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","jianzh5@163.com")).description("Swagger接口文檔").version(VERSION).build();}}這里通過.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))標明給加上@Api注解的類自動生成接口文檔。
第三步,配置API接口
@RestController @Api(tags?=?"參數校驗") @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("單參數校驗")@PostMapping(value?=?"/valid/test3")public?String?test3(@Email?String?email){log.info("email?is?{}",?email);return?"email?valid?success";} }通過@Api注解標注需要生成接口文檔,通過@ApiOperation注解標注接口名。
同時我們給ValidVO也加上對應的注解
@Data @ApiModel(value?=?"參數校驗類") public?class?ValidVO?{@ApiModelProperty("ID")private?String?id;@ApiModelProperty(value?=?"應用ID",example?=?"cloud")private?String?appId;@NotEmpty(message?=?"級別不能為空")@ApiModelProperty(value?=?"級別")private?String?level;@ApiModelProperty(value?=?"年齡")private?int?age;...}通過@ApiModel標注這是一個參數實體,通過@ApiModelProperty標注字段說明。
Unable to infer base url
簡單三步,我們項目就集成了Swagger接口文檔,趕緊啟動服務,訪問http://localhost:8080/swagger-ui.html體驗一下。
好吧,出了點小問題,不過不用慌。
出現這個問題的原因是因為我們加上了ResponseBodyAdvice統一處理返回值/響應體,導致給Swagger的返回值也包裝了一層,UI頁面無法解析。可以通過http://localhost:8080/v2/api-docs?group=SwaggerDemo觀察Swagger返回的json數據。
既然知道了問題原因那就很好解決了,我們只需要在ResponseBodyAdvice處理類中只轉換我們自己項目的接口即可。
@RestControllerAdvice(basePackages?=?"com.jianzh5.blog") @Slf4j public?class?ResponseAdvice?implements?ResponseBodyAdvice<Object>?{... }???通過添加basePackage屬性限定統一返回值的范圍,這樣就不影響Swagger了。
重啟服務器再次訪問swagger接口地址,就可以看到接口文檔頁面了。
For input string: ""
Swagger2.9.2有個bug,就是當我們參數實體有int類型的參數時,打開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)有兩種解決方案:
給int類型的字段使用@ApiModelPorperty注解時添加example屬性
去除原swagger中的swagger-models和swagger-annotations,自行引入高版本的annotations和models
集成Swagger過程中雖然會出現兩個小問題,解決后我們就可以愉快享受Swagger給我們帶來的便利了。
?
Swagger美化
Swagger原生UI有點丑,我們可以借助Swagger的增強工具knife4j優化一下。
第一步:引入依賴包
?<!--整合Knife4j--> <dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>2.0.4</version> </dependency>“
由于knife4j中已經帶了swagger-annotations和swagger-models的依賴,所以我們可以把上文中手動添加的兩個依賴刪除。
”
第二步:啟用knife4j增強
@Configuration @EnableSwagger2 @ConditionalOnClass(Docket.class) @EnableKnife4j public?class?SwaggerConfig?{... }通過上面兩步我們就完成了Swagger的美化,通過瀏覽器訪問http://localhost:8080/doc.html即可看到效果。
?
Swagger參數分組
看到這里的同學心理肯定會想,就這?這就是老鳥的做法?跟我們新手也沒啥區別呀!
別急,我們先來看一個效果。
首先我們定義了兩個接口,一個新增,一個編輯
@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來接收前端參數,只不過使用了參數校驗中的分組,然后我們打開kife4j頁面觀察兩者的接口文檔有何不同。
新增:
編輯:
通過上面可以看到,雖然用于接受參數的實體一樣,但是當分組不一樣時展示給前端的參數也不一樣,這就是Swagger的分組功能。當然原生的Swagger是不支持分組功能的,我們需要對Swagger進行擴展。我已經將代碼上傳到了github上,由于代碼量比較多這里就不展示了,大家可以自行查閱。
引入擴展類后還需要在Swagger配置類SwaggerConfig中注入對應的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?=?"應用ID不能為空") @ApiModelProperty(value?=?"應用ID",example?=?"cloud") private?String?appId;當新增場景的時候,appId為空,不需要傳值;當修改場景的時候,appId不能為空,需要傳值 ;其他沒有配置組的皆為默認組(Default)
2.在接口參數的時候加入組規則校驗
?@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屬性進行校驗,同時針對保存常見的屬性進行校驗。
?
小結
Swagger集成相對來說還是很簡單的,雖然在集成過程中也出現了幾個小問題,不過也很容易就解決了。今天文章的重點內容是Swagger分組功能,跟之前的參數校驗文章一樣,很多同學遇到這種分組場景時往往會選擇創建多個實體類,雖然也能解決問題,只不過總是有點別扭。
不過遺憾的是,本文中Swagger的分組擴展只支持Swagger2,至于新版本Swagger3就不怎么友好了。
有道無術,術可成;有術無道,止于術
歡迎大家關注Java之道公眾號
好文章,我在看??
總結
以上是生活随笔為你收集整理的SpringBoot 如何生成接口文档,老鸟们都这么玩的!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python第三十二课——队列
- 下一篇: “零代码”时代已来!程序员真的要去送外卖