之前在SpringBoot我的项目中始终应用的是SpringFox提供的Swagger库,上了下官网发现曾经有靠近两年没出新版本了!前几天降级了SpringBoot 2.6.x 版本,发现这个库的兼容性也越来越不好了,有的罕用注解属性被废除了竟然都没提供代替!无心中发现了另一款Swagger库SpringDoc
,试用了一下十分不错,举荐给大家!
SpringBoot实战电商我的项目mall(50k+star)地址:https://github.com/macrozheng/mall
SpringDoc简介
SpringDoc是一款能够联合SpringBoot应用的API文档生成工具,基于OpenAPI 3
,目前在Github上已有1.7K+Star
,更新发版还是挺勤快的,是一款更好用的Swagger库!值得一提的是SpringDoc不仅反对Spring WebMvc我的项目,还能够反对Spring WebFlux我的项目,甚至Spring Rest和Spring Native我的项目,总之十分弱小,上面是一张SpringDoc的架构图。
应用
接下来咱们介绍下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迁徙
- 咱们先来看下常常应用的Swagger注解,看看SpringFox的和SpringDoc的有啥区别,毕竟比照已学过的技术能该快把握新技术;
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中应用的注解进行革新,对照上表即可,之前在
@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 = "每页数量") 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)); }}
- 接下来进行SpringDoc的配置,应用
OpenAPI
来配置根底的文档信息,通过GroupedOpenApi
配置分组的API文档,SpringDoc反对间接应用接口门路进行配置。
/** * SpringDoc API文档相干配置 * Created by macro on 2022/3/4. */@Configurationpublic 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实战电商我的项目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(); }}
联合SpringSecurity应用
- 因为咱们的我的项目集成了SpringSecurity,须要通过JWT认证头进行拜访,咱们还需配置好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)//跨域申请会先进行一次options申请 .permitAll() .anyRequest()// 除下面外的所有申请全副须要鉴权认证 .authenticated(); }}
- 而后在
OpenAPI
对象中通过addSecurityItem
办法和SecurityScheme
对象,启用基于JWT的认证性能。
/** * SpringDoc API文档相干配置 * Created by macro on 2022/3/4. */@Configurationpublic 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实战电商我的项目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...
- 咱们先通过登录接口进行登录,能够发现这个版本的Swagger返回后果是反对高亮显示的,版本显著比SpringFox来的新;
- 而后通过认证按钮输出获取到的认证头信息,留神这里不必加
bearer
前缀;
- 之后咱们就能够欢快地拜访须要登录认证的接口了;
- 看一眼申请参数的文档阐明,还是相熟的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/**
总结
在SpringFox的Swagger库良久不出新版的状况下,迁徙到SpringDoc的确是一个更好的抉择。明天体验了一把SpringDoc,的确很好用,和之前相熟的用法差不多,学习老本极低。而且SpringDoc能反对WebFlux之类的我的项目,性能也更加弱小,应用SpringFox有点卡手的敌人能够迁徙到它试试!
如果你想理解更多SpringBoot实战技巧的话,能够试试这个带全套教程的实战我的项目(50K+Star):https://github.com/macrozheng/mall
参考资料
- 我的项目地址:https://github.com/springdoc/...
- 官网文档:https://springdoc.org/
我的项目源码地址
https://github.com/macrozheng...