Springdoc使用及规范

Springdoc使用及规范

Springdoc对于Springfox3.0.0的优点

  • Springfox对swagger 3的新注解支持的不够,目前已知@Tag和Schema不生效
  • Springdoc支持最新版本的Spring和SpringBoot,Springfox不支持
  • Springfox更新缓慢,最近一次更新在20年一月,Springdoc有日常更新

集成Springdoc

mvc 项目

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.7.0</version>
</dependency>

webflux项目

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-webflux-ui</artifactId>
    <version>1.7.0</version>
</dependency>

默认不用添加额外配置就能访问swaggger ui界面
默认访问地址:http://server:port/context-path/swagger-ui.html
关于Swagger 3 注解的使用见Swagger 3 注解使用及规范

(可选)配置

springdoc:
  documentation:
    enabled: true # 是否开启springdoc openapi端点 默认true
    #path: /v3/api-docs ## springdoc openapi端点路径 默认/v3/api-docs
  swagger-ui:
    enabled: true ## 是否开启 swagger ui 默认true
    path: my-swagger.html ## 自定义 swagger访问路径 默认swagger-ui.html

更多配置参见Springdoc-openapi Properties

迁移Springfox到Springdoc

  • 移除所有Srpingfox和Swagger 2的依赖,加入Springdoc的依赖集成Springdoc

  • 用Swagger 3的注解替换Swagger 2的注解。可以通过IDEA快捷键ctr+shift+r快速替换

    • @Api@Tag

    • @ApiIgnore@Parameter(hidden = true) or @Operation(hidden = true) or @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”)

  • (可选)如果有多个Docket,用GroupedOpenApi替换

    Springfox:

    @Bean
    public Docket publicApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("org.github.springshop.web.public"))
                .paths(PathSelectors.regex("/public.*"))
                .build()
                .groupName("springshop-public")
                .apiInfo(apiInfo());
    }
    
    @Bean
    public Docket adminApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("org.github.springshop.web.admin"))
                .paths(PathSelectors.regex("/admin.*"))
                .apis(RequestHandlerSelectors.withMethodAnnotation(Admin.class))
                .build()
                .groupName("springshop-admin")
                .apiInfo(apiInfo());
    }
    

    Springdoc:

    @Bean
    public GroupedOpenApi publicApi() {
        return GroupedOpenApi.builder()
                .group("springshop-public")
                .pathsToMatch("/public/**")
                .build();
    }
    @Bean
    public GroupedOpenApi adminApi() {
        return GroupedOpenApi.builder()
                .group("springshop-admin")
                .pathsToMatch("/admin/**")
                .addOpenApiMethodFilter(method -> method.isAnnotationPresent(Admin.class))
                .build();
    }
    
    

    如果只有一个Docket,可以通过配置来代替

      springdoc.packagesToScan=package1, package2
      springdoc.pathsToMatch=/v1, /api/balance/**
    
  • (可选) 自定义文档信息

    @Bean
    public OpenAPI springdocOpenAPI() {
        return new OpenAPI()
                .info(new Info().title("SpringShop API")
                .description("Spring shop sample application")
                .version("v0.0.1")
                .license(new License().name("Apache 2.0").url("http://springdoc.org")))
                .externalDocs(new ExternalDocumentation()
                .description("SpringShop Wiki Documentation")
                .url("https://springshop.wiki.github.org/docs"));
    }
    

Swagger 3 使用及规范

统一Swagger配置

所有Swagger有关的配置都应通过开关springdoc.api-docs.enabled来统一控制,这样可以根据实际需求来开启/关闭Swagger,例如生产环境需要关闭Swagger。

案例

Swagger配置:

@Configuration
@ConditionalOnProperty(value = "springfox.documentation.enabled", havingValue = "true", matchIfMissing = true)
public class SwaggerConfig {
    
    @Bean
    public GroupedOpenApi publicApi() {
        return GroupedOpenApi.builder()
            .group("springshop-public")
            .pathsToMatch("/public/**")
            .build();
    }
    @Bean
    public GroupedOpenApi adminApi() {
        return GroupedOpenApi.builder()
            .group("springshop-admin")
            .pathsToMatch("/admin/**")
            .addOpenApiMethodFilter(method -> method.isAnnotationPresent(Admin.class))
            .build();
    }
}

不同环境创建不同配置文件

  • 开发环境,需要开启swagger,application-dev.yml内容

      springdoc:
        documentation:
          enabled: true
    
  • 生产环境,需要关闭swagger防止风险。application-master.yml内容

    springdoc:
      documentation:
        enabled: false
    

指定配置生效配置

spring:
  profiles:
    active: master // 开发环境改为dev

组件的Springdoc依赖设置为可选

当工程是个功能组件时,依赖设置为可选,由组件的使用方去决定要不要引入。

<dependency>
    <groupId>org.springdoc</groupId>
    <artifactId>springdoc-openapi-ui</artifactId>
    <version>1.7.0</version>
    <optional>true</optional>
</dependency>

废弃的接口应及时隐藏

    @Hidden
    @GetMapping("")
    public JsonResult<String> queryRoleList() {
        return JsonResult.ok();
    }

避免分组名称重复

不同模块可以各自配置分组。为了避免分组名称出现重复,分组名称应尽量按照"项目-模块-功能"进行命名

public class OemClientSwaggerConfig {

    @Bean("koca-admin-oem-client-openapi")
    public GroupedOpenApi api() {
        return GroupedOpenApi.builder().group("koca-admin-oem-client")
            .packagesToScan("com.szkingdom.koca.admin.oem.client")
            .build();
    }

}

常用注解

  1. @OpenAPIDefinition
    用于描述标签、文档信息、安全配置及外部文档,用在类上。一个应用中只会生效一个。
    常用参数:
  • info:描述文档信息,详情见以下的 @Info
  • tags:定义标签列表,详情见以下的 @Tag
  • servers:目标服务器连接列表,详情见以下的 @Server
  • externalDocs:API 的一些外部文档,详情见以下的 @ExternalDocumentation

示例:

@OpenAPIDefinition(
    tags = {
        @Tag(name = "用户管理", description = "用户模块操作"),
        @Tag(name = "角色管理", description = "角色模块操作")
    },
    info = @Info(
        title = "用户接口 API 文档",
        description = "用户数据管理......",
        version = "1.0.0",
        contact = @Contact(
            name = "lanweihong",
            email = "986310747@qq.com",
            url = "https://www.lanweihong.com"
        ),
        license = @License(
            name = "Apache 2.0",
            url = "http://www.apache.org/licenses/LICENSE-2.0.html"
        )
    ),
    servers = {
        @Server(description = "生产环境服务器", url = "https://xxxx.com/api/v1"),
        @Server(description = "测试环境服务器", url = "https://test.xxxx.com/api/v1")
    },
    security = @SecurityRequirement(name = "Oauth2"),
    externalDocs = @ExternalDocumentation(
        description = "项目编译部署说明",
        url = "http://localhost/deploy/README.md"
    )
)
  1. @Info
    用于说明文档信息,用在 @OpenAPIDefinition 中。
    常用参数:
  • title:应用标题
  • description:应用描述
  • contact:联系信息,详情看 @Contact
  • license:许可信息,详情看 @License
  • version:版本

示例:

@OpenAPIDefinition(
        info = @Info(
            title = "用户接口 API 文档",
            description = "用户数据管理......",
            version = "1.0.0",
            contact = @Contact(name = "lanweihong", email = "986310747@qq.com", url = "https://www.lanweihong.com"),
            license = @License(name = "Apache 2.0", url = "http://www.apache.org/licenses/LICENSE-2.0.html")
        )
)
  1. @Tag
    对一个 operation 进行说明或定义的标签,用在类或方法上,也可以用在 @OpenAPIDefinition 中定义标签。
    常用参数:
  • name:名称
  • description:描述

示例:
用在类上:

@Tag(name = "用户管理")
@RestController
public class UserController {
    // ···
}

用在 @OpenAPIDefinition 中定义标签:


@OpenAPIDefinition(
        tags = {
            @Tag(name = "用户管理", description = "用户模块操作"),
            @Tag(name = "角色管理", description = "角色模块操作")
        }
)
  1. @Contact
    用于描述联系人信息,用在 @Info 中。
    常用参数:
  • name:唯一名称(个人/组织)
  • url:指向联系人信息的 URL
  • email:邮箱

示例:

@OpenAPIDefinition(
    info = @Info(
        contact = @Contact(
                name = "Li.chen", 
                email = "mail", 
                url = "www"
        )
    )
)
  1. @License
    用于描述许可证信息,用在 @Info 中。
    常用参数:
  • name:许可证名称
  • url:指向许可证的 URL

示例:

@OpenAPIDefinition(
    servers = {
        @Server(description = "生产环境服务器", url = "https://xxxx.com/api/v1"),
        @Server(description = "测试环境服务器", url = "https://test.xxxx.com/api/v1")
    }
)
  1. Server
    用于配置目标主机,用在 @OpenAPIDefinition 中。
    常用参数:
  • url:主机地址
  • description:主机描述

示例:

@OpenAPIDefinition(
    servers = {
        @Server(description = "生产环境服务器", url = "https://xxxx.com/api/v1"),
        @Server(description = "测试环境服务器", url = "https://test.xxxx.com/api/v1")
    }
)
  1. @Operation
    用于说明方法用途,用在方法上。
    参数:
  • summary:方法概要,方法的一个简单介绍,建议 120 个字符内
  • description:方法描述,一般是很长的内容
  • hidden:是否隐藏

示例:

@Operation(summary = "查询用户列表", description = "返回所有用户数据")
@GetMapping("/users")
public String getUseList() {
    return "";
}
  1. @Parameter
    用于说明方法参数,用在方法参数上。
    参数:
  • name:指定的参数名
  • in:参数位置,可选 query、header、path 或 cookie,默认为空,表示忽略
  • description:参数描述
  • required:是否必填,默认为 false

示例:

@Operation(summary = "删除用户")
@DeleteMapping("/users/{username}")
public JsonResult<UserVO> deleteUserByName(
        @Parameter(name = "username", in = ParameterIn.PATH, description = "用户名", required = true) 
        @PathVariable("username") String userName
    ) {
    // TODO
    return JsonResult.ok();
}
  1. @ApiResponse
    用于说明一个响应信息,用在 @ApiResponses 中。
    参数:
  • responseCode:HTTP 响应码
  • description:描述

示例:

@Operation(summary = "通过用户名查询用户", description = "根据用户名查询用户详细信息")
@ApiResponses(value = {
        @ApiResponse(responseCode = "200", description = "请求成功"),
        @ApiResponse(responseCode = "404", description = "用户不存在", content = @Content)
})
@GetMapping("/{username}")
public JsonResult<UserVO> getUserByName(@Parameter(description = "用户名", required = true) @PathVariable("username") String userName) {
    // TODO
    return JsonResult.ok();
}
  1. @ApiResponses
    用于说明一组响应信息,比如一个请求可能返回多种响应情况,比如成功信息(200),也有可能抛参数异常(400),用在方法上。
    参数:
  • value:@ApiResponse 数组

示例参考以上的 @ApiResponse
11. @Schema
用于描述数据对象信息或数据对象属性,比如各种 POJO 类及属性,用在类或类属性上。
参数:

  • name:属性名称
  • description:属性描述
  • required:是否必须
  • minLength:字符最小长度
  • maxLength:字符最大长度

示例:

@Schema(description = "用户实体")
public class UserVO {

    @Schema(description = "用户名")
    private String userName;

    @Schema(description = "邮箱")
    private String email;

    // Getter And Setter ...
}
  1. @Hidden
    用于隐藏资源、类或属性,用在类、方法或属性上。
    示例:
@RestController
@RequestMapping("/api/roles")
// 隐藏整个 RoleController
@Hidden
public class RoleController {

    @GetMapping("")
    public JsonResult<String> queryRoleList() {
        return JsonResult.ok();
    }
}

:+1: