SpringBoot的API文檔生成工具SpringDoc使用詳解
前言
之前在SpringBoot項目中一直使用的是SpringFox提供的Swagger庫,上了下官網(wǎng)發(fā)現(xiàn)已經(jīng)有接近兩年沒出新版本了!前幾天升級了SpringBoot 2.6.x 版本,發(fā)現(xiàn)這個庫的兼容性也越來越不好了,有的常用注解屬性被廢棄了居然都沒提供替代!無意中發(fā)現(xiàn)了另一款Swagger庫SpringDoc,試用了一下非常不錯,推薦給大家!
SpringBoot實戰(zhàn)電商項目mall(50k+star)地址:https://github.com/macrozheng/mall
SpringDoc簡介
SpringDoc是一款可以結(jié)合SpringBoot使用的API文檔生成工具,基于OpenAPI 3,目前在Github上已有1.7K+Star,更新發(fā)版還是挺勤快的,是一款更好用的Swagger庫!值得一提的是SpringDoc不僅支持Spring WebMvc項目,還可以支持Spring WebFlux項目,甚至Spring Rest和Spring Native項目,總之非常強大,下面是一張SpringDoc的架構(gòu)圖。
使用
接下來我們介紹下SpringDoc的使用,使用的是之前集成SpringFox的mall-tiny-swagger項目,我將把它改造成使用SpringDoc。
集成
首先我們得集成SpringDoc,在pom.xml中添加它的依賴即可,開箱即用,無需任何配置。
<!--springdoc 官方Starter--> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-ui</artifactId> <version>1.6.6</version> </dependency>
從SpringFox遷移
- 我們先來看下經(jīng)常使用的Swagger注解,看看SpringFox的和SpringDoc的有啥區(qū)別,畢竟對比已學(xué)過的技術(shù)能該快掌握新技術(shù);
SpringFox | SpringDoc |
---|---|
@Api | @Tag |
@ApiIgnore | @Parameter(hidden = true)or@Operation(hidden = true)or@Hidden |
@ApiImplicitParam | @Parameter |
@ApiImplicitParams | @Parameters |
@ApiModel | @Schema |
@ApiModelProperty | @Schema |
@ApiOperation(value = "foo", notes = "bar") | @Operation(summary = "foo", description = "bar") |
@ApiParam | @Parameter |
@ApiResponse(code = 404, message = "foo") | ApiResponse(responseCode = "404", description = "foo") |
接下來我們對之前Controller中使用的注解進(jìn)行改造,對照上表即可,之前在@Api注解中被廢棄了好久又沒有替代的description屬性終于被支持了!
/** * 品牌管理Controller * Created by macro on 2019/4/19. */ @Tag(name = "PmsBrandController", description = "商品品牌管理") @Controller @RequestMapping("/brand") public class PmsBrandController { @Autowired private PmsBrandService brandService; private static final Logger LOGGER = LoggerFactory.getLogger(PmsBrandController.class); @Operation(summary = "獲取所有品牌列表",description = "需要登錄后訪問") @RequestMapping(value = "listAll", method = RequestMethod.GET) @ResponseBody public CommonResult<List<PmsBrand>> getBrandList() { return CommonResult.success(brandService.listAllBrand()); } @Operation(summary = "添加品牌") @RequestMapping(value = "/create", method = RequestMethod.POST) @ResponseBody @PreAuthorize("hasRole('ADMIN')") public CommonResult createBrand(@RequestBody PmsBrand pmsBrand) { CommonResult commonResult; int count = brandService.createBrand(pmsBrand); if (count == 1) { commonResult = CommonResult.success(pmsBrand); LOGGER.debug("createBrand success:{}", pmsBrand); } else { commonResult = CommonResult.failed("操作失敗"); LOGGER.debug("createBrand failed:{}", pmsBrand); } return commonResult; } @Operation(summary = "更新指定id品牌信息") @RequestMapping(value = "/update/{id}", method = RequestMethod.POST) @ResponseBody @PreAuthorize("hasRole('ADMIN')") public CommonResult updateBrand(@PathVariable("id") Long id, @RequestBody PmsBrand pmsBrandDto, BindingResult result) { CommonResult commonResult; int count = brandService.updateBrand(id, pmsBrandDto); if (count == 1) { commonResult = CommonResult.success(pmsBrandDto); LOGGER.debug("updateBrand success:{}", pmsBrandDto); } else { commonResult = CommonResult.failed("操作失敗"); LOGGER.debug("updateBrand failed:{}", pmsBrandDto); } return commonResult; } @Operation(summary = "刪除指定id的品牌") @RequestMapping(value = "/delete/{id}", method = RequestMethod.GET) @ResponseBody @PreAuthorize("hasRole('ADMIN')") public CommonResult deleteBrand(@PathVariable("id") Long id) { int count = brandService.deleteBrand(id); if (count == 1) { LOGGER.debug("deleteBrand success :id={}", id); return CommonResult.success(null); } else { LOGGER.debug("deleteBrand failed :id={}", id); return CommonResult.failed("操作失敗"); } } @Operation(summary = "分頁查詢品牌列表") @RequestMapping(value = "/list", method = RequestMethod.GET) @ResponseBody @PreAuthorize("hasRole('ADMIN')") public CommonResult<CommonPage<PmsBrand>> listBrand(@RequestParam(value = "pageNum", defaultValue = "1") @Parameter(description = "頁碼") Integer pageNum, @RequestParam(value = "pageSize", defaultValue = "3") @Parameter(description = "每頁數(shù)量") Integer pageSize) { List<PmsBrand> brandList = brandService.listBrand(pageNum, pageSize); return CommonResult.success(CommonPage.restPage(brandList)); } @Operation(summary = "獲取指定id的品牌詳情") @RequestMapping(value = "/{id}", method = RequestMethod.GET) @ResponseBody @PreAuthorize("hasRole('ADMIN')") public CommonResult<PmsBrand> brand(@PathVariable("id") Long id) { return CommonResult.success(brandService.getBrand(id)); } }
接下來進(jìn)行SpringDoc的配置,使用OpenAPI來配置基礎(chǔ)的文檔信息,通過GroupedOpenApi配置分組的API文檔,SpringDoc支持直接使用接口路徑進(jìn)行配置。
/** * SpringDoc API文檔相關(guān)配置 * Created by macro on 2022/3/4. */ @Configuration public class SpringDocConfig { @Bean public OpenAPI mallTinyOpenAPI() { return new OpenAPI() .info(new Info().title("Mall-Tiny API") .description("SpringDoc API 演示") .version("v1.0.0") .license(new License().name("Apache 2.0").url("https://github.com/macrozheng/mall-learning"))) .externalDocs(new ExternalDocumentation() .description("SpringBoot實戰(zhàn)電商項目mall(50K+Star)全套文檔") .url("http://www.macrozheng.com")); } @Bean public GroupedOpenApi publicApi() { return GroupedOpenApi.builder() .group("brand") .pathsToMatch("/brand/**") .build(); } @Bean public GroupedOpenApi adminApi() { return GroupedOpenApi.builder() .group("admin") .pathsToMatch("/admin/**") .build(); } }
結(jié)合SpringSecurity使用
由于我們的項目集成了SpringSecurity,需要通過JWT認(rèn)證頭進(jìn)行訪問,我們還需配置好SpringDoc的白名單路徑,主要是Swagger的資源路徑;
/** * SpringSecurity的配置 * Created by macro on 2018/4/26. */ @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity.csrf()// 由于使用的是JWT,我們這里不需要csrf .disable() .sessionManagement()// 基于token,所以不需要session .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers(HttpMethod.GET, // Swagger的資源路徑需要允許訪問 "/", "/swagger-ui.html", "/swagger-ui/", "/*.html", "/favicon.ico", "/**/*.html", "/**/*.css", "/**/*.js", "/swagger-resources/**", "/v3/api-docs/**" ) .permitAll() .antMatchers("/admin/login")// 對登錄注冊要允許匿名訪問 .permitAll() .antMatchers(HttpMethod.OPTIONS)//跨域請求會先進(jìn)行一次options請求 .permitAll() .anyRequest()// 除上面外的所有請求全部需要鑒權(quán)認(rèn)證 .authenticated(); } }
然后在OpenAPI對象中通過addSecurityItem方法和SecurityScheme對象,啟用基于JWT的認(rèn)證功能。
/** * SpringDoc API文檔相關(guān)配置 * Created by macro on 2022/3/4. */ @Configuration public class SpringDocConfig { private static final String SECURITY_SCHEME_NAME = "BearerAuth"; @Bean public OpenAPI mallTinyOpenAPI() { return new OpenAPI() .info(new Info().title("Mall-Tiny API") .description("SpringDoc API 演示") .version("v1.0.0") .license(new License().name("Apache 2.0").url("https://github.com/macrozheng/mall-learning"))) .externalDocs(new ExternalDocumentation() .description("SpringBoot實戰(zhàn)電商項目mall(50K+Star)全套文檔") .url("http://www.macrozheng.com")) .addSecurityItem(new SecurityRequirement().addList(SECURITY_SCHEME_NAME)) .components(new Components() .addSecuritySchemes(SECURITY_SCHEME_NAME, new SecurityScheme() .name(SECURITY_SCHEME_NAME) .type(SecurityScheme.Type.HTTP) .scheme("bearer") .bearerFormat("JWT"))); } }
測試
接下來啟動項目就可以訪問Swagger界面了,訪問地址:http://localhost:8088/swagger-ui.html
我們先通過登錄接口進(jìn)行登錄,可以發(fā)現(xiàn)這個版本的Swagger返回結(jié)果是支持高亮顯示的,版本明顯比SpringFox來的新;
然后通過認(rèn)證按鈕輸入獲取到的認(rèn)證頭信息,注意這里不用加bearer前綴;
之后我們就可以愉快地訪問需要登錄認(rèn)證的接口了;
看一眼請求參數(shù)的文檔說明,還是熟悉的Swagger樣式!
常用配置
SpringDoc還有一些常用的配置可以了解下,更多配置可以參考官方文檔。
springdoc: swagger-ui: # 修改Swagger UI路徑 path: /swagger-ui.html # 開啟Swagger UI界面 enabled: true api-docs: # 修改api-docs路徑 path: /v3/api-docs # 開啟api-docs enabled: true # 配置需要生成接口文檔的掃描包 packages-to-scan: com.macro.mall.tiny.controller # 配置需要生成接口文檔的接口路徑 paths-to-match: /brand/**,/admin/**
總結(jié)
在SpringFox的Swagger庫好久不出新版的情況下,遷移到SpringDoc確實是一個更好的選擇。今天體驗了一把SpringDoc,確實很好用,和之前熟悉的用法差不多,學(xué)習(xí)成本極低。而且SpringDoc能支持WebFlux之類的項目,功能也更加強大,使用SpringFox有點卡手的朋友可以遷移到它試試!
如果你想了解更多SpringBoot實戰(zhàn)技巧的話,可以試試這個帶全套教程的實戰(zhàn)項目(50K+Star):github.com/macrozheng/…
參考資料
- 項目地址:github.com/springdoc/s…
- 官方文檔:springdoc.org/
項目源碼地址 :https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-springdoc
更多關(guān)于SpringBoot API文檔工具SpringDoc的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JDK8新特性-java.util.function-Function接口使用
這篇文章主要介紹了JDK8新特性-java.util.function-Function接口使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04聊聊ResourceBundle和properties讀取配置文件的區(qū)別
這篇文章主要介紹了ResourceBundle和properties讀取配置文件的區(qū)別,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07SpringBoot中的@Configuration注解詳解
這篇文章主要介紹了SpringBoot中的@Configuration注解詳解,Spring Boot推薦使用JAVA配置來完全代替XML 配置,JAVA配置就是通過 @Configuration和 @Bean兩個注解實現(xiàn)的,需要的朋友可以參考下2023-08-08