Swagger3快速构建OpenApi3.0接口文档
By: Date: 2021年10月4日 Categories: 程序 标签:

做项目经常要写的,不只是代码,也不是寂寞,而是文档。项目文档,设计文档,接口文档等等。那接口文档怎么写,大家都知道用Swagger。但一说到Swagger,就不得不提一下OpenAPI。简单来说,OpenAPI简称OAS,即OpenAPI Specification,是一个用于定义和描述API的语言规范,可以通过这套规范,在向第三方的开发者提供对外暴露的接口服务时,大家达成统一的标准。

Swagger是套工具,Swagger2.0团队将其API规范捐献给OpenAPI的组织,再经过组织的发展与完善之后,OpenAPI3.0发布。Swagger3.0在2017年发布,支持OpenAPI3.0,提供了可以使用JSON,YAML编写API文档的功能,并能更好的支持restful接口。项目中要支持OpenAPI3.0我们常用的组件有两个,一个是springfox,还有一个则是springdoc。有什么区别呢?我们以前使用swagger都用的是springfox2.0,而springfox3.0是将原来的Swagger2.0升级到Swagger3.0来支持OpenAPI3.0,也就是说我们原先使用的springfox只要升级下版本号,就可以支持OpenAPI3.0的协议了。springdoc是全新的基于Swagger的一个组件,更早支持OpenAPI3.0的标准,并兼容spring框架。在Swagger2.0的时候,为了支持OpenAPI3.0,很多项目都采用了这个组件,到目前为止也更为流行,下面简单的写下基础的配置。


1.springfox

添加springfox依赖:

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

增加配置类:

@Configuration
@EnableOpenApi
@ConditionalOnProperty(value = "springfox.documentation.enabled", havingValue = "true", matchIfMissing = true)
public class Swagger3Config {

    @Bean
    public Docket createBizApi() {
        return new Docket(DocumentationType.OAS_30)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.st.storyadmin.controller.biz"))
                .paths(PathSelectors.regex("/biz.*"))
                .build()
                .globalRequestParameters(this.getGlobalRequestParameters())
                .globalResponses(HttpMethod.GET, getGlobalResonseMessage())
                .globalResponses(HttpMethod.POST, getGlobalResonseMessage())
                .groupName("业务处理");
    }

    @Bean
    public Docket createBaseInfoApi() {
        return new Docket(DocumentationType.OAS_30)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.st.storyadmin.controller.baseinfo"))
                .paths(PathSelectors.regex("/baseinfo.*"))
                .build()
                .globalRequestParameters(this.getGlobalRequestParameters())
                .globalResponses(HttpMethod.GET, getGlobalResonseMessage())
                .globalResponses(HttpMethod.POST, getGlobalResonseMessage())
                .groupName("基础配置");
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Story-Admin系统后台服务API接口文档")
                .description("Story-Admin系统后台API接口")
                .version("1.0")
                .build();
    }

    //生成全局通用参数
    private List<RequestParameter> getGlobalRequestParameters() {
        List<RequestParameter> parameters = new ArrayList<>();
        parameters.add(new RequestParameterBuilder()
                .name("appid").description("AppId")
                .required(true).in(ParameterType.QUERY)
                .query(q -> q.model(m -> m.scalarModel(ScalarType.STRING)))
                .required(false).build());
        return parameters;
    }

    //生成通用响应信息
    private List<Response> getGlobalResonseMessage() {
        List<Response> responseList = new ArrayList<>();
        responseList.add(new ResponseBuilder()
        .code("404")
        .description("找不到资源").build());
        return responseList;
    }
}

好吧就这么简单,最终的效果放在后面了。


2.springdoc

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

这里我们将所有的API接口按照包或者请求路径分为三个组,可以通过定义三个 GroupedOpenApi实现:

@Configuration
public class OpenApiConfig {

    @Bean
    public GroupedOpenApi createBaseApi() {
        return GroupedOpenApi.builder()
                .group("基础配置")
                .packagesToScan("com.st.storyadmin.controller.baseinfo")
                //.pathsToMatch("/baseinfo/**")
                .build();
    }

    @Bean
    public GroupedOpenApi createBizApi() {
        return GroupedOpenApi.builder()
                .group("业务处理")
                .packagesToScan("com.st.storyadmin.controller.biz")
                //.pathsToMatch("/biz/**")
                .build();
    }

    @Bean
    public GroupedOpenApi createPublicApi() {
        return GroupedOpenApi.builder()
                .group("公共模块")
                .packagesToScan("com.st.storyadmin.controller.pub")
                //.pathsToMatch("/public/**")
                .build();
    }

    @Bean
    public OpenAPI springShopOpenAPI() {
        return new OpenAPI()
                .info(new Info().title("Story-Admin系统后台服务API接口文档")
                        .description("Story-Admin系统后台服务API接口文档")
                        .version("v0.0.1")
                        .license(new License().name("Apache 2.0").url("http://springdoc.org")))
                .externalDocs(new ExternalDocumentation()
                        .description("Story-Admin Documentation")
                        .url("https://story-admin.wiki.github.org/docs"));
    }
}

当然也可以按照注释中的代码,根据URI来进行匹配分组,那么我们访问接口的默认地址就是 http://localhost:8080/swagger-ui.html。

如果想要修改上面的API文档地址,可以通过下面的配置轻松实现。

#OpenApi
springdoc:
  api-docs:
    path: /api/data
  swagger-ui:
    path: /api/index.html

这时,我们的文档地址可就变成了 http://localhost:8080/api/index.html 。

那么我们Controller上的注解要怎么写?
引用下springdoc官网的话:

将swagger 2注解替换为swagger 3注解(它已经包含在springdoc openapi ui依赖项中)。swagger 3注释的包是io.swagger.v3.oas.annotations。

简单来说Swagger2的注解已经被新的注解替换了,举个最简单的例子:

@RestController
@Tag(name = "查询方案配置接口")
@RequestMapping(value = "/baseinfo/scheme")
public class BaseQuerySchemeController {

    @GetMapping(value = "/getAllModules")
    @Operation(summary = "获取所有模块标识")
    public Result<Set<String>> getAllModules() {
        //...
    }
}

@Schema(title = "查询方案中条件Vo")
public class GeneralFilterVo {
    @Schema(title="模块")
    String module;
    @Schema(title="属性描述")
    String propLabel;
    //...
}

下面则是从官网拿过来的,全部注解的变更:

@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")

好了,关于springfox和springdoc引用后最终的效果如下:


3.Knife4j

有的人会觉得Swagger的页面比较难看,那么可以试试Knife4j,它是基于swagger2.0的版本,重写了Swagger的UI,因此目前还不支持OpenApi3.0的标准。

首先添加依赖:

<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>2.0.4</version>
</dependency>

增加配置类

@Configuration
@EnableSwagger2
@EnableKnife4j
public class SwaggerConfig {

    @Bean
    public Docket createRestApi() {
        List<Parameter> aParameters = Lists.newArrayList();
        return new Docket(DocumentationType.SWAGGER_2)
                .globalOperationParameters(aParameters)
                .apiInfo(apiInfo())
                .groupName("业务处理")
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.st.storyadmin"))
                .paths(PathSelectors.any())
                .build()
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
    }

    /**
     * 登陆验证配置
     * @return
     */
    private List<ApiKey> securitySchemes() {
        List<ApiKey> apiKeys = new ArrayList();
        ApiKey apiKey = new ApiKey("Authorization", SecurityConsts.REQUEST_AUTH_HEADER, "header");
        apiKeys.add(apiKey);
        return  apiKeys;
    }

    /**
     * 登陆验证配置
     * @return 
     */
    private List<SecurityContext> securityContexts() {
        List<SecurityContext> securityContextList = new ArrayList();
        SecurityContext securityContext = SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.any())
                .build();
        securityContextList.add(securityContext);
        return securityContextList;
    }
    /**
     * 登陆验证配置
     * @return
     */
    public List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        List<SecurityReference> securityReferenceList = new ArrayList<>();
        securityReferenceList.add(new SecurityReference("Authorization", authorizationScopes));
        return securityReferenceList;
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Story-Admin系统RESTful APIs文档说明")
                .description("相关接口构建RESTful APIs")
                .termsOfServiceUrl("")
                .version("1.0")
                .build();
    }
}

到这里就结束了,当然配置起来还是相对简单的,效果如下:


4.相关链接

  1. Swagger官网
  2. Spingdoc官网
  3. knife4j官网

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注