【JAVA】在SpringCloud Alibaba 2021微服务Gateway网关项目中整合Swagger3

hey-girl东拼西凑原创文章,若有歧义可留言,若需转载需标明出处

前言唠个五毛钱:想做到的效果,通过网关访问swagger地址,可以看到所有服务的API文档。这个要求不过份吧。

开始干活前,我就斗胆先给和我一样懵逼的兄弟扫盲下。不难发现,当我们百度搜索swagger的配置整合时候。我们总是会发现好多兄弟引入的包都不一样。给大家截图看看。下面这些是不是都是我们常见的包。看到五花八门的包是不是给整懵了。所以我就去找了下文档。潦草的学习了下。
springfox
io.swagger

swagger是什么?

了表尊重,官网传送先放上swagger
官网首页说的:使用 Swagger 开源和专业工具集为用户、团队和企业简化 API 开发
Swagger 工具的强大功能始于 OpenAPI 规范——RESTful API 设计的行业标准

Swagger提供了哪些产品了。我捡了几个重要的说明下。(下面描述均来自官网)

  • Swagger UI:允许任何人(无论是您的开发团队还是您的最终消费者)在没有任何实现逻辑的情况下可视化 API 资源并与之交互。它是根据您的 OpenAPI(以前称为 Swagger)规范自动生成的,带有可视化文档,便于后端实现和客户端使用。
  • Swagger Codegen: Swagger Codegen 可以通过为使用 OpenAPI(以前称为 Swagger)规范定义的任何 API 生成服务器存根和客户端 SDK 来简化您的构建过程,因此您的团队可以更好地专注于 API 的实施和采用
  • Swagger Editor: 在第一个完全致力于基于 OpenAPI 的 API 的开源编辑器上设计、描述和记录您的 API。Swagger 编辑器是一种开始使用 OpenAPI 规范(以前称为 Swagger)的简单方法,支持 Swagger 2.0 和 OpenAPI 3.0。
  • swaggerHub:UI+Codegen+Editor
    swaggerHub

springfox是又是什么?

先看看springfox的文档springfox文档
springfox是 Springfox java库套件都是关于为使用spring系列项目编写的JSON api自动生成机器和人类可读的规范。 Springfox的工作方式是在运行时检查应用程序一次,根据spring配置、类结构和各种编译时java注释推断API语义 (有道翻译)

springfox的历史: Springfox是由Marty Pitt最初创建的一个项目演变而来的,它被命名为swagger-springmvc。 荣誉归于马蒂 。
扩展对许多针对JSON API规范和文档的不断发展的标准的支持,如swagger、RAML和jsonapi。

浅谈下这俩者啥关系了?

swagger是一个流行的API开发框架,这个框架以“开放API声明”(OpenAPI Specification,OAS)为基础,对整个API的开发周期都提供了相应的解决方案,是一个非常庞大的项目(包括设计、编码和测试,几乎支持所有语言)。

OAS本身是一个API规范,它用于描述一整套API接口,包括一个接口是GET还是POST请求啊,有哪些参数哪些header啊,都会被包括在这个文件中。它在设计的时候通常是YAML格式,这种格式书写起来比较方便,而在网络中传输时又会以json形式居多,因为json的通用性比较强。

由于Spring的流行,Marty Pitt编写了一个基于Spring的组件swagger-springmvc,用于将swagger集成到springmvc中来。而springfox则是从这个组件发展而来,同时springfox也是一个新的项目。

像文章最开始的时候引入的依赖,springfox-swagger2依然是依赖OSA规范文档,也就是一个描述API的json文件,而这个组件的功能就是帮助我们自动生成这个json文件,我们会用到的另外一个组件springfox-swagger-ui就是将这个json文件解析出来,用一种更友好的方式呈现出来。

Springfox其实是一个通过扫描代码提取代码中的信息,生成API文档的工具。API文档的格式不止Swagger的OpenAPI Specification,还有RAML,jsonapi,Springfox的目标同样包括支持这些格式。这就能解释那个swagger2的后缀了,这只是Springfox对Swagger的支持。

