SpringBoot集成Swagger

1OpenAPI规范

1.1介绍

OpenAPI规范(OAS)定义了一个标准的、与语言无关的HTTP api接口,它允许人类和计算机发现和理解服务的功能,而无需访问源代码、文档或通过网络流量检查。正确定义后,使用者可以用最少的实现逻辑理解远程服务并与之交互。

OpenAPI3.1.0规范详情请参阅Swagger官网:https://swagger.io/specification/

1.2OAS与Swagger关系

Swagger 和 OpenAPI 实际上是密切相关的概念。Swagger 是一种用于设计、构建、文档化和消费 RESTful API 的工具集,而 OpenAPI 是 Swagger 的规范化版本。

具体来说,OpenAPI Specification(OAS)是一个基于 JSON 或 YAML 格式的文档规范,用于描述和定义 API 的结构、操作、参数、响应等。它提供了一种标准化的方式,使得不同的开发团队可以理解和交流关于 API 的信息。

Swagger 以前是由 SmartBear Software 开发并维护的一组工具和开源项目,包括 Swagger UI、Swagger Editor 等。然而,在 Swagger 规范化之后,Swagger 社区和规范正式改名为 OpenAPI。因此,Swagger 和 OpenAPI 实际上是同一个东西,只是 Swagger 是之前版本的称呼,而 OpenAPI 是 Swagger 规范化后的称呼。

因此,当人们谈论 Swagger 时,通常指的是 OpenAPI Specification,即用于描述和定义 API 的规范。而在实际使用中,Swagger 仍然是一个广泛使用的术语,用来表示使用 Swagger 工具集和规范进行 API 开发和文档化的过程。

2Springfox

Springfox 是一个用于将 Swagger 集成到 Spring Boot 应用程序中的库。它允许你使用 Swagger 注解来描述和定义 API,自动生成和展示 API 文档,并提供一个交互式的 UI 界面来测试和探索 API。

具体来说,Springfox 提供了以下功能和组件:

  1. 自动生成 API 文档:在 Spring Boot 应用程序中使用 Springfox,它会自动解析你的 API 控制器和注解,并生成符合 Swagger 规范的 API 文档。

  2. Swagger UI 支持:Springfox 集成了 Swagger UI,它提供了一个漂亮而易于使用的交互式界面,用于浏览和测试 API。你可以通过访问 /swagger-ui.html 路径来访问 Swagger UI。

  3. API 注解支持:Springfox 支持所有的 Swagger 注解,例如 @Api@ApiOperation@ApiParam 等。你可以在你的 API 控制器和模型类中使用这些注解来定义 API 的结构、操作、参数等信息。

  4. API 文档自定义:Springfox 提供了很多配置选项,可以定制生成的 API 文档的外观和行为。你可以通过配置类和属性来修改标题、版本、路径等信息,并应用各种定制化的样式和模板。

使用 Springfox,你可以轻松地将 Swagger 集成到 Spring Boot 应用程序中,并自动生成和展示 API 文档。这样,你可以更方便地开发、测试和文档化你的 RESTful API。

Springfox参考文档:http://springfox.github.io/springfox/docs/current/

截止到2023年7月15日10:44:32,最新版本为3.0.0,那就以该版本为例演示SpringBoot的集成过程。

2.1Maven依赖

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

2.2Swagger配置类

下面这段代码是官网的写法,我们先来看注释看一下代码的作用是什么。

package springfox.springconfig;

import com.fasterxml.classmate.TypeResolver;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.async.DeferredResult;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseBuilder;
import springfox.documentation.schema.ScalarType;
import springfox.documentation.schema.WildcardType;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.ParameterType;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.service.Tag;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.DocExpansion;
import springfox.documentation.swagger.web.ModelRendering;
import springfox.documentation.swagger.web.OperationsSorter;
import springfox.documentation.swagger.web.SecurityConfiguration;
import springfox.documentation.swagger.web.SecurityConfigurationBuilder;
import springfox.documentation.swagger.web.TagsSorter;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import springfox.petstore.controller.PetController;

import java.util.List;

import static java.util.Collections.*;
import static springfox.documentation.schema.AlternateTypeRules.*;


@SpringBootApplication
// 启用Springfox swagger 2
@EnableSwagger2
// 指示spring在哪里扫描API控制器
@ComponentScan(basePackageClasses = {PetController.class})
public class Swagger2SpringBoot {

  public static void main(String[] args) {
    SpringApplication.run(Swagger2SpringBoot.class, args);
  }


