Swagger

1,250 阅读4分钟

Swagger的使用

1、引入依赖

<!--Swagger-UI API文档生产工具-->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

Swagger配置:

开启Swagger

/**
 * 开启Swagger
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig extends BaseSwaggerConfig {

    @Override
    public SwaggerProperties swaggerProperties() {
        return SwaggerProperties.builder()
                .apiBasePackage("com.data.empower.controller")
                .title("阿尔法平台")
                .description("阿尔法平台相关接口文档")
                .contactName("alpha")
                .version("1.0")
                .enableSecurity(true)
                .build();
    }

    @Bean
    public BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
        return generateBeanPostProcessor();
    }
}

实体类

/**
 * 参数实体类
 */
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * Swagger自定义配置
 * Created by macro on 2020/7/16.
 */
@Data
@EqualsAndHashCode
@Builder
public class SwaggerProperties {
    /**
     * API文档生成基础路径
     */
    private String apiBasePackage;
    /**
     * 是否要启用登录认证
     */
    private boolean enableSecurity;
    /**
     * 文档标题
     */
    private String title;
    /**
     * 文档描述
     */
    private String description;
    /**
     * 文档版本
     */
    private String version;
    /**
     * 文档联系人姓名
     */
    private String contactName;
    /**
     * 文档联系人网址
     */
    private String contactUrl;
    /**
     * 文档联系人邮箱
     */
    private String contactEmail;
}


import com.data.empower.common.domain.SwaggerProperties;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Swagger基础配置
 *
 * @author Dataempower9
 * @date 2020/7/16
 */
public abstract class BaseSwaggerConfig {

    @Bean
    public Docket createRestApi() {
        SwaggerProperties swaggerProperties = swaggerProperties();
        //Docket实现了DocumentationPlugin接口很明显,这是文档插件。那就很明了了。Swagger通过文档插件来实现输出的。
        //构造函数需要传入DocumentationType
        //这是名称和版本。
        //我们一般设置为DocumentationType.SWAGGER_2。
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo(swaggerProperties))
                .select()
                .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getApiBasePackage()))
                .paths(PathSelectors.any())
                .build();
        if (swaggerProperties.isEnableSecurity()) {

            docket.securitySchemes(securitySchemes()).securityContexts(securityContexts());
        }
        return docket;
    }

    private ApiInfo apiInfo(SwaggerProperties swaggerProperties) {

        return new ApiInfoBuilder()
                .title(swaggerProperties.getTitle())
                .description(swaggerProperties.getDescription())
                .contact(new Contact(swaggerProperties.getContactName(), swaggerProperties.getContactUrl(), swaggerProperties.getContactEmail()))
                .version(swaggerProperties.getVersion())
                .build();
    }

    private List<SecurityScheme> securitySchemes() {
        //设置请求头信息
        List<SecurityScheme> result = new ArrayList<>();
        //注意,这里应对应登录token鉴权对应的k-v
        ApiKey apiKey = new ApiKey("Authorization", "Authorization", "header");
        result.add(apiKey);
        return result;
    }

    private List<SecurityContext> securityContexts() {
        //设置需要登录认证的路径
        List<SecurityContext> result = new ArrayList<>();
        result.add(getContextByPath("/*/.*"));
        return result;
    }

    private SecurityContext getContextByPath(String pathRegex) {
        return SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.regex(pathRegex))
                .build();
    }

    private List<SecurityReference> defaultAuth() {
        List<SecurityReference> result = new ArrayList<>();
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        result.add(new SecurityReference("Authorization", authorizationScopes));
        return result;
    }

 

    /**
     * 自定义Swagger配置
     */
    public abstract SwaggerProperties swaggerProperties();
}

解析

1、Docket

Docket实现了DocumentationPlugin接口。DocumentationPlugin接口是文档插件,Swagger通过文档插件来实现输出的。

public class Docket implements DocumentationPlugin {

  public static final String DEFAULT_GROUP_NAME = "default";

