• 微服务与中间件系列——GateWay整合Swagger3增强Knife4j


    GateWay整合Swagger3增强Knife4j(easy模式)

    目的

    统一进行文档管理,查看,避免swagger文档在微服务中使用繁琐的问题
    本案例使用nacos作为服务的注册中心

    服务端

    1.导入依赖

            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-boot-starter</artifactId>
                <version>3.0.0</version>
            </dependency>
            <dependency>
                <groupId>com.github.xiaoymin</groupId>
                <artifactId>knife4j-spring-boot-starter</artifactId>
                <version>3.0.3</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.编写配置类

    package cn.fly.client.config;
    
    import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
    import io.swagger.annotations.ApiOperation;
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    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 Syf200208161018
     * @date 2022/11/19 15:44
     * @ClassName:SwaggerConfig
     * @Effect:SwaggerConfig is used for
     */
    @Configuration
    @EnableOpenApi
    @Data
    @ConfigurationProperties(prefix = "swagger")
    public class SwaggerConfig {
    
    
        /**
         * 是否开启swagger,生产环境一般关闭,所以这里定义一个变量
         */
        private Boolean enable;
    
        /**
         * 项目应用名
         */
        private String applicationName;
    
        /**
         * 项目版本信息
         */
        private String applicationVersion;
    
        /**
         * 项目描述信息
         */
        private String applicationDescription;
    
        @Bean
        public Docket docket() {
            return new Docket(DocumentationType.OAS_30)
                    .pathMapping("/")
    
                    // 定义是否开启swagger,false为关闭,可以通过变量控制,线上关闭
                    .enable(enable)
    
                    //配置api文档元信息
                    .apiInfo(apiInfo())
    
                    // 选择哪些接口作为swagger的doc发布
                    .select()
    
                    //apis() 控制哪些接口暴露给swagger,
                    // RequestHandlerSelectors.any() 所有都暴露
                    // RequestHandlerSelectors.basePackage("net.xdclass.*")  指定包位置
                    // withMethodAnnotation(ApiOperation.class)标记有这个注解 ApiOperation
                    .apis(RequestHandlerSelectors.basePackage("cn.fly.client.controller.common"))
    
                    .paths(PathSelectors.any())
    
                    .build();
        }
    
    
        private ApiInfo apiInfo() {
            return new ApiInfoBuilder()
                    .title(applicationName)
                    .description(applicationDescription)
                    .contact(new Contact("syf", "syf20020816@outlook.com", "syf20020816@outlook.com"))
                    .version(applicationVersion)
                    .build();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    3.yaml配置

    1. 配置服务名称
    2. 配置mvc路径策略
    3. 配置nacos路径
    4. 配置swagger(自定义非官方,看配置类就知道了)
    spring:
      application:
        name: Eprop-client
      mvc:
        pathmatch:
          matching-strategy: ant_path_matcher
      cloud:
        nacos:
    #      server-addr: 192.168.31.149:8848
          server-addr: 172.16.216.47:8848
    swagger:
      enable: true
      application-name: Eprop-client
      application-version: 1.0.0
      application-description: client
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    GateWay网关

    1.文档枚举

    package cn.fly.gateway.swagger;
    
    import io.netty.channel.nio.AbstractNioByteChannel;
    
    /**
     * @author Syf200208161018
     * @date 2022/11/19 19:12
     * @ClassName:DocEnum
     * @Effect:DocEnum is used for
     */
    public enum DocEnum {
        /**
         * 路由信息
         */
        EPROP_COMMON("Eprop-client","eprop-API模块");
    
    
        private String routeId;
        private String swaggerInfo;
    
        DocEnum(String routeId, String swaggerInfo) {
            this.routeId = routeId;
            this.swaggerInfo = swaggerInfo;
        }
    
        public String getRouteId() {
            return routeId;
        }
    
        public void setRouteId(String routeId) {
            this.routeId = routeId;
        }
    
        public String getSwaggerInfo() {
            return swaggerInfo;
        }
    
        public void setSwaggerInfo(String swaggerInfo) {
            this.swaggerInfo = swaggerInfo;
        }
    
        public static String getSwaggerInfoByRouteId(String routeId){
            for (DocEnum value : DocEnum.values()) {
                if (value.getRouteId().equals(routeId)){
                    return value.getSwaggerInfo();
                }
            }
            return null;
        }
    
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    2.SwaggerProvider

    实现SwaggerResourcesProvider对资源进行修改

    package cn.fly.gateway.swagger;
    
    import com.alibaba.cloud.commons.lang.StringUtils;
    import lombok.AllArgsConstructor;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.gateway.config.GatewayProperties;
    import org.springframework.cloud.gateway.route.RouteLocator;
    import org.springframework.cloud.gateway.support.NameUtils;
    import org.springframework.context.annotation.Primary;
    import org.springframework.stereotype.Component;
    import springfox.documentation.swagger.web.SwaggerResource;
    import springfox.documentation.swagger.web.SwaggerResourcesProvider;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author Syf200208161018
     * @date 2022/11/19 16:55
     * @ClassName:SwaggerProvider
     * @Effect:SwaggerProvider is used for
     */
    /**
     * 聚合系统接口
     * @author ROCKY
     */
    @Component
    @Primary
    
    public class SwaggerProvider implements SwaggerResourcesProvider {
    
        public static final String API_URI = "/v3/api-docs";
        private final RouteLocator routeLocator;
        private final GatewayProperties gatewayProperties;
    
        public SwaggerProvider(RouteLocator routeLocator, GatewayProperties gatewayProperties) {
            this.routeLocator = routeLocator;
            this.gatewayProperties = gatewayProperties;
        }
    
        @Override
        public List<SwaggerResource> get() {
            List<SwaggerResource> resources = new ArrayList<>();
            List<String> routes = new ArrayList<>();
            // 取出gateway的route
            routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
            // 结合配置的route-路径(Path),和route过滤,只获取在枚举中说明的route节点
            gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId()))
                    .forEach(routeDefinition -> routeDefinition.getPredicates().stream()
                            // 目前只处理Path断言  Header或其他路由需要另行扩展
                            .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
                            .forEach(predicateDefinition -> {
                                        String routeId = routeDefinition.getId();
                                        String swaggerInfo = DocEnum.getSwaggerInfoByRouteId(routeId);
                                        if (StringUtils.isNotEmpty(swaggerInfo)) {
                                            resources.add(swaggerResource(swaggerInfo, predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", API_URI)));
                                        }
                                    }
                            ));
            return resources;
        }
    
        private SwaggerResource swaggerResource(String name, String location) {
            SwaggerResource swaggerResource = new SwaggerResource();
            swaggerResource.setName(name);
            swaggerResource.setLocation(location);
            swaggerResource.setSwaggerVersion("3.0");
            return swaggerResource;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    3.yaml配置

    1. 注意路由的ID要对应服务的名称
      在这里插入图片描述

    2. 注意过滤器的StripPrefix=3一定要和你前面指定的断言- Path=/api/v1/eprop/**匹配上,比如我这个就是去除3个前缀,如果是/api/hello/**,就是去除2个前缀,这个一定不能错,因为这和swagger请求地址有关
      在这里插入图片描述

    server:
      port: 21301
    spring:
      application:
        name: gateway
      cloud:
        nacos:
    #      server-addr: 192.168.31.149:8848
          server-addr: 172.16.216.47:8848
    #     server-addr: 192.168.1.103:8848
        gateway:
          routes:
            - id: Eprop-client
              uri: lb://Eprop-client
              predicates:
                - Path=/api/v1/eprop/**
              filters:
                - StripPrefix=3
          globalcors:
            cors-configurations:
              '[/**]':
                allowedOrigins: # 允许哪些网站进行跨域请求
                  - "http://localhost:8080"
                allowedMethods:
                  - "GET"
                  - "POST"
                  - "DELETE"
                  - "PUT"
                  - "OPTIONS"
                allowedHeaders: "*" # 允许所有请求头
                allowCredentials: true # 是否允许携带cookie
                maxAge: 360000 # 跨域监测有效期
            add-to-simple-url-handler-mapping: true #解决options请求拦截
          discovery:
            locator:
              lower-case-service-id: true
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    结果

    启动gateway浏览器访问ip:端口/doc.html
    成功如下:
    在这里插入图片描述

    增强版

    其实也就是做了一下对于配置的处理

    服务端

    1.增加配置参数类

    package cn.fly.client.properties;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author Syf200208161018
     * @date 2022/11/20 0:44
     * @ClassName:SwaggerProperties
     * @Effect:SwaggerProperties is used for
     */
    @ConfigurationProperties(prefix = "swagger-api")
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class SwaggerProperties {
        private String title="EPROP-API文档";
        private String groupName = "default";
        private String des="default API doc";
        private String version="1.1.0";
    //    private Contact contact = new Contact("syf","syf20020816@outlook.com","syf20020816@outlook.com");
        private String docMaker = "syf";
        private String docUrl = "syf20020816@Outlook.com";
        private String makerEmail="syf20020816@Outlook.com";
        private String basePackage="cn.fly.client.controller";
        //解析的url规则
        private List<String> basePath = new ArrayList<>();
        //需要排除的url
        private List<String> excludePath = new ArrayList<>();
        /**
         * 是否开启swagger,生产环境一般关闭,所以这里定义一个变量
         */
        private Boolean enable;
    
        /**
         * 项目应用名
         */
        private String applicationName;
    
        /**
         * 项目版本信息
         */
        private String applicationVersion;
    
        /**
         * 项目描述信息
         */
        private String applicationDescription;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    2.修改配置类

    package cn.fly.client.config;
    
    import cn.fly.client.properties.SwaggerProperties;
    import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
    import io.swagger.annotations.ApiOperation;
    import lombok.Data;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    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 Syf200208161018
     * @date 2022/11/19 15:44
     * @ClassName:SwaggerConfig
     * @Effect:SwaggerConfig is used for
     */
    @Configuration
    @EnableOpenApi
    @EnableConfigurationProperties(SwaggerProperties.class)
    public class SwaggerConfig {
        @Autowired
        private SwaggerProperties swaggerProperties;
    
        @Bean
        public Docket docket() {
            return new Docket(DocumentationType.OAS_30)
                    .pathMapping("/")
                    // 定义是否开启swagger,false为关闭,可以通过变量控制,线上关闭
                    .enable(swaggerProperties.getEnable())
                    //配置api文档元信息
                    .apiInfo(apiInfo())
                    // 选择哪些接口作为swagger的doc发布
                    .select()
                    //apis() 控制哪些接口暴露给swagger,
                    // RequestHandlerSelectors.any() 所有都暴露
                    // RequestHandlerSelectors.basePackage("net.xdclass.*")  指定包位置
                    // withMethodAnnotation(ApiOperation.class)标记有这个注解 ApiOperation
                    .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))
                    .paths(PathSelectors.any())
                    .build();
        }
    
    
        private ApiInfo apiInfo() {
            return new ApiInfoBuilder()
                    .title(swaggerProperties.getTitle())
                    .description(swaggerProperties.getApplicationDescription())
                    .contact(new Contact(swaggerProperties.getDocMaker(),swaggerProperties.getDocUrl(),swaggerProperties.getMakerEmail()))
                    .version(swaggerProperties.getApplicationVersion())
                    .build();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    3.修改yaml配置

    swagger-api:
      enable: true
      application-name: Eprop-client
      application-version: 1.0.0
      application-description: Eprop API文档Swagger3版本
      title: EPROP-API 文档
      groupName: Eprop-client
      des: Eprop API文档Swagger3版本
      version: 1.0.0
      docMaker: syf
      docUrl: www.eprop.fly.cn
      markerEmail: syf20020816@Outlook.com
      basePackage: cn.fly.client.controller
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    GateWay网关

    1.增加全局认证过滤器

    package cn.fly.gateway.filter;
    
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.core.annotation.Order;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.server.reactive.ServerHttpRequest;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    import java.util.List;
    
    /**
     * @author Syf200208161018
     * @date 2022/10/28 13:16
     * @ClassName:AuthorizeFilter
     * @Effect:AuthorizeFilter is used for filtering user
     * the request header must have a token-eprop and then getUserInfo
     */
    @Component
    @Order(-1)
    public class AuthorizeFilter implements GlobalFilter {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            System.out.println(exchange.getRequest().getURI().getPath());
                if (exchange.getRequest().getURI().getPath().equals("/v3/api-docs")){
                    return chain.filter(exchange);
                }else{
                    //get request params
                    final ServerHttpRequest request = exchange.getRequest();
                    //get header: token-eprop
                    final HttpHeaders requestHeaders = request.getHeaders();
                    final List<String> values = requestHeaders.get("token-eprop");
                    for (String value : values) {
                        System.out.println(value);
                    }
                    final String tokenValue = values.get(0);
                    System.out.println(tokenValue);
                    //if tokenValue is empty or null intercept the request
                    if (StringUtils.isBlank(tokenValue)){
                        return exchange.getResponse().setComplete();
                    }
                    return chain.filter(exchange);
                }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    其他无需更改

  • 相关阅读:
    AWS CloudFormation
    作业 --- 数组
    java并发编程 SynchronousQueue详解
    系统移植3:kernel的配置,编译和移植以及根文件系统
    一文搞懂shell脚本
    自学Python笔记总结(2——了解)
    高级工程师评审:高级工程师有哪些专业?高级工程师职称专业分类
    java.lang.Float类下compareTo()方法具有什么功能呢?
    go mod why
    OpenHarmony实战开发-文件上传下载性能提升指导。
  • 原文地址:https://blog.csdn.net/qq_51553982/article/details/127944394