  @Bean
  public Docket petApi() {
    // Docket是Springfox提供的一个类,它用于配置Swagger的相关参数和API信息。Docket的主要作用是定义哪些接口需要生成文档,
    // 并提供了一系列的配置选项来自定义生成的文档。
    // Docket, Springfox的主要api配置机制在swagger规范2.0中被初始化
    return new Docket(DocumentationType.SWAGGER_2)
    	// 配置 API 信息:通过 select() 方法,可以指定 API 的扫描规则和过滤条件,例如扫描的包路径、特定的注解等。可以使用   		   // apis() 方法来限定只生成指定的接口文档。
    	// select()返回一个ApiSelectorBuilder实例,以对通过swagger公开的端点进行细粒度控制。
        .select() 
        // api()允许使用谓词选择RequestHandler。这里的示例使用any谓词(默认)。提供的开箱即用谓词有any、none、	
        // withClassAnnotation、withMethodAnnotation和baseppackage。
        .apis(RequestHandlerSelectors.any()) 
        // paths()允许使用谓词选择路径。这里的示例使用any谓词(默认)。我们开箱即用地为regex、ant、any、none提供了谓词。
        .paths(PathSelectors.any())
        // 选择器需要在配置api和路径选择器之后构建。
        .build()
        // 当servlet具有路径映射时,添加servlet路径映射。这将使用提供的路径映射为路径添加前缀。
        .pathMapping("/") 
        // 方便的规则构建器,在呈现模型属性时用String替换LocalDate
        .directModelSubstitute(LocalDate.class, String.class) 
        .genericModelSubstitutes(ResponseEntity.class)
        .alternateTypeRules(
	        // 使用类型参数替代具有一个类型参数的泛型类型的便利规则构建器。
            newRule(typeResolver.resolve(DeferredResult.class,
                typeResolver.resolve(ResponseEntity.class, WildcardType.class)),
                typeResolver.resolve(WildcardType.class))) 
         // 指示是否需要使用默认http响应代码的标志。
        .useDefaultResponseMessages(false) 
        // 允许全局重写不同http方法的响应消息。在这个例子中,我们覆盖了所有GET请求的500错误码。
        .globalResponses(HttpMethod.GET, 
            singletonList(new ResponseBuilder()
                .code("500")
                .description("500 message")
                .representation(MediaType.TEXT_XML)
                .apply(r ->
                    r.model(m ->
                        m.referenceModel(ref ->
                            ref.key(k ->
                                k.qualifiedModelName(q ->
                                    q.namespace("some:namespace")
                                    // 并指出它将使用响应模型Error(将在其他地方定义)。
                                        .name("ERROR")))))) 
                .build()))
         // 设置用于保护api的安全方案。支持的方案有ApiKey、BasicAuth和OAuth
        .securitySchemes(singletonList(apiKey())) 
        // 这里我们使用ApiKey作为安全模式,它由名称mykey标识
        .securityContexts(singletonList(securityContext())) 
        .enableUrlTemplating(true) 
        // 配置全局参数:通过 globalRequestParameters() 方法,可以定义全局的请求参数,这些参数将适用于所有的接口文档。
        .globalRequestParameters(
            singletonList(new springfox.documentation.builders.RequestParameterBuilder()
                .name("someGlobalParameter")
                .description("Description of someGlobalParameter")
                .in(ParameterType.QUERY)
                .required(true)
                .query(q -> q.model(m -> m.scalarModel(ScalarType.STRING)))
                .build()))
        .tags(new Tag("Pet Service", "All apis relating to pets")) 
        .additionalModels(typeResolver.resolve(AdditionalModel.class)); 
  }

    /**
     * 在 Swagger 3.0.0 中,TypeResolver 是 Springfox 提供的一个类,它用于解析 Java 类型,将其转换为 Swagger 的类型表示。
     * TypeResolver 的主要作用是帮助 Swagger 生成器(例如 Docket)在分析和解析 API 方法返回类型、请求参数类型、字段类型等时,
     * 将 Java 类型映射为 Swagger 规范中定义的类型。
     * 具体来说,TypeResolver 的作用包括:
     * 解析返回类型:当 Swagger 生成器分析 API 方法的返回类型时,它会使用 TypeResolver 来解析该返回类型,并将其转换为 Swagger 规范中对应的类型。这样可以确保生成的 API 文档中将正确显示和描述该返回类型。
     * 解析请求参数类型:当 Swagger 生成器分析 API 方法的请求参数类型时,它也会使用 TypeResolver 来解析该参数类型。这样可以确保生成的 API 文档中针对每个请求参数都能正确标记其类型和描述。
     * 解析字段类型:当 Swagger 生成器分析 Java 类型中的字段类型时,例如在模型类中,也会使用 TypeResolver 对字段类型进行解析和映射。这样可以确保生成的模型类在 API 文档中能正确展示字段的类型信息。
     * 通过使用 TypeResolver,Swagger 3.0.0 可以根据 Java 类型系统来生成准确的 API 文档。TypeResolver 将 Java 类型映射为适当的 Swagger 类型,确保在生成的文档中能正确显示和描述类型信息。
     * 需要注意的是,TypeResolver 可能还与其他配置类和插件一起使用,例如 ParameterBuilder、ModelConverter 等,以实现更复杂的类型解析和自定义处理。
     */
  @Autowired
  private TypeResolver typeResolver;

    /**
     * 在 Swagger 3.0.0 中,`ApiKey` 是一种身份验证机制,用于在 API 请求中传递一个固定的密钥或令牌。它的作用是确保只有提供了有效认证密钥的用户才能访问受保护的 API 资源。
     * 具体来说,`ApiKey` 的作用包括:
     * 1. 身份验证:`ApiKey` 可以用于验证用户的身份。API 的开发者可以要求用户在每个请求中提供一个有效的密钥或令牌,以确认其身份。
     * 2. 授权访问:`ApiKey` 可以用于授权用户访问特定的 API 资源或功能。每个密钥或令牌都可以根据其权限级别或角色来限制用户所能访问的资源。
     * 3. 安全性:使用 `ApiKey` 可以增加 API 的安全性。只有具有有效密钥或令牌的用户才能通过身份验证并访问受保护的资源。这可以防止未经授权的访问和滥用。
     * 在 Swagger 3.0.0 中,通过 `SecurityScheme` 以及 `@SecurityRequirement` 注解来定义和使用 `ApiKey`。`SecurityScheme` 用于定义 `ApiKey` 的名称、位置和其他相关属性,而 `@SecurityRequirement` 用于将 `ApiKey` 应用到具体的 API 上。
     * 当使用 `ApiKey` 进行身份验证时,在 Swagger UI 中的请求示例中会出现一个带有用户提供的密钥或令牌的字段,以确保请求的有效性和安全性。
     * 需要注意的是,使用 `ApiKey` 时需要妥善保管密钥或令牌,并在传输中使用适当的加密和保护措施,以防止泄露和滥用。
     */
  private ApiKey apiKey() {
    return new ApiKey("mykey", "api_key", "header"); 
  }