  private final DocumentationType documentationType;
  private final List<SecurityContext> securityContexts = new ArrayList<>();
  private final Map<RequestMethod, List<springfox.documentation.service.ResponseMessage>> responseMessages
      = new HashMap<>();
  private final Map<HttpMethod, List<Response>> responses = new HashMap<>();
  private final List<springfox.documentation.service.Parameter> globalOperationParameters = new ArrayList<>();
  private final List<Function<TypeResolver, AlternateTypeRule>> ruleBuilders = new ArrayList<>();
  private final Set<Class> ignorableParameterTypes = new HashSet<>();
  private final Set<String> protocols = new HashSet<>();
  private final Set<String> produces = new LinkedHashSet<>();
  private final Set<String> consumes = new LinkedHashSet<>();
  private final Set<ResolvedType> additionalModels = new HashSet<>();
  private final Set<Tag> tags = new HashSet<>();
  private final List<Server> servers = new ArrayList<>();

  private PathProvider pathProvider;
  private List<SecurityScheme> securitySchemes;
  private Comparator<ApiListingReference> apiListingReferenceOrdering;
  private Comparator<ApiDescription> apiDescriptionOrdering;
  private Comparator<Operation> operationOrdering;

  private ApiInfo apiInfo = ApiInfo.DEFAULT;
  private String groupName = DEFAULT_GROUP_NAME;
  private boolean enabled = true;
  private GenericTypeNamingStrategy genericsNamingStrategy = new DefaultGenericTypeNamingStrategy();
  private boolean applyDefaultResponseMessages = true;
  private String host = "";
  private Optional<String> pathMapping = empty();
  private ApiSelector apiSelector = ApiSelector.DEFAULT;
  private boolean enableUrlTemplating = false;
  private final List<VendorExtension> vendorExtensions = new ArrayList<>();
  private final List<RequestParameter> globalRequestParameters = new ArrayList<>();
}



1.DocumentationType 文档类型

public Docket(DocumentationType documentationType) {
  this.documentationType = documentationType;
}

DocumentationType 构造函数需要传入DocumentationType,我们一般设置为DocumentationType.SWAGGER_2。

public class DocumentationType extends SimplePluginMetadata {
    public static final DocumentationType SWAGGER_12 = new DocumentationType("swagger", "1.2");
    public static final DocumentationType SWAGGER_2 = new DocumentationType("swagger", "2.0");
    public static final DocumentationType OAS_30 = new DocumentationType("openApi", "3.0");
    //@deprecated since 3.0.0
    @Deprecated
    public static final DocumentationType SPRING_WEB = new DocumentationType("spring-web", "5.2");
}

SimplePluginMetadata

//名称,版本
private final String name;
private final String version;

2.apiInfo() 配置文档信息

public Docket apiInfo(ApiInfo apiInfo) {
  this.apiInfo = defaultIfAbsent(apiInfo, this.apiInfo);
  return this;
}

ApiInfo配置文档信息

public class ApiInfo {

  public static final Contact DEFAULT_CONTACT
      = new Contact(
      "",
      "",
      "");
  public static final ApiInfo DEFAULT
      = new ApiInfo(
      "Api Documentation",
      "Api Documentation",
      "1.0",
      "urn:tos",
      DEFAULT_CONTACT,
      "Apache 2.0",
      "http://www.apache.org/licenses/LICENSE-2.0",
      new ArrayList<>());
  //版本
  private final String version;
  //标题
  private final String title;
  //描述
  private final String description;
  //服务条款Url 服务条款Url
  private final String termsOfServiceUrl;
  //许可证
  private final String license;
  //许可证地址
  private final String licenseUrl;
  // 联系人信息
  private final Contact contact;
  //扩展
  private final List<VendorExtension> vendorExtensions;
}

1)Contact

//文档联系人姓名
private final String name;
//文档联系人网址
private final String url;
//文档联系人邮箱
private final String email;

2)ApiInfoBuilder

build()方法构建ApiInfo实体类。

