【超详细】springboot + springdoc-openapi + knife4j 集成案例
作者:mmseoamin日期:2023-12-05

springdoc-openapi 简介

springdoc-openapijava库有助于使用 spring boot 项目自动生成 API 文档。 springdoc-openapi通过在运行时检查应用程序以根据 spring 配置、类结构和各种注释推断 API 语义来工作。

自动生成 JSON/YAML 和 HTML 格式 API 的文档。可以使用 swagger-api 注释通过注释来完成此文档。

该库支持:

  • OpenAPI3

    • SpringBoot (v1, v2 and v3)

      • JSR-303, specifically for @NotNull, @Min, @Max, and @Size.

        • Swagger-ui

          • OAuth 2

            • GraalVM 原生镜像

              为什么使用 springdoc-openapi🤔

              由于之前项目一直使用的是springfox3.0来集成swagger管理API接口文档,但目前springfox已经停止维护了。最近在升级底层框架时看到spring官方推荐使用springdoc,在自己一步一步查找相关资料时,发现国内对于这块的参考资料较少,也不全面。故写此篇文章来帮助大家快速集成。

              Knife4j简介

              Knife4j是一个集Swagger2和OpenAPI3为一体的增强解决方案。

              开始集成

              Maven引入

              首先在maven里引入springdoc-openapi:

              org.springdocspringdoc-openapi-ui1.6.15复制代码

              注释的区别

              这里需要注意,我们要用swagger3注释替换swagger2注释(它已经包含在springdoc-openapi-ui依赖项中)。swagger 3 注释的包是io.swagger.v3.oas.annotations:

              @Api -> @Tag@ApiIgnore -> @Parameter(hidden = true) 或 @Operation(hidden = true) 或 @Hidden@ApiImplicitParam -> @Parameter@ApiImplicitParams -> @Parameters@ApiModel -> @Schema@ApiModelProperty(hidden = true) -> @Schema(accessMode = READ_ONLY)@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:

              @Tag(name = "用户接口")@RestController@RequestMapping("sys/user")publicclassSysUserController {
                  @Resourceprivate ISysUserService sysUserService;
                  @Operation(summary = "分页查询")@GetMapping("page")public AjaxResult queryPage(SysUserPageDTO dto) {
                      PageInfopage= sysUserService.queryPage(dto);
                      return AjaxResult.success(page);
                  }
                  @Operation(summary = "详情")@GetMapping("{id}")public AjaxResult queryInfo(@PathVariable Long id) {
                      SysUserDTOdto= sysUserService.queryById(id);
                      return AjaxResult.success(dto);
                  }
                  @Operation(summary = "新增")@PostMappingpublic AjaxResult save(@RequestBody SysUserDTO dto) {
                      Longid= sysUserService.saveInfo(dto);
                      return AjaxResult.success(id);
                  }
              }
              复制代码

              DTO:

              @Schema(description = "用户 数据传输对象")@Data@Accessors(chain = true)publicclassSysUserDTOimplementsSerializable {
                  @Schema(description = "ID")private Long id;
                  @Schema(description = "用户名")private String userName;
                  @Schema(description = "真实姓名")private String realName;
                  @Schema(description = "密码")private String password;
                  @Schema(description = "性别(0男,1女)")private Integer sex;
                  @Schema(description = "电话号码")private String phone;
                  @Schema(description = "状态(0停用,1正常)")private Integer status;
              }
              复制代码

              配置

              配置文件,更多配置请看:springdoc 核心配置

              springdoc:api-docs:# 是否开启接口文档enabled:trueswagger-ui:# 持久化认证数据,如果设置为 true,它会保留授权数据并且不会在浏览器关闭/刷新时丢失persistAuthorization:true复制代码

              配置文档:

              ❗ 这里我更推荐将文档标题、作者等信息写到application里,然后通过@ConfigurationProperties引入,会更优雅😉

              @Configuration@AutoConfigureBefore(SpringDocConfiguration.class)publicclassOpenApiConfig {
                  privatestaticfinalStringTOKEN_HEADER="Authorization";
                  @Beanpublic OpenAPI openApi() {
                      // 针对 knife4j(增强UI),这里添加全局请求头(addParameters)无效,只能按组添加,待官方解决returnnewOpenAPI()
                              .components(
                                      newComponents().addSecuritySchemes(TOKEN_HEADER,
                                              newSecurityScheme()
                                                      .type(SecurityScheme.Type.APIKEY)
                                                      // 这里配置 bearer 后,你的请求里会自动在 token 前加上 Bearer
                                                      .scheme("bearer")
                                                      .bearerFormat("JWT")
                                      ).addParameters(TOKEN_HEADER,
                                              newParameter()
                                                      .in("header")
                                                      .schema(newStringSchema())
                                                      .name(tokenHeader)
                                      ))
                              .info(
                                      newInfo()
                                              .title("文档标题")
                                              .description("文档描述")
                                              .contact(newContact().name("作者").email("邮箱").url("可以写你的博客地址或不填"))
                                              // 参考 Apache 2.0 许可及地址,你可以不配此项
                                              .license(newLicense().name("Apache 2.0").url("https://www.apache.org/licenses/LICENSE-2.0.html"))
                                              .version("0.1")
                              )
                              // 引入外部的文档,我这里引得是 springdoc 官方文档地址,你可以不配此项
                              .externalDocs(newExternalDocumentation()
                                      .description("SpringDoc Full Documentation")
                                      .url("https://springdoc.org/")
                              );
                  }
                  /**
                   * GroupedOpenApi 是对接口文档分组,类似于 swagger 的 Docket
                   * 
                   * @return
                   */@Beanpublic GroupedOpenApi authApi() {
                      return GroupedOpenApi.builder()
                              // 组名
                              .group("认证接口")
                              // 扫描的路径,支持通配符
                              .pathsToMatch("/login")
                              // 扫描的包
                              .packagesToScan("com.demo.controller.auth")
                              .build();
                  }
                  
                  @Beanpublic GroupedOpenApi sysApi() {
                      return GroupedOpenApi.builder()
                              .group("系统接口")
                              .pathsToMatch("/sys/**")
                              // 添加自定义配置,这里添加了一个用户认证的 header,否则 knife4j 里会没有 header
                              .addOperationCustomizer((operation, handlerMethod) -> operation.security(
                                      Collections.singletonList(newSecurityRequirement().addList(TOKEN_HEADER)))
                              )
                              .build();
                  }
              }
              复制代码

              访问文档

              配置完成之后,就可以访问文档地址:http://localhost:${port}/${context-path}/swagger-ui/html.index

              ❗ 如果你加入了拦截器或引入了spring-security等权限框架,需要放通文档地址及静态资源:

              - /**/*.html
              - /**/*.css
              - /**/*.js
              - /**/api-docs/**
              复制代码

              至此一个简单的接口文档就生成了,是不是很简单😎

              集成knife4j

              Maven引入

              在maven里引入knife4j

              com.github.xiaoyminknife4j-openapi3-spring-boot-starter4.0.0复制代码

              ❗ 如果你使用的是SpringBoot3,需要注意:

              • Spring Boot 3 只支持OpenAPI3规范

                • Knife4j提供的starter已经引用springdoc-openapi的jar,开发者需注意避免jar包冲突

                  • JDK版本必须 >= 17

                    而且需要引入这个包:

                    com.github.xiaoyminknife4j-openapi3-jakarta-spring-boot-starter4.0.0复制代码

                    访问文档地址

                    然后你就可以直接访问文档地址了:http://localhost:${port}/${context-path}/doc.html

                    至此我们就集成完了,有其他疑问欢迎在评论区提出来😊

                    作者:penga

                    链接:https://juejin.cn/post/7214015651828006967