  private SecurityContext securityContext() {
    return SecurityContext.builder()
        .securityReferences(defaultAuth())
        // 这里我们使用安全方案mykey中定义的相同密钥
        .forPaths(PathSelectors.regex("/anyPath.*")) 
        .build();
  }

  List<SecurityReference> defaultAuth() {
    AuthorizationScope authorizationScope
        = new AuthorizationScope("global", "accessEverything");
    AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
    authorizationScopes[0] = authorizationScope;
    return singletonList(
        new SecurityReference("mykey", authorizationScopes)); 
  }

     /**
     * 在 Swagger 3.0.0 中,`SecurityConfiguration` 是 Springfox 提供的一个类,其作用是配置安全信息,包括认证和授权相关的设置,用于在生成的 Swagger 文档中添加安全定义。
     * 具体来说,`SecurityConfiguration` 的作用包括:
     * 1. 配置全局安全认证:通过 `securityContexts()` 方法,可以设置全局的安全上下文。每个安全上下文通过 `SecurityContextBuilder` 对象定义,可以指定哪些接口需要进行认证,以及使用何种认证方式。
     * 2. 配置全局安全方案:通过 `securitySchemes()` 方法,可以设置全局的安全方案,即认证方式。常见的安全方案包括 OAuth2、ApiKey、Basic Authentication 等。每个安全方案通过 `SecurityScheme` 对象定义。
     * 3. 配置安全域:通过 `securityReferences()` 方法,可以设置安全引用,即安全方案在接口操作中的引用。可以指定哪些接口使用哪种安全方案进行认证。
     * 通过 `SecurityConfiguration` 的配置,可以在 Swagger 生成的 API 文档中添加认证和授权信息,使用户能够了解和测试受保护的 API 资源。
     * 需要注意的是,`SecurityConfiguration` 根据项目实际需要进行配置,在实际使用中可能会结合其他安全框架和工具进行更加细粒度的安全控制。同时,安全方案的配置和使用也需要遵循相应的安全最佳实践和规范,以确保 API 的安全性和用户的身份验证。
     */
  @Bean
  SecurityConfiguration security() {
    return SecurityConfigurationBuilder.builder() 
        .clientId("test-app-client-id")
        .clientSecret("test-app-client-secret")
        .realm("test-app-realm")
        .appName("test-app")
        .scopeSeparator(",")
        .additionalQueryStringParams(null)
        .useBasicAuthenticationWithAccessCodeGrant(false)
        .enableCsrfSupport(false)
        .build();
  }

     /**
     * 在 Swagger 3.0.0 中,`UiConfiguration` 是 Springfox 提供的一个类,用于配置 Swagger UI 的行为和样式。
     * 具体来说,`UiConfiguration` 的作用包括:
     * 1. 配置页面标题和描述:通过 `title` 和 `description` 属性,可以设置生成的 Swagger UI 页面的标题和描述信息,以便用户更好地理解 API 文档的用途和内容。
     * 2. 配置文档展示方式:通过 `deepLinking` 属性,可以控制生成的 Swagger UI 页面中是否使用深链接。深链接允许将 UI 页面的状态保存在 URL 中,以便用户可以直接分享、保存和加载特定的视图。
     * 3. 配置默认展开操作:通过 `defaultModelsExpandDepth` 和 `defaultModelExpandDepth` 属性,可以设置默认展开的操作和模型的层级深度。这样,用户在打开 Swagger UI 时可以选择是否展开某些操作或模型。
     * 4. 配置接口排序方式:通过 `docExpansion` 属性,可以设置接口在 Swagger UI 页面中的显示方式,包括以列表方式或逐个展开方式进行排序。
     * 5. 配置是否显示请求授权功能:通过 `showRequestHeaders` 和 `showAuthorizeButton` 属性,可以设置是否在 Swagger UI 中显示请求头和授权按钮。这样,用户可以更方便地进行请求授权和自定义请求头。
     * 通过调整 `UiConfiguration` 的配置,可以根据项目需求来定制 Swagger UI 的展示行为和样式,使其更符合项目的设计和用户体验。
     * 需要注意的是,`UiConfiguration` 的配置仅影响 Swagger UI 的前端展示,不会对实际的 API 实现产生直接影响。对于更高级的自定义需求,可以通过自定义 Swagger UI 的方式来修改和扩展 UI 的样式和行为。
     */
  @Bean
  UiConfiguration uiConfig() {
    return UiConfigurationBuilder.builder() 
        .deepLinking(true)
        .displayOperationId(false)
        .defaultModelsExpandDepth(1)
        .defaultModelExpandDepth(1)
        .defaultModelRendering(ModelRendering.EXAMPLE)
        .displayRequestDuration(false)
        .docExpansion(DocExpansion.NONE)
        .filter(false)
        .maxDisplayedTags(null)
        .operationsSorter(OperationsSorter.ALPHA)
        .showExtensions(false)
        .showCommonExtensions(false)
        .tagsSorter(TagsSorter.ALPHA)
        .supportedSubmitMethods(UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS)
        .validatorUrl(null)
        .build();
  }
}

当然上述配置内容也可以和Spring Boot启动类分来写,这也是我在使用Swagger时常用的写法。下面示例我只在配置类中定义了API文档的类型格式和基本信息。

package com.example.swaggerdemo.config;

import io.swagger.annotations.ApiOperation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

/**
 * @Author yrz
 * @create 2023/7/17 10:59
 * @Description TODO
 */

/**
 * 在早期版本的Swagger中,常常要求将@EnableSwagger2注解放置在Spring Boot应用的启动类上。但是,从Swagger 3.0开始,其对注解的使用进行了一些调整。
 * 对于Swagger 3.0及更高版本,我们需要使用其他注解来启用Swagger API文档框架。具体而言,我们可以使用以下注解之一:
 * - @EnableSwagger2WebMvc:如果我们使用Spring MVC作为Web框架,则可以将此注解放置在配置类上,来启用Swagger。
 * - @EnableSwagger2WebFlux:如果我们使用Spring WebFlux作为Web框架,则可以将此注解放置在配置类上,来启用Swagger。
 * - @EnableOpenApi:这是Swagger 3.0引入的新注解,可以用于Spring Boot应用中启用Swagger。它可以用于既支持Spring MVC,也支持Spring WebFlux的应用。
 * 因此,根据你的具体情况,你可以选择适当的注解来启用Swagger API文档框架,并将其放置在合适的配置类上。
 */
@EnableOpenApi
@Configuration
public class SwaggerConfig {
    @Bean
    public Docket createRestApi() {

        /**
         * 在Swagger中,Docket是Swagger的主要配置类,它用于初始化和配置Swagger的核心功能。在Docket初始化时,
         * 可以设置DocumentationType值来指定生成的API文档的类型和格式。
         * DocumentationType是一个枚举类型,它定义了几种不同的API文档标准。常见的DocumentationType值及其含义如下:
         * 1. SWAGGER_2:表示使用Swagger 2规范(旧版Swagger)生成API文档。这是Swagger默认的文档类型,生成的文档将符合Swagger 2的规范。
         * 2. OPENAPI_3_0_0:表示使用OpenAPI 3规范(Swagger的最新规范)生成API文档。OpenAPI是Swagger 3版本开始使用的新规范,具有更多功能和灵活性。
         * 一般来说,如果使用较新版本的Swagger(3.0及以上),建议使用OPENAPI_3_0_0作为DocumentationType的值。如果使用早期版本的Swagger(2.0),则使用SWAGGER_2。
         * 通过设置DocumentationType的值,我们可以确保生成的API文档符合相应的规范,以便开发者更好地理解和使用API。
         */
        return new Docket(DocumentationType.OAS_30)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .paths(PathSelectors.any())
                .build();
    }