public class ApiInfoBuilder {
  private String title;
  private String description;
  private String termsOfServiceUrl;
  private Contact contact;
  private String license;
  private String licenseUrl;
  private String version;
  private final List<VendorExtension> vendorExtensions = new ArrayList<>();

  public ApiInfo build() {
    return new ApiInfo(title, description, version, termsOfServiceUrl, contact, license, licenseUrl, vendorExtensions);
  }

未配置ApiInfo效果:

image.png

配置ApiInfo效果:

image.png

3.enable()

  • enable(false) 关闭Swagger
public Docket enable(boolean externallyConfiguredFlag) {
  this.enabled = externallyConfiguredFlag;
  return this;
}

image.png

4.groupName()

  • groupName()配置一个分组

image.png

5.securitySchemes()

设置请求头信息

public Docket securitySchemes(List<SecurityScheme> securitySchemes) {
  this.securitySchemes = securitySchemes;
  return this;
}

生成参数:

private List<SecurityScheme> securitySchemes() {
    //设置请求头信息
    List<SecurityScheme> result = new ArrayList<>();
    //注意,这里应对应登录token鉴权对应的k-v
    ApiKey apiKey = new ApiKey("Authorization", "Authorization", "header");
    result.add(apiKey);
    return result;
}

Docket.securitySchemes(securitySchemes())

效果

image.png

image.png

6.securityContexts

设置需要登录认证的路径

/**
 * 配置哪些api操作(通过regex模式)和HTTP方法将安全上下文应用于api。
 */
public Docket securityContexts(List<SecurityContext> securityContexts) {
  this.securityContexts.addAll(securityContexts);
  return this;
}

参数创建

private List<SecurityContext> securityContexts() {
    //设置需要登录认证的路径
    List<SecurityContext> result = new ArrayList<>();
    result.add(getContextByPath("/*/.*"));
    return result;
}

private SecurityContext getContextByPath(String pathRegex) {
    return SecurityContext.builder()
            .securityReferences(defaultAuth())
            .forPaths(PathSelectors.regex(pathRegex))
            .build();
}

1)SecurityContext

一个类,用于表示应用于每个api操作的默认授权集

要自定义应用授权列表的请求映射,请指定自定义includePatterns或requestMethods

public class SecurityContext {

  private final List<SecurityReference> securityReferences = new ArrayList<>();
  private final Predicate<String> selector;
  private final Predicate<HttpMethod> methodSelector;
  private final Predicate<OperationContext> operationSelector;
}

使用:

private SecurityContext getContextByPath(String pathRegex) {
    return SecurityContext.builder()
            .securityReferences(defaultAuth())
            .forPaths(PathSelectors.regex(pathRegex))
            .build();
}

private List<SecurityReference> defaultAuth() {
    List<SecurityReference> result = new ArrayList<>();
    AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
    AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
    authorizationScopes[0] = authorizationScope;
    result.add(new SecurityReference("Authorization", authorizationScopes));
    return result;
}

.ApiSelectorBuilder

1) .select()

public ApiSelectorBuilder select() {
  return new ApiSelectorBuilder(this);
}

2) .apis()

RequestHandlerSelectors配置要扫描接口的方式

basePackage:指定要扫描的包=>RequestHandlerSelectors.basePackage("com.kuang.swagger.controller") any():扫描全部 none():全部不扫描

withClassAnnotation:扫描类上的注解=>RequestHandlerSelectors.withClassAnnotation(RestController.class)

withMethodAnnotation:扫描方法上的注解=>RequestHandlerSelectors.withMethodAnnotation(GetMapping.class)

public ApiSelectorBuilder apis(Predicate<RequestHandler> selector) {
  requestHandlerSelector = requestHandlerSelector.and(selector);
  return this;
}

3) .paths()

Path:过滤路径 ant:指定路径 any:过滤全部 none:全部不过滤 regex:按照正则表达式来过滤

public ApiSelectorBuilder paths(Predicate<String> selector) {
  pathSelector = pathSelector.and(selector);
  return this;
}