说明一个事。首先生成一个满足OSA规范的json文件。然后再通过UI解析这文件展示出来。干好这2件事就可了。

开始整活

上述了半天。也不知你看懂没。但是这都不重要了。重要的是。要开始写代码了。鸡冻!
swagger-ui 位置已从简称http://host/context-path/swagger-ui.html 为http://host/context-path/swagger-ui/index.html OR http://host/context-path/swagger-ui/

使用springfox。先look下文档的一些更新说的啥。如下图。我把几个重要点勾选了下。
在这里插入图片描述
涉及的服务和需求说明:
gateway服务
upms服务
common-swagger服务
需要网关和资源服务依赖common-swagger服务

  1. common-swagger中引入相关依赖包,只需要引入一个这个就好了。其他花里胡哨不需要了哈。
  <!--swagger相关包-->
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-boot-starter</artifactId>
        <version>3.0.0</version>
    </dependency>
    <!--webflux 相关包-->
       <dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-webflux</artifactId>
           <scope>provided</scope>
       </dependency>
    <!--网关 和 swagger 聚合依赖-->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-gateway-server</artifactId>
          <scope>provided</scope>
      </dependency>

2.common-swagger中添加资源处理程序配置器,按照文档说的。有2种方式。webMvc或者webFlux。我这里是使用的webFlux.因为需要个gateway整合配置。
配置请看WebFluxSwaggerConfig

public class WebFluxSwaggerConfiguration implements WebFluxConfigurer {
    /**
     * 添加资源处理器
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/swagger-ui/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
                .resourceChain(false);
    }
}
  1. 上面说到,当前需求是要整合gateway和其他微服务。所以在common-swagger中添加一个注解EnableGirlSwagger3。为了后续拿到有需要的服务使用。这个注解抛开元注解不说,主要就是2点。一把SwaggerProperties配置注册为Spring的一个Bean。二import用来导入配置类。主要导入的SwaggerAutoConfiguration和GatewaySwaggerAutoConfiguration
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@EnableConfigurationProperties(SwaggerProperties.class)
@Import({ SwaggerAutoConfiguration.class, GatewaySwaggerAutoConfiguration.class })
public @interface EnableGirlSwagger3 {
}
  1. 接着在common-swagger服务中,添加SwaggerProperties。对应配置鞋子yml即可
package com.hey.girl.common.swagger.support;

import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * @Description: SwaggerProperties 这里没有注册SwaggerProperties
 * @author: heihei
 * @date: 2021年11月08日 10:37
 */
@Data
@ConfigurationProperties("swagger")
public class SwaggerProperties {
    /**
     * 是否开启swagger
     */
    private Boolean enabled = true;

    /**
     * swagger会解析的包路径
     **/
    private String basePackage = "";

    /**
     * swagger会解析的url规则
     **/
    private List<String> basePath = new ArrayList<>();

    /**
     * 在basePath基础上需要排除的url规则
     **/
    private List<String> excludePath = new ArrayList<>();

    /**
     * 需要排除的服务
     */
    private List<String> ignoreProviders = new ArrayList<>();

    /**
     * 标题
     **/
    private String title = "";

    /**
     * 描述
     **/
    private String description = "";

    /**
     * 版本
     **/
    private String version = "";

    /**
     * 许可证
     **/
    private String license = "";

    /**
     * 许可证URL
     **/
    private String licenseUrl = "";

    /**
     * 服务条款URL
     **/
    private String termsOfServiceUrl = "";

    /**
     * host信息
     **/
    private String host = "";

    /**
     * 联系人信息
     */
    private Contact contact = new Contact();

    /**
     * 全局统一鉴权配置
     **/
    private Authorization authorization = new Authorization();

    /**
     * 认证参数
     */
    private SwaggerBasic basic = new SwaggerBasic();

    @Data
    @NoArgsConstructor
    public static class Contact {

        /**
         * 联系人
         **/
        private String name = "";

        /**
         * 联系人url
         **/
        private String url = "";

        /**
         * 联系人email
         **/
        private String email = "";

    }

    @Data
    @NoArgsConstructor
    public static class Authorization {

        /**
         * 鉴权策略ID,需要和SecurityReferences ID保持一致
         */
        private String name = "";

        /**
         * 需要开启鉴权URL的正则
         */
        private String authRegex = "^.*$";

        /**
         * 鉴权作用域列表
         */
        private List<AuthorizationScope> authorizationScopeList = new ArrayList<>();

        private List<String> tokenUrlList = new ArrayList<>();

    }

    @Data
    @NoArgsConstructor
    public static class AuthorizationScope {

        /**
         * 作用域名称
         */
        private String scope = "";

        /**
         * 作用域描述
         */
        private String description = "";

    }

    @Data
    public static class SwaggerBasic {

        /**
         * 是否开启 basic 认证
         */
        private Boolean enabled;

        /**
         * 用户名
         */
        private String username;

        /**
         * 密码
         */
        private String password;

    }
}

  1. 接下来在common-swagger中配置SwaggerAutoConfiguration。在springfox的文档中,给了一个demo的。建议先看看。
package com.hey.girl.common.swagger.config;
/**
 * @EnableOpenApi 开启swagger3的注解
 * @Description: swagger3配置文件
 * @author: heihei
 * @date: 2021年11月04日 14:49
 */
@EnableOpenApi
@ConditionalOnProperty(prefix = "swagger", name = "enabled", matchIfMissing = true)
@ConditionalOnMissingClass("org.springframework.cloud.gateway.config.GatewayAutoConfiguration")
public class SwaggerAutoConfiguration {
    /**
     * 默认的排除路径,排除Spring Boot默认的错误处理路径和端点
     * 默认的排除路径,排除Spring Boot默认的错误处理路径和端点(在解析的url规则之上)
     * error,由于服务通常加前缀,所以前面/*忽略前缀
     */
    private static final List<String> DEFAULT_EXCLUDE_PATH = Arrays.asList("/error", "/actuator/**", "/*/error");

    /**
     * swagger会解析的url规则
     */
    private static final String BASE_PATH = "/**";

    @Bean
    public Docket createRestApi(SwaggerProperties swaggerProperties) {
        // base-path处理
        if (swaggerProperties.getBasePath().isEmpty()) {
            swaggerProperties.getBasePath().add(BASE_PATH);
        }
        // exclude-path处理
        if (swaggerProperties.getExcludePath().isEmpty()) {
            swaggerProperties.getExcludePath().addAll(DEFAULT_EXCLUDE_PATH);
        }
        //需要排除的url
        List<Predicate<String>> excludePath = new ArrayList<>();
        swaggerProperties.getExcludePath().forEach(path -> excludePath.add(PathSelectors.ant(path)));

        // 版本请求头处理
        List<RequestParameter> pars = new ArrayList<>();

        RequestParameterBuilder versionPar = new RequestParameterBuilder().description("灰度路由版本信息")
                .in(ParameterType.HEADER).name("VERSION").required(false)
                .query(param -> param.model(model -> model.scalarModel(ScalarType.STRING)));

        pars.add(versionPar.build());
        ApiSelectorBuilder builder = new Docket(DocumentationType.OAS_30)
                // // 接口调试地址
                .host(swaggerProperties.getHost())
                // 将api的元信息设置为包含在json ResourceListing响应中。
                .apiInfo(apiInfo(swaggerProperties)).globalRequestParameters(pars)
                // 选择哪些接口作为swagger的doc发布
                .select()
                // 配置要扫描接口的方式
                .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()));
        // 过滤path
        swaggerProperties.getBasePath().forEach(p -> builder.paths(PathSelectors.ant(p)));

        swaggerProperties.getExcludePath().forEach(p -> builder.paths(PathSelectors.ant(p).negate()));
        // 授权信息设置,必要的header token等认证信息
        // 授权信息全局应用
        return builder.build().securitySchemes(Collections.singletonList(securitySchema(swaggerProperties)))
                .securityContexts(Collections.singletonList(securityContext(swaggerProperties))).pathMapping("/");

    }

    /**
     * 配置默认的全局鉴权策略的开关,通过正则表达式进行匹配;默认匹配所有URL
     *
     * @return
     */
    private static SecurityContext securityContext(SwaggerProperties swaggerProperties) {
        return SecurityContext.builder().securityReferences(defaultAuth(swaggerProperties)).build();
    }

    /**
     * 默认的全局鉴权策略
     *
     * @return
     */
    private static List<SecurityReference> defaultAuth(SwaggerProperties swaggerProperties) {
        ArrayList<AuthorizationScope> authorizationScopeList = new ArrayList<>();
        swaggerProperties.getAuthorization().getAuthorizationScopeList()
                .forEach(authorizationScope -> authorizationScopeList.add(
                        new AuthorizationScope(authorizationScope.getScope(), authorizationScope.getDescription())));
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[authorizationScopeList.size()];
        return Collections
                .singletonList(SecurityReference.builder().reference(swaggerProperties.getAuthorization().getName())
                        .scopes(authorizationScopeList.toArray(authorizationScopes)).build());
    }

    /**
     * 设置授权信息
     */
    private static OAuth securitySchema(SwaggerProperties swaggerProperties) {
        ArrayList<AuthorizationScope> authorizationScopeList = new ArrayList<>();
        swaggerProperties.getAuthorization().getAuthorizationScopeList()
                .forEach(authorizationScope -> authorizationScopeList.add(
                        new AuthorizationScope(authorizationScope.getScope(), authorizationScope.getDescription())));
        ArrayList<GrantType> grantTypes = new ArrayList<>();
        swaggerProperties.getAuthorization().getTokenUrlList()
                .forEach(tokenUrl -> grantTypes.add(new ResourceOwnerPasswordCredentialsGrant(tokenUrl)));
        return new OAuth(swaggerProperties.getAuthorization().getName(), authorizationScopeList, grantTypes);
    }

    /**
     * API 页面上半部分展示信息
     */
    private static ApiInfo apiInfo(SwaggerProperties swaggerProperties) {
        return new ApiInfoBuilder().title(swaggerProperties.getTitle()).description(swaggerProperties.getDescription())
                .license(swaggerProperties.getLicense()).licenseUrl(swaggerProperties.getLicenseUrl())
                .termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
                .contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(),
                        swaggerProperties.getContact().getEmail()))
                .version(swaggerProperties.getVersion()).build();
    }

}

针对上面配置。斗胆来代码给解析下。

@ConditionalOnProperty控制配置文件是否可以加载。这里就是根据yml文件的swagger.enable的值来判断。matchIfMissing = true默认没有这个值也加载。

@ConditionalOnMissingClass(“org.springframework.cloud.gateway.config.GatewayAutoConfiguration”)表示当前类路径下没有这个类就创建。也就是网关服务不需要配置这个类

  1. 接着在common-swagger服务中配置GatewaySwaggerAutoConfiguration
/**
 * @Description: 网关swagger 配置类,仅在webflux 环境生效哦
 * 当Spring为web服务时,才使注解的类生效;通常是配置类;
 * 设置配置类生效环境
 * @author: heihei
 * @date: 2021年11月08日 11:53
 */
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
public class GatewaySwaggerAutoConfiguration {

    @Bean
    @Primary
    public SwaggerProvider swaggerProvider(SwaggerProperties swaggerProperties, GatewayProperties gatewayProperties) {
        return new SwaggerProvider(swaggerProperties, gatewayProperties);
    }

    @Bean
    public SwaggerResourceHandler swaggerResourceHandler(SwaggerProvider swaggerProvider) {
        return new SwaggerResourceHandler(swaggerProvider);
    }

    @Bean
    public WebFluxSwaggerConfiguration fluxSwaggerConfiguration() {
        return new WebFluxSwaggerConfiguration();
    }

    @Bean
    @ConditionalOnProperty(value = "swagger.basic.enabled", havingValue = "true")
    public SwaggerBasicGatewayFilter swaggerBasicGatewayFilter(SwaggerProperties swaggerProperties) {
        return new SwaggerBasicGatewayFilter(swaggerProperties);
    }

    @Bean
    public SwaggerSecurityHandler swaggerSecurityHandler(
            ObjectProvider<SecurityConfiguration> securityConfigurationObjectProvider) {
        SecurityConfiguration securityConfiguration = securityConfigurationObjectProvider
                .getIfAvailable(() -> SecurityConfigurationBuilder.builder().build());
        return new SwaggerSecurityHandler(securityConfiguration);
    }

    @Bean
    public SwaggerUiHandler swaggerUiHandler(ObjectProvider<UiConfiguration> uiConfigurationObjectProvider) {
        UiConfiguration uiConfiguration = uiConfigurationObjectProvider
                .getIfAvailable(() -> UiConfigurationBuilder.builder().build());
        return new SwaggerUiHandler(uiConfiguration);
    }

    @Bean
    public RouterFunction<ServerResponse> swaggerRouterFunction(SwaggerProperties swaggerProperties,
                                                                SwaggerUiHandler swaggerUiHandler, SwaggerSecurityHandler swaggerSecurityHandler,
                                                                SwaggerResourceHandler swaggerResourceHandler) {
        // 开启swagger 匹配路由
        if (swaggerProperties.getEnabled()) {
            return RouterFunctions
                    .route(RequestPredicates.GET("/swagger-resources").and(RequestPredicates.accept(MediaType.ALL)),
                            swaggerResourceHandler)
                    .andRoute(RequestPredicates.GET("/swagger-resources/configuration/ui")
                            .and(RequestPredicates.accept(MediaType.ALL)), swaggerUiHandler)
                    .andRoute(RequestPredicates.GET("/swagger-resources/configuration/security")
                            .and(RequestPredicates.accept(MediaType.ALL)), swaggerSecurityHandler);
        } else {
            // 关闭时,返回404
            return RouterFunctions.route(
                    RequestPredicates.GET("/swagger-ui/**").and(RequestPredicates.accept(MediaType.ALL)),
                    serverRequest -> ServerResponse.notFound().build());
        }
    }

}

Q1- @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
A1- 网关swagger 配置类,仅在webflux 环境生效。在mvc不需要生效。也就是当我们在upms服务引用的时候。配置文件不加载。

Q2- SwaggerProvider是啥?SwaggerProvider
A2- 首先看看SwaggerProvider的配置如下,自定义SwaggerResourcesProvider实现SwaggerResourcesProvider接口的get方法,方法可返回多个SwaggerResource,每个SwaggerResource对应每个微服务,我们可以过滤掉网关自身的

package com.hey.girl.common.swagger.support;
/**
 * @Description: 添加文档来源
 * @author: heihei
 * @date: 2021年11月08日 14:07
 */
@Primary
@RequiredArgsConstructor
public class SwaggerProvider implements SwaggerResourcesProvider {

    private static final String API_URI = "/v2/api-docs";

    private final SwaggerProperties swaggerProperties;

    private final GatewayProperties gatewayProperties;

    @Lazy
    @Autowired
    private RouteLocator routeLocator;

    /**
     * 重写get方法 返回多个SwaggerResource
     * 自定义SwaggerResourcesProvider实现SwaggerResourcesProvider接口的get方法,
     * 方法可返回多个SwaggerResource,每个SwaggerResource对应每个微服务,我们可以过滤掉网关自身的,代码如下
     */
    @Override
    public List<SwaggerResource> get() {
        List<SwaggerResource> resources = new ArrayList<>();
        List<String> routes = new ArrayList<>();
        routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
        gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId()))
                .forEach(routeDefinition -> routeDefinition.getPredicates().stream()
                        .filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName()))
                        .filter(predicateDefinition -> !swaggerProperties.getIgnoreProviders()
                                .contains(routeDefinition.getId()))
                        .forEach(predicateDefinition -> resources
                                .add(swaggerResource(routeDefinition.getId(), predicateDefinition.getArgs()
                                        .get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", API_URI)))));
        return resources;
    }
    private static SwaggerResource swaggerResource(String name, String location) {
        SwaggerResource swaggerResource = new SwaggerResource();
        swaggerResource.setName(name);
        swaggerResource.setLocation(location);
        swaggerResource.setSwaggerVersion("3.0");
        return swaggerResource;
    }
}

Q3- SwaggerResourceHandler是啥?在这里插入图片描述
A3- 首先配置SwaggerResourceHandler,就是资源处理器。执行我们自己写的SwaggerResourcesProvider的get方法。

@Slf4j
@RequiredArgsConstructor
public class SwaggerResourceHandler implements HandlerFunction<ServerResponse> {

    private final SwaggerResourcesProvider swaggerResources;

    @Override
    public Mono<ServerResponse> handle(ServerRequest request) {
        return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(swaggerResources.get()));
    }
}

Q4- 这个上面写的就是资源路径配置。(上面已经配置了,所以不贴代码)在这里插入图片描述
Q5- 接着看看这段代码SwaggerBasicGatewayFilter
SwaggerBasicGatewayFilter
SwaggerBasicGatewayFilter:

@Slf4j
@RequiredArgsConstructor
public class SwaggerBasicGatewayFilter implements GlobalFilter {

    private static final String API_URI = "/v2/api-docs";

    private static final String BASIC_PREFIX = "Basic ";

    private final SwaggerProperties swaggerProperties;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();

        if (!request.getURI().getPath().contains(API_URI)) {
            return chain.filter(exchange);
        }

        if (hasAuth(exchange)) {
            return chain.filter(exchange);
        }
        else {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            response.getHeaders().add(HttpHeaders.WWW_AUTHENTICATE, "Basic Realm=\"girl\"");
            return response.setComplete();
        }
    }

    /**
     * 简单的basic认证
     * @param exchange 上下文
     * @return 是否有权限
     */
    private boolean hasAuth(ServerWebExchange exchange) {
        ServerHttpRequest request = exchange.getRequest();
        String auth = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
        log.info("Basic认证信息为:{}", auth);
        if (!StringUtils.hasText(auth) || !auth.startsWith(BASIC_PREFIX)) {
            return Boolean.FALSE;
        }

        String username = swaggerProperties.getBasic().getUsername();
        String password = swaggerProperties.getBasic().getPassword();

        String encodeToString = Base64Utils
                .encodeToString((username + ":" + password).getBytes(StandardCharsets.UTF_8));

        return auth.equals(BASIC_PREFIX + encodeToString);
    }

}

A5- swagger.basic.enabled值为true,才加载。basic 过滤器

Q6- SwaggerSecurityHandler
A6-SwaggerSecurityHandler配置

@Slf4j
@RequiredArgsConstructor
public class SwaggerSecurityHandler implements HandlerFunction<ServerResponse> {


    private final SecurityConfiguration securityConfiguration;

    /**
     * Handle the given request.
     *
     * @param request the request to handler
     * @return the response
     */
    @Override
    public Mono<ServerResponse> handle(ServerRequest request) {
        return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(Optional.ofNullable(securityConfiguration)
                        .orElse(SecurityConfigurationBuilder.builder().build())));
    }
}

Q7- SwaggerUiHandler
A7- SwaggerUiHandler

@Slf4j
@RequiredArgsConstructor
public class SwaggerUiHandler implements HandlerFunction<ServerResponse> {


    private final UiConfiguration uiConfiguration;

    /**
     * Handle the given request.
     * @param request the request to handler
     * @return the response
     */
    @Override
    public Mono<ServerResponse> handle(ServerRequest request) {
        return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(BodyInserters
                .fromValue(Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build())));
    }
}
  1. 差不多配置文件就这些。配置完以后。只需要使用的服务中加上注解
    类似这样
    在这里插入图片描述
    然后再配置yml文件中加下配置:

基本配置忽略认证服务
访问:
http://localhost:9999/swagger-ui/#/在这里插入图片描述
可以右上角的服务是都可以选的。已经把服务整合进来了。当我们需要认证的时候。
在这里插入图片描述
至此基本配置完成。

再说说注解,相信之前的注解@Api开头的就很常见。但是我发现有新的注解@Tag.但是我使用了,没有效果。这个暂时不知道原因。但是用之前swagger2的注解。还是挺好用的

完结,撒花!后面有啥再补充

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值