    /**
     * ApiInfo类是Swagger API文档框架中的一个辅助类,用于提供API文档的基本信息,包括标题、描述、版本号、许可证等。
     * ApiInfo类的作用是为API文档提供更详细的介绍和说明。通过配置ApiInfo,我们可以在生成的API文档中添加以下信息:
     * 1. 标题(Title):用于标识API文档的名称或标题。
     * 2. 描述(Description):对API文档的简要描述,可以说明API的功能、用途、使用方式等。
     * 3. 版本(Version):API文档的版本号,用于标识API的不同版本。
     * 4. 许可证(License):API文档所属的许可证类型,可以指明API的开放程度、使用限制等。
     * 5. 作者信息(Contact):关于API的作者或维护者的联系信息,如姓名、电子邮件等。
     * 6. 参考链接(Terms of service URL):提供一条指向API相关信息或条款的链接。
     * 通过配置ApiInfo类,我们可以向API文档添加更多详细信息,方便开发者理解和使用API。这些信息将在Swagger的可视化界面中显示,并提供给开发者参考和查阅。
     * @return
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Swagger接口文档")
                .description("如有疑问,请联系开发工程师")
                .contact(new Contact("yrz", "", "yangruizeng@qq.com.cn"))
                .version("1.0")
                .build();
    }
}

2.2.1问题1

完成配置类可以先启动一下Spring Boot项目,此时会有意外惊喜,启动报错:Failed to start bean ‘documentationPluginsBootstrapper’

org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
	at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181) ~[spring-context-5.3.27.jar:5.3.27]
	at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) ~[spring-context-5.3.27.jar:5.3.27]

报错信息显示“documentationPluginsBootstrapper”bean启动失败,报了一个空指针异常,跟踪代码吧,找了半天发现是

public interface RequestHandler extends Comparable<RequestHandler> {
	...
	@SuppressWarnings({"rawtypes", "unchecked"})
  static String sortedPaths(PatternsRequestCondition patternsCondition) {
    TreeSet<String> paths = new TreeSet<>(patternsCondition.getPatterns());
    return paths.stream()
        .filter(Objects::nonNull)
        .collect(Collectors.joining(","));
  }
  ...
}

该方法的参数PatternsRequestCondition为null,也就是Swagger在启动时并没有加载到PatternsRequestCondition实例。

PatternsRequestCondition类是Spring MVC中的一个类,它用于表示请求URL的模式条件。主要作用是匹配请求的URL路径与预定义的模式进行匹配,以确定是否能够处理该请求。

在Spring MVC中,控制器方法通常使用@RequestMapping注解来定义处理请求的URL路径。PatternsRequestCondition类就是用来解析和匹配这些URL路径的。

PatternsRequestCondition类提供了以下功能:

  1. 解析URL模式:它可以解析@RequestMapping注解中的value或path属性值,将其转化为一个包含多个URL模式的集合。每个URL模式可以包含固定的路径,以及占位符(例如/{id})和通配符(例如/*)。

  2. 匹配URL路径:根据预定义的URL模式,PatternsRequestCondition类可以将请求的URL路径与这些模式进行匹配。它使用Ant风格的路径匹配规则,支持通配符(*)和占位符({var})来进行模式匹配。

  3. 条件合并:PatternsRequestCondition类还支持条件合并的功能,可以将多个PatternsRequestCondition对象进行合并,以实现更复杂的匹配逻辑。例如,可以将基于URL和请求方法的模式条件合并在一起。

通过使用PatternsRequestCondition类,Spring MVC能够根据定义的URL模式,准确地匹配请求的URL路径,并将请求分发给适当的控制器方法进行处理。这有助于实现灵活且精确的请求URL映射和路由。

反观Swagger的路径匹配策略,它是由PathSelectors 这个类决定的,在 Swagger 3.0.0 中,PathSelectors 的作用是用于过滤要在 Swagger 文档中显示的 API 路径。它可以帮助开发者定制需要包含或排除的 API 路径,以便在生成的 Swagger 文档中只展示感兴趣的部分。

具体来说,PathSelectors 通过提供一些静态方法来创建 PathSelector 对象。这些静态方法包括:

  1. any():选择所有的 API 路径,不进行过滤。
  2. none():不选择任何 API 路径,即排除所有路径。
  3. regex(String regex):选择与给定正则表达式匹配的 API 路径。
  4. ant(String antPattern):选择与给定 Ant 风格的路径模式匹配的 API 路径。

例如,如果想要只在 Swagger 文档中展示以 /api 开头的 API 路径,可以使用 PathSelectors.ant("/api/**")

在使用 PathSelectors 的时候,一般是通过 Docket 对象的 select 方法来设置,示例如下:

@Configuration
@EnableSwagger2
public class SwaggerConfiguration {

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .paths(PathSelectors.ant("/api/**"))
                .build();
    }
}

在上述示例中,通过 PathSelectors.ant("/api/**") 方法,只选择以 /api 开头的 API 路径进行展示。

需要注意的是,PathSelectors 提供的方法只能进行简单的路径过滤,并不支持进一步的逻辑组合,如 AND 或 OR 运算。如果需要更复杂的路径过滤逻辑,可以自定义实现相应的 Predicate 对象,并使用 .paths(customPredicate) 方法来设置。

综上所述,启动报错Swagger和Spring MVC的路径匹配策略不一致导致的。那么修改Spring MVC路径匹配策略,在配置文件中添加如下配置,问题解决。

spring.mvc.pathmatch.matching-strategy=ant_path_matcher

2.2.2问题2

如果你的项目中引用了

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-actuator</artifactId>
 </dependency>

那么你在启动项目时,2.1.1的问题就会又出现了,debug吧,定位到

public class WebMvcPatternsRequestConditionWrapper
    implements springfox.documentation.spring.wrapper.PatternsRequestCondition<PatternsRequestCondition> {
    ...
     @Override
  public Set<String> getPatterns() {
    return this.condition.getPatterns().stream()
        .map(p -> String.format("%s/%s", maybeChompTrailingSlash(contextPath),  maybeChompLeadingSlash(p)))
        .collect(Collectors.toSet());
  }
  ...
}

该方法的condition为null导致的问题,condition为WebMvcPatternsRequestConditionWrapper的成员变量,也就是在WebMvcPatternsRequestConditionWrapper初始化时,condition就为null。追根溯源,condition来源于

public class WebMvcRequestHandlerProvider implements RequestHandlerProvider {
  private final List<RequestMappingInfoHandlerMapping> handlerMappings;
  private final HandlerMethodResolver methodResolver;
  private final String contextPath;
  ...
 }

中的private final List handlerMappings;RequestMappingInfoHandlerMapping有五个子类(AbstractWebMvcEndpointHandlerMapping、AdditionalHealthEndpointPathsWebMvcHandlerMapping、CloudFoundryWebEndpointServletHandlerMapping、ControllerEndpointHandlerMapping、WebMvcEndpointHandlerMapping)来自于spring-boot-starter-actuator的jar包中,这些类都是 Spring Boot Actuator 框架中的处理器映射器,用于映射请求到相应的 Actuator 端点处理器。下面分别解释每个映射器的作用:

  1. AbstractWebMvcEndpointHandlerMapping:是一个抽象基类,它定义了通用的方法和逻辑,用于处理 Spring Boot Actuator 中的端点请求映射。

  2. AdditionalHealthEndpointPathsWebMvcHandlerMapping:用于将特定路径与 HealthEndpoint 相关联,提供了额外的健康检查信息。例如,可以将 /health 映射到 /actuator/health 端点。

  3. CloudFoundryWebEndpointServletHandlerMapping:专为部署在 Cloud Foundry 平台上的应用程序设计的映射器。它通过解析 Cloud Foundry 平台提供的信息,自动将请求映射到相应的 Actuator 端点。

  4. ControllerEndpointHandlerMapping:用于映射带有 @Endpoint 注解的控制器端点。这些控制器端点可以用于自定义的业务逻辑,并暴露为 Actuator 端点。

  5. WebMvcEndpointHandlerMapping: 是 Actuator 的核心处理器映射器,用于将请求映射到标准的 Actuator 端点处理器。它解析并匹配请求路径,并将请求映射到相应的 Actuator 端点进行处理。

这些映射器都是为了实现 Actuator 端点的请求映射和处理而存在的。它们负责解析请求路径、匹配请求,选择合适的处理器方法,并最终执行请求处理逻辑。每个映射器都有不同的特定用途,并在 Actuator 框架中扮演重要的角色,提供健康检查、监控和管理等功能。

在WebMvcRequestHandlerProvider类中打断点,发现Swagger启动时会加载三个Actuator 映射器,在这里插入图片描述

Actuator映射器在一堆lambda表达式操作后并不能转化成WebMvcPatternsRequestConditionWrapper对象,然后调用WebMvcRequestHandler 类中的 getPatternsCondition() 方法。

在生成 Swagger 文档时,springfox-swagger 库会扫描应用程序中的控制器方法,并通过 WebMvcRequestHandlerMapping 来解析和处理这些方法。在此过程中,getPatternsCondition() 方法会被调用,用于获取控制器方法上的请求路径条件。

getPatternsCondition() 方法返回的是一个 PatternsRequestCondition 对象,其中包含了控制器方法的请求路径模式。这些模式信息会被 springfox-swagger 库使用,用于构建 Swagger 文档的路径信息,包括生成 API 文档的接口路径。

总之,WebMvcRequestHandler 类的 getPatternsCondition() 方法在 springfox-swagger 库中用于构建 Swagger 文档时被调用,用于获取控制器方法的请求路径模式信息,以便生成对应的 API 文档路径。

继续执行断点,会发现没有AbstractWebMvcEndpointHandlerMapping的实例在这里插入图片描述

所以需要注册Actuator控制器的实例,在配置类中添加如下配置:

   @Bean
    public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier, ServletEndpointsSupplier servletEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier, EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties, WebEndpointProperties webEndpointProperties, Environment environment) {
        List<ExposableEndpoint<?>> allEndpoints = new ArrayList();
        Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
        allEndpoints.addAll(webEndpoints);
        allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
        allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
        String basePath = webEndpointProperties.getBasePath();
        EndpointMapping endpointMapping = new EndpointMapping(basePath);
        boolean shouldRegisterLinksMapping = this.shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
        return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes, corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath), shouldRegisterLinksMapping, null);
    }
    private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment, String basePath) {
        return webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath) || ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
    }

问题解决,项目可以正常启动!接下来就访问swagger-ui的页面http://localhost:8080/swagger-ui/index.html。在这里插入图片描述

2.3Swagger UI配置类

这段代码是一个 Swagger UI 的配置类(Swagger源码),用于配置 Swagger UI 的访问路径和资源处理。

作用如下:

  1. 构造器:接收一个 baseUrl 参数,用于指定 Swagger UI 的根路径。

  2. addResourceHandlers 方法:重写 WebMvcConfigurer 接口的该方法,用于添加资源处理器。在这里,它配置了一个资源处理器,用于处理 Swagger UI 的静态资源文件。

    • addResourceHandler(baseUrl + “/swagger-ui/**”):指定了 Swagger UI 的资源路径模式和匹配规则。
    • addResourceLocations(“classpath:/META-INF/resources/webjars/springfox-swagger-ui/”):指定了 Swagger UI 资源文件的存放位置,通常是在项目的 classpath 下的 webjars 目录。
    • resourceChain(false):禁用资源链的自动配置,以确保能够直接访问到 Swagger UI 的静态资源文件。
  3. addViewControllers 方法:重写 WebMvcConfigurer 接口的该方法,用于添加视图控制器。在这里,它配置了一个视图控制器,用于将 Swagger UI 的访问重定向到具体的 HTML 页面。

    • registry.addViewController(baseUrl + “/swagger-ui/”):指定了 Swagger UI 的访问路径。
    • setViewName(“forward:” + baseUrl + “/swagger-ui/index.html”):设置视图名称,将该请求转发到具体的 Swagger UI 的 HTML 页面。

通过使用这段代码,你可以将 Swagger UI 集成到 Spring Boot 应用程序中,并配置 Swagger UI 的访问路径和资源处理。这样,在运行应用程序并访问相应的路径时,你将能够在浏览器中看到 Swagger UI 的界面,并浏览、测试和探索你的 API 文档。

package springfox.boot.starter.autoconfigure;

import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

// tag::swagger-ui-configurer[]
public class SwaggerUiWebMvcConfigurer implements WebMvcConfigurer {
  private final String baseUrl;

  public SwaggerUiWebMvcConfigurer(String baseUrl) {
    this.baseUrl = baseUrl;
  }

  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    String baseUrl = StringUtils.trimTrailingCharacter(this.baseUrl, '/');
    registry.
        addResourceHandler(baseUrl + "/swagger-ui/**")
        .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
        .resourceChain(false);
  }

  @Override
  public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController(baseUrl + "/swagger-ui/")
        .setViewName("forward:" + baseUrl + "/swagger-ui/index.html");
  }
}
// end::swagger-ui-configurer[]

2.3.1重写Swagger UI配置类

要自定义 Swagger UI 页面的访问路径,可以按照以下步骤进行操作:

  1. 创建一个自定义的 Swagger UI 配置类,命名为 CustomSwaggerUiConfig(或者根据您的喜好选择一个合适的类名)。

    import org.springframework.util.StringUtils;
    import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    public class CustomSwaggerUiConfig implements WebMvcConfigurer {
        private final String basePath;
    
        public CustomSwaggerUiConfig(String basePath) {
            this.basePath = basePath;
        }
    
        @Override
        public void addViewControllers(ViewControllerRegistry registry) {
            registry.addViewController(basePath + "/my-swagger")
                    .setViewName("redirect:/swagger-ui/index.html");
        }
    }
    
  2. 在新的配置类中,重写 addViewControllers() 方法,并根据需要自定义您的 Swagger UI 访问路径。在这个例子中,我们使用 /my-swagger 作为自定义的 Swagger UI 路径,并将其重定向到 /swagger-ui/index.html 页面。

  3. 在主配置类(通常是指 Spring Boot 的启动类)中,将自定义的 Swagger UI 配置类注入为一个 Bean。

    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class ApplicationConfig {
    
        @Value("${server.servlet.context-path:}")
        private String contextPath;
    
        @Bean
        public CustomSwaggerUiConfig swaggerUiConfig() {
            return new CustomSwaggerUiConfig(contextPath);
        }
    
        // 其他配置和 Bean
    }
    
  4. 启动应用程序并访问自定义的 Swagger UI 页面。在这个例子中,您可以通过访问 http://localhost:8080/<contextPath>/my-swagger 来访问自定义的 Swagger UI 页面。请注意,<contextPath> 是您配置的应用程序上下文路径。

通过以上步骤,您就可以自定义 Swagger UI 的访问路径,并通过新定义的路径来访问 Swagger UI。

3Controller层与Model层注解使用

@Api

  • 使用场景

在 Rest 接口类上边使用。

  • 概述

标记类为 Swagger 资源类,运行时有效。

  • 属性

属性名称 数据类型 默认值 说明

value String “” 隐式设置操作的标记,遗留支持(读取 description)

tags String[] “” 对接口进行分组

produces String “” 采用逗号分隔的 content types,例如:application/json,application/xml 生成JSON和XML的输出

consumes String “” 采用逗号分隔的 content types,例如: application/json,application/xml 会接收JSON和XML的输入

protocols String “” 采用逗号分隔的可用协议,例如:http,https,ws,wss

authorizations Authorization[] “” 授权列表

hidden boolean false 隐藏此资源下的操作, 和 @ApiOperation 注解中的 hidden 组合使用可以隐藏改接口

@ApiOperation

  • 使用场景

在 Rest 接口上使用

  • 概述

描述针对特定路径的操作,通常是 HTTP 方法。具有等效路径的操作被分到单个分组中。HTTP 方法和路径的组合创建了一个独特的操作

  • 属性

属性名称 数据类型 默认值 说明

value String 接口简要说明,120字符或更少

notes String “” 接口详细描述

tags String[] “” tag 列表,可用于按自愿或任何其它限定符对操作进行逻辑分组

response Class<?> Void.class 接口返回类型

responseContainer String “” 声明包装响应的容器。有效值为 List,Set,Map,任何其它值都将被忽略

responseReference String “” 指定对响应类型的引用,本地/远程引用,并将覆盖任何其它指定的response()类

httpMethod String “” 请求方式:“GET”, “HEAD”, “POST”, “PUT”, “DELETE”, “OPTIONS” and “PATCH”,如果未指定则使用除"PATH"之外的其它所有

nickname String “” 第三方工具使用operationId来唯一表示此操作

produces String “” 采用逗号分隔的 content types 类型的返回数据,例如:application/json,application/xml

consumes String “” 采用逗号分隔的 content types 类型的入参数据类型,例如:application/json,application/xml

protocols String “” 指定协议类型:http,https,ws,wss,多个协议使用逗号进行分隔

authorizations Authorization[] @Authorization(value = “”) 获取此操作的授权列表

hidden boolean false 是否隐藏操作列表中的操作

responseHeaders ResponseHeader[] @ResponseHeader(name = “”, response = Void.class) 指定 response header 信息列表

code int 200 HTTP返回状态码

extensions Extension[] @Extension(properties = @ExtensionProperty(name = “”, value = “”)) 可选的扩展数组

@ApiImplicitParams 和 @ApiImplicitParam

@ApiImplicitParams

  • 使用场景

在 Rest 接口方法上使用来指定请求参数

  • 概述

在 Rest 接口方法上使用来指定请求参数

  • 属性

属性名称 数据类型 默认值 说明

value ApiImplicitParam[] API 可用的参数列表

@ApiImplicitParam

  • 使用场景

场景一:在 Rest 接口上单独使用

@ApiImplicitParam 在 Rest 接口上单独使用的时候,表示单个请求参数

场景二:在 Rest 接口上和 @ApiImplicitParams 组合使用
@ApiImplicitParam 在 Rest 接口上和 @ApiImplicitParams 组合时候,表示多个请求参数

  • 概述

表示 Rest 接口的单个请求参数,可与 @ApiImplicitParams 组合使用来表示多个请求参数

  • 属性

属性名称 数据类型 默认值 说明

name String “” 参数名称(实体类字段名称)

value String “” 参数简要说明

defaultValue String “” 描述参数的默认值

allowableValues String “” 限制此参数接收的值,可使用的值或值得范围

required boolean false 指定是否为必填参数,false:非必传参数; true:必传参数

access String “” 参数过滤,参考: io.swagger.core.filter.SwaggerSpecFilte

allowMultiple boolean false 指定参数是否可以通过多次出现来接收多个值

dataType String “” 参数的数据类型,可以使类名或原始数据类型

dataTypeClass Class<?> Void.class 参数的类,如果提供则覆盖 dataType

paramType String “” 参数的参数类型,有效值为 path, query, body, header, form

example String “” 非请求体(body)参数的单个请求示例

examples Example @Example(value = @ExampleProperty(mediaType = “”, value = “”)) 参数示例,仅适用于 BodyParameters(请求体类型的)

type String “” 添加覆盖检测到的类型的功能

format String “” 添加提供自定义格式的功能

allowEmptyValue boolean false 添加将 format 设置为空的功能

readOnly boolean false 添加被指定为只读的能力

collectionFormat String “” 添加使用 array 类型 collectionFormat 的功能

@ApiModel 和 @ApiModelProperty

@ApiModel

  • 使用场景

在实体类上边使用,标记类时swagger的解析类

  • 概述

提供有关swagger模型的其它信息,类将在操作中用作类型时自动内省

  • 属性

属性名称 数据类型 默认值 说明

value String 类名 为模型提供备用名称

description String “” 提供详细的类描述

parent Class<?> parent Void.class 为模型提供父类以允许描述继承关系

discriminatory String “” 支持模型继承和多态,使用鉴别器的字段的名称,可以断言需要使用哪个子类型

subTypes Class<?>[] {} 从此模型继承的子类型数组

reference String “” 指定对应类型定义的引用,覆盖指定的任何其他元数据

@ApiModelProperty

  • 使用场景

使用在被 @ApiModel 注解的模型类的属性上

  • 概述

添加和操作模型属性的数据

  • 属性

属性名称 数据类型 默认值 说明

value String “” 属性简要说明

name String “” 运行覆盖属性的名称。重写属性名称

allowableValues String “” 限制参数可接收的值,三种方法,固定取值,固定范围

access String “” 过滤属性,参阅:io.swagger.core.filter.SwaggerSpecFilter

notes String “” 目前尚未使用

dataType String “” 参数的数据类型,可以是类名或原始数据类型,此值将覆盖从类属性读取的数据类型

required boolean false 是否为必传参数,false:非必传参数; true:必传参数

position int 0 允许在模型中显示排序属性

hidden boolean false 隐藏模型属性,false:不隐藏; true:隐藏

example String “” 属性的示例值

readOnly boolean false 指定模型属性为只读,false:非只读; true:只读

reference String “” 指定对应类型定义的引用,覆盖指定的任何其他元数据

allowEmptyValue boolean false 允许传空值,false:不允许传空值; true:允许传空值

@ApiResponses 和 @ApiResponse

@ApiResponses
代码示例
github 代码示例: https://github.com/CoderFreeMan/swagger-demo

  • 使用场景

在 Rest 接口上使用,用作返回值的描述

  • 概述

一个包装器,允许列出多个 ApiResponse,若果你需要描述单个 ApiResponse,你仍然必须使用此注解并将@ApiResponse 包装在一个数组中

  • 属性

属性名称 数据类型 默认值 说明

value ApiResponse[] ApiResponse 列表

@ApiResponse

  • 使用场景

在 Rest 接口或类上和 @ApiResponses 组合使用,组装返回参数说明

  • 概述

描述操作的可能响应,这可用于描述 Rest API 调用中可能的成功和错误 code 码。此注解可以在方法或类级别应用;仅当在方法级别或抛出时未定义相同代码的@ApiResponse注解时才会解析类级别注解异常,如果响应中使用了不同的响应类,则可以通过将响应类于响应码组合使用。注意swagger不允许单个响应代码的多个响应类型。此注解不直接使用,单独使用时swagger不会解析,应该和ApiResponses组合使用。

  • 属性

属性名称 数据类型 默认值 说明

code int 响应的HTTP状态码

message String 伴随响应的人类可读的消息

response Class<?> Void.class 用于描述消息有效负载的可选响应类,对应于响应消息对象的 schema 字段

reference String “” 指定对响应类型的引用,指定的应用可以使本地引用,也可以是远程引用,将按原样使用,并将覆盖任何指定的response()类

responseHeaders ResponseHeader[] @ResponseHeader(name = “”, response = Void.class) 可能响应的 header 列表

responseContainer String “” 声明响应的容器,有效值为List,Set,Map,任何其他值都将被忽略

@ResponseHeader

  • 使用场景

作为 @ApiResponse 的属性,作为返回数据的一部分,指定返回 header 信息

  • 概述

作为返回数据的一部分提供返回数据的 header 信息

  • 属性

属性名称 数据类型 默认值 说明

name String “” Header’s name.

description String “” response header 详细描述

response Class<?> Void.class Header’s data type

responseContainer String “” 声明包装响应的容器,有效值为List或Set,任何其他值都将被覆盖

@ApiParam

  • 使用场景

在 Rest 接口上或 Rest 接口参数前边使用

  • 概述

为 Rest 接口参数添加其它元数据(导入到 yapi 中不会被解析)

  • 属性

属性名称 数据类型 默认值 说明

name String “” 参数名称,参数名称将从 filed/method/parameter 名称中派生,但你可以覆盖它,路径参数必须始终命名为它们所代表的路径部分

value String “” 参数简单描述

defaultValue String “” 描述参数默认值

allowableValues String “” 可接收参数值限制,有三种方式,取值列表,取值范围

required boolean false 是否为必传参数, false:非必传; true:必传

access String “” 参数过滤,请参阅:io.swagger.core.filter.SwaggerSpecFilter

allowMultiple boolean false 指定参数是否可以通过多次出现来接收多个值

hidden boolean false 隐藏参数列表中的参数

example String “” 非请求体(body)类型的单个参数示例

examples Example @Example(value = @ExampleProperty(mediaType = “”, value = “”)) 参数示例,仅适用于请求体类型的请求

type String “” 添加覆盖检测到类型的功能

format String “” 添加提供自定义format格式的功能

allowEmptyValue boolean false 添加将格式设置为空的功能

readOnly boolean false 添加被指定为只读的能力

collectionFormat String “” 添加使用 array 类型覆盖 collectionFormat 的功能

@ExternalDocs

  • 使用场景

使用外部文档说明的时候使用,参数,方法,属性上可使用

  • 概述

定义外部文档说明

  • 属性
属性名称数据类型默认值说明
valueString“”目标文档的简要描述,GFM语法可用于富文本表示
urlString引用文档的 URL
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倔强的初学者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值