Springfox与SpringDoc——swagger如何选择(SpringDoc入门)

天翼云开发者社区
• 阅读 443

本文分享自天翼云开发者社区@《Springfox与SpringDoc——swagger如何选择(SpringDoc入门)》,作者: 才开始学技术的小白

0.引言 之前写过一篇关于swagger(实际上是springfox)的使用指南(https://www.ctyun.cn/developer/article/371704742199365),涵盖了本人在开发与学习的时候碰到的各种大坑。但由于springfox已经不更新了,很多项目都在往springdoc迁移 笔者也是花了一些时间试了一下这个号称“把springfox按在地下摩擦”的springdoc究竟好不好使,本文就来简单介绍下springdoc的使用以及优劣势

1.引入maven依赖 这里有个大坑一定要注意!!! 如果你跟我一样,现在使用的是springfox,但是想往springdoc迁移,结果试了一下发现还是springfox好用/懒得改那么多注解,还是想换回springfox,一定要把springdoc的maven依赖删掉!!!不然springboot会默认你用的是springdoc,导致swagger界面出不来 org.springdoc springdoc-openapi-ui 1.6.11

2.springdoc配置类 实际上springdoc的配置非常简单,使用的是OpenAPI类与GroupedOpenApi来配置 /**

  • SpringDoc API文档相关配置

  • Created by macro on 2023/02/02.

  • /@Configurationpublic class SpringDocConfig { @Bean public OpenAPI mallTinyOpenAPI() {

      return new OpenAPI()
              .info(new Info().title("CTYUN API")
                      .description("SpringDoc API 演示")
                      .version("v1.0.0")
                      .license(new License().name("Apache 2.0").url("https://github.com/")))
              .externalDocs(new ExternalDocumentation()
                      .description("SpringBoot项目")
                      .url("http://www.ctyun.com"));

    }

    @Bean public GroupedOpenApi adminApi() {

      return GroupedOpenApi.builder()
              .group("admin")
              .pathsToMatch("/**")
              .build();

    } //可以创建不同的GroupedOpenApi来判断不同的controller @Bean public GroupedOpenApi userApi() {

      return GroupedOpenApi.builder()
              .group("user")
              .pathsToMatch("/user/**")
              .build();

    }}

3.启动 默认配置之后直接进入:http://localhost:8080/swagger-ui/index.html 即可 注意这里与springfox略有不同(http://localhost:8080/swagger-ui.html) Springfox与SpringDoc——swagger如何选择(SpringDoc入门)

4.与SpringFox的注解对照 Springfox与SpringDoc——swagger如何选择(SpringDoc入门)

5.SpringDoc基本注解用法 这里转载一个写的非常全面的示例接口,原文可以去看:https://blog.csdn.net/zhenghongcs/article/details/123812583 /**

  • 品牌管理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> 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> 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 brand(@PathVariable("id") Long id) {

      return CommonResult.success(brandService.getBrand(id));

    }}

6.与SpringSecurity的结合 如果项目中使用了SpringSecurity,需要做两个配置来让springdoc正常使用: 1.在SpringSecurity配置类中放行白名单:"/v3/api-docs/", "/swagger-ui/" 2.在SpringDoc配置中增加对应内容,如下: @Configurationpublic class SpringDocConfig {

private static final String SECURITY_SCHEME_NAME = "BearerAuth";

@Bean
public OpenAPI managerOpenAPI() {

    return new OpenAPI()
            .info(new Info().title("Galaxy-Cluster-Manager后端接口文档")
                    .description("提供给前端界面(portal)的接口文档")
                    .version("v1.0.0")
                    .license(new License().name("galaxy 1.2.0").url("https://gitlab.ctyun.cn/hpc/galaxy-parent/-/tree/v1.2.0")))
            .externalDocs(new ExternalDocumentation()
                    .description("弹性高性能计算(CTHPC)")
                    .url("http://www.ctyun.cn"))
            //以下是针对SpringSecurity的设置,同时还有设置白名单
            .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")));
}
@Bean
public GroupedOpenApi publicApi() {
    return GroupedOpenApi.builder()
            .group("portal")
            .pathsToMatch("/api/**")
            .build();
}

}

7.SpringDoc使用对象作为Query参数的问题 实际上springfox也会有这个问题,使用对象作为query传参的时候,页面通常是这样的: Springfox与SpringDoc——swagger如何选择(SpringDoc入门)

就没有办法逐个描述参数,也不能逐个调试(只能用json调试),非常的麻烦;springdoc有一个解决这个问题非常方便的注解:@ParameterObject 比如某一个控制器的入参是User user,我们只需要在这前面加上注解变为:@ParameterObject User user 即可,结果如下; Springfox与SpringDoc——swagger如何选择(SpringDoc入门)

这里也有一个大坑:参数的类型可能会不正确,比如这里我们的id参数实际上是int,但显示出来是string,这个时候就需要我们在User类的属性中加上对应的注解,比如: @Parameter(description = "id传参",example = "6") 再重启UI就会发现参数类型正确了

8.SpringDoc配置扫包范围 有的时候仅仅使用@Hidden并不能满足我们的需要,因为可能需要配置不同group的controller类,这个时候就需要在配置类中取设置扫包范围代码如下: Springfox与SpringDoc——swagger如何选择(SpringDoc入门)

9.SpringDoc的优劣势 优势:SpringDoc有着非常好看的UI,以及比Springfox更加完善的参数注解体系,看起来非常舒服,并且还在不断更新与维护中 劣势:一些冷门功能还不完善,比如: a.有十个接口,他们的url是一样的但是可以通过query参数来分别(如:@PostMapping(params = "action=QueryUsers"))这个时候springdoc只能通过扫包范围配置,来写多个GroupOpenApi来解决,非常的麻烦;springfox可以在docket创建的时候使用:docket.enableUrlTemplating(true); 这个方法即可解决 b.springdoc的网络配置可能会与springfox冲突,如果迁移,需要逐个尝试网络配置是否合适(主要是GsonHttpMessageConverter的配置) c.兼容性问题仍需要观望,相对于springfox,springdoc的兼容性并没有那么好,在许多时候可能会出现序列化的乱码问题

总结:如果当前项目/工程已经集成了完备的springfox,建议不要轻易尝试迁移到springdoc,尤其是接口类型比较复杂、springfox配置docket比较多的项目;但如果是从头开始的项目,由于接口相对比较简单,可以采用springdoc,毕竟可以获得更加清晰明了的显示界面与参数解释。

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
PPDB:今晚老齐直播
【今晚老齐直播】今晚(本周三晚)20:0021:00小白开始“用”飞桨(https://www.oschina.net/action/visit/ad?id1185)由PPDE(飞桨(https://www.oschina.net/action/visit/ad?id1185)开发者专家计划)成员老齐,为深度学习小白指点迷津。
双十一预售活动分析
2022年双十一促销活动已经开始,大家应该都提前开始关注今年双十一活动的时间表了吧?2022年10月24日晚8:00天猫双11预售时间,第一波销售时间10月31日晚8:0,第二波销售时间11月10日晚8:00;天猫双11的优惠力度是跨店每满30050
基于SpringBoot实现单元测试的多种情境/方法(二)
本文分享自天翼云开发者社区@《》,作者:才开始学技术的小白1Mock基础回顾在上一篇分享中我们详细介绍了简单的、用mock来模拟接口测试环境的方法,具体的使用样例我们再回顾一下:1.首先是最简单的不需要传参的示例,需要注意的是,可能@Resource这个注
Stella981 Stella981
3年前
Spring Boot demo系列(八):Swagger
2021.2.24更新1概述Swagger主要用于生成API文档,本文演示了如何使用目前最新的OpenAPI3以及Swagger来进行接口文档的生成。2依赖<dependency<groupIdorg.springdoc</groupId
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Jenkins 插件开发之旅:两天内从 idea 到发布(上篇)
本文首发于:Jenkins中文社区(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fjenkinszh.cn)!huashan(https://oscimg.oschina.net/oscnet/f499d5b4f76f20cf0bce2a00af236d10265.jpg)
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
使用element-ui 的上传组件upload完成自定义上传到天翼云oss云服务器
本文分享自天翼云开发者社区@《》,作者:我是小朋友首先配置天翼云,如下操作1、要求在使用OOS之前,首先需要在www.ctyun.cn注册一个账号(Account)。创建AccessKeyId和AccessSecretKey。AccessKeyId和Acc
HPC调度基础:slurm集群的部署
本文分享自天翼云开发者社区@《》,作者:才开始学技术的小白0.引言HPC(HighPerformanceComputing,以下简称HPC)是一个领域,试图在任何时间点和技术上对于相关技术、方法和应用等多种方面实现最大的计算能力;换而言之其目的就是求解一类
天翼云开发者社区
天翼云开发者社区
Lv1
天翼云是中国电信倾力打造的云服务品牌,致力于成为领先的云计算服务提供商。提供云主机、CDN、云电脑、大数据及AI等全线产品和场景化解决方案。
文章
696
粉丝
15
获赞
40