开发者

springcloud-gateway集成knife4j的示例详解

目录
  • springcloud-gateway集成knife4j
    • 环境信息
  • 环境信息
    • 准备工作
  • 网关集成knife4j
    • 编写配置类Knife4jGatewayConfig
    • 测试验证
  • 相关资料

    springcloud-gateway集成knife4j

    环境信息

    环境信息

    • spring-boot:2.6.3
    • spring-cloud-alibaba:2021编程客栈.0.1.0
    • knife4j-openapi2-spring-boot-starter:4.0.0

    准备工作

    各微服务&网关引入依赖

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

    微服务集成knife4j 第一步:编写Knife4jApiInfoProperties

    import com.ideaaedi.springcloud.jd.commonspring.config.Knife4jConfig;
    import lombok.Data;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    
    /**
     * api 基础信息配置。更多配置信息项见{@link Knife4jConfig}
     *
     * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img
     * src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
     * @since 2021.0.1.D
     */
    @Data
    @Component
    public class Knife4jApiInfoProperties {
        
        /**
         * 要扫描api的base包
         */
        @Value("${api-info.base-package:com}")
        private String basePackage;
        
        /**
         * 是否启用登录认证
         */
        @Value("${api-info.enable-security:true}")
        private boolean enableSecurity;
        
        /**
         * 文档标题
         */
        @Value("${api-info.title:}")
        private String title;
        
        /**
         * 文档描述
         */
        @Value("${api-info.description:api info}")
        private String description;
        
        /**
         * 文档版本
         */
        @Value("${api-info.version:1.0.0}")
        private String version;
        
        /**
         * 联系人姓名
         */
        @Value("${api-info.contact-name:JustryDeng}")
        private String contactName;
        
        /**
         * 联系人网址
         */
        @Value("${api-info.contact-url:https://gitee.com/JustryDeng/projects}")
        private String contactUrl;
     编程   
        /**
         * 联系人邮箱
         */
        @Value("${api-info.contact-email:13548417409@163.com}")
        private String contactEmail;
    }
    

    第二步:编写配置类Knife4jConfig

    import com.ideaaedi.springcloud.jd.commonds.constant.BaseConstant;
    import com.ideaaedi.springcloud.jd.commonspring.config.properties.Knife4jApiInfoProperties;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.service.ApiKey;
    import springfox.documentation.service.AuthorizationScope;
    import springfox.documentation.service.Contact;
    import springfox.documentation.service.SecurityReference;
    import springfox.documentation.service.SecurityScheme;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spi.service.contexts.SecurityContext;
    import springfox.documentation.spring.web.plugins.Docket;
    
    import Java.util.ArrayList;
    import java.util.List;
    
    /**
     * knife4j配置类
     *
     * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img
     * src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
     * @since 2021.0.1.D
     */
    @Slf4j
    @Configuration
    public class Knife4jConfig implements WebMvcConfigurer {
        
        /** 文档相关资源的链接(需保证这些资源不需要鉴权即可访问) */
        public static String[] RESOURCE_URLS = new String[]{"/webjars/**", "/swagger**", "/v2/api-docs", "/doc.html"};
        
        @Value("${spring.application.name:}")
        private String applicationName;
        
        @Bean
        public Docket docket(Knife4jApiInfoProperties knife4jApiInfoProperties) {
            String apiBasePackage = knife4jApiInfoProperties.getBasePackage();
            Docket docket = new Docket(DocumentationType.SWAGGER_2)
                    .apiInfo(apiInfo(knife4jApiInfoProperties))
                    .select()
                    .apis(RequestHandlerSelectors.basePackage(apiBasePackage))
                    .paths(PathSelectors.any())
                    .build();
            if (knife4jApiInfoProperties.isEnableSecurity()) {
                docket.securitySchemes(securitySchemes()).securityContexts(securityContexts());
            }
            return docket;
        }
        
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
            registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
        }
        
        private ApiInfo apiInfo(Knife4jApiInfoProperties knife4jApiInfoProperties) {
            return new ApiInfoBuilder()
                    .title(knife4jApiInfoProperties.getTitle())
                    .description(knife4jApiInfoProperties.getDescription())
                    .termsOfServiceUrl(StringUtils.isBlank(applicationName) ? "" : "/" + applicationName)
                    .contact(new Contact(knife4jApiInfoProperties.getContactName(), knife4jApiInfoProperties.getContactUrl(), knife4jApiInfoProperties.getContactEmail()))
                    .version(knife4jApiInfoProperties.getVersion())
                    .build();
        }
        
        private List<SecurityScheme> securitySchemes() {
            // 设置请求头信息
            List<SecurityScheme> result = new ArrayList<>();
            // 第一个参数,自定义即可。 如:BaseConstant.JWT_TOKEN_KEY=Auth-Token,然后在代码里request.getHeader(BaseConstant.JWT_TOKEN_KEY)取值
            ApiKey apiKey = new ApiKey(BaseConstant.JWT_TOKEN_KEY, "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;
        }
        
    }
    
    

    第三步:放行相关静态资源

    对于管控了权限的应用,应放行以下资源

    # 需要放行的资源已经定义进上面编写的Knife4jConfig中
    public static String[] RESOURCE_URLS = new String[]{"/webjars/**", "/swagger**", "/v2/api-docs", "/doc.html"};

    网关集成knife4j

    编写配置类Knife4jGatewayConfig

    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.gateway.config.GatewayProperties;
    import org.springframework.cloud.gateway.route.RouteLocator;
    import org.springframework.clpythonoud.gateway.support.NameUtils;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.stereotype.Component;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import reactor.core.publisher.Mono;
    import springfox.documentation.swagger.web.SecurityConfiguration;
    import springfox.documentation.swagger.web.SecurityConfigurationBuilder;
    import springfox.documentation.swagger.web.SwaggerResource;
    import springfox.documentation.swagger.web.SwaggerResourcesProvider;
    import springfox.documentation.swagger.web.UiConfiguration;
    import springfox.documentation.swagger.web.UiConfigurationBuilder;
    
    import javax.annotation.Resource;
    import java.util.ArrayList;
    import java.util.Comparator;
    import java.util.LinkedHashSet;
    import java.util.List;
    import java.util.Opti开发者_C培训onal;
    import java.util.Set;
    import java.util.stream.Collectors;
    
    /**
     * 网关knife4j配置
     *
     * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
     * @since 2021.0.1.D
     */
    @RestController
    public class Knife4jGatewayConfig {
        
        private final SecurityConfiguration securityConfi编程客栈guration;
        
        private final UiConfiguration uiConfiguration;
        
        private final SwaggerResourceAdapter swaggerResourceAdapter;
        
        public Knife4jGatewayConfig(@Autowired(required = false) SecurityConfiguration securityConfiguration,
                                    @Autowired(required = false) UiConfiguration uiConfiguration,
                                    SwaggerResourceAdapter swaggerResourceAdapter) {
            this.securityConfiguration = securityConfiguration;
            this.uiConfiguration = uiConfiguration;
            this.swaggerResourceAdapter = swaggerResourceAdapter;
        }
        
        /**
         * 安全配置
         */
        @GetMapping("/swagger-resources/configuration/security")
        public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
            return Mono.just(new ResponseEntity<>(
                    Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
        }
        
        /**
         * ui配置
         */
        @GetMapping("/swagger-resources/configuration/ui")
        public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
            return Mono.just(new ResponseEntity<>(
                    Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
        }
        
        /**
         * 资源配置,自动路由到微服务中的各个服务的api-docs信息
         */
        @GetMapping("/swagger-resources")
        public Mono<ResponseEntity<List<SwaggerResource>>> swaggerResources() {
            return Mono.just(new ResponseEntity<>(swaggerResourceAdapter.get(), Ht编程tpStatus.OK));
        }
        
        /**
         * favicon.ico
         */
        @GetMapping("/favicon.ico")
        public Mono<ResponseEntity<?>> favicon() {
            return Mono.just(new ResponseEntity<>(null, HttpStatus.OK));
        }
        
        /**
         * swagger资源适配器
         *
         * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" />
         * @since 2021.0.1.D
         */
        @Slf4j
        @Component
        public static class SwaggerResourceAdapter implements SwaggerResourcesProvider {
            
            /**
             * spring-cloud-gateway是否开启了根据服务发现自动为服务创建router
             */
            @Value("${spring.cloud.gateway.discovery.locator.enabled:false}")
            private boolean autoCreateRouter;
            
            @Value("${spring.application.name:}")
            private String applicationName;
            
            @Resource
            private RouteLocator routeLocator;
            
            @Resource
            private GatewayProperties gatewayProperties;
            
            /**
             * 根据当前所有的微服务路由信息,创建对应的SwaggerResource
             */
            @Override
            public List<SwaggerResource> get() {
                List<SwaggerResource> finalResources;
                Set<String> routes = new LinkedHashSet<>(16);
                // 获取所有路由的id
                routeLocator.getRoutes().subscribe(route -> {
                    String routeId = route.getId();
                    routeId = routeId.replace("ReactiveCompositeDiscoveryClient_", "");
                    routes.add(routeId);
                });
                // 没有开启自动创建路由,那么走配置文件中配置的路由
                if (!autoCreateRouter) {
                    finalResources = new ArrayList<>(16);
                    gatewayProperties.getRoutes().stream()
                            // 过滤出配置文件中定义的路由
                            .filter(routeDefinition -> routes.contains(routeDefinition.getId())).forEach(route -> {
                                route.getPredicates().stream()
                                        // 过滤出设置有Path Predicate的路由
                                        .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
                                        // 根据路径拼接成api-docs路径,生成SwaggerResource
                                        .forEach(predicateDefinition -> finalResources.add(swaggerResource(route.getId(),
                                                predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0")
                                                        .replace("**", "v2/api-docs"))));
                            });
                } else {
                    finalResources = routes.stream().map(routeId -> swaggerResource(routeId, routeId + "/v2/api-docs")).collect(Collectors.toList());
                }
                List<SwaggerResource> resources = new ArrayList<>(finalResources);
                // resources过滤掉网关的SwaggerResource, 我们一般也不会在网关中编写业务controller
                if (StringUtils.isNotBlank(applicationName)) {
                    resources = resources.stream().filter(x -> !applicationName.equalsIgnoreCase(x.getName())).collect(Collectors.toList());
                }
                // 排序
                resources.sort(Comparator.comparing(x -> x.getName().length()));
                return resources;
            }
            
            /**
             * 创建swagger资源
             *
             * @param name
             *            swagger资源名(注:一般对应 {路由id})
             * @param location
             *            swagger资源路径(注:一般对应 {路由id}/v2/api-docs)
             * @return  swager资源
             */
            private SwaggerResource swaggerResource(String name, String location) {
                log.info("name:{},location:{}", name, location);
                SwaggerResource swaggerResource = new SwaggerResource();
                swaggerResource.setName(name);
                swaggerResource.setLocation(location);
                swaggerResource.setSwaggerVersion("2.0");
                return swaggerResource;
            }
            
        }
    }
    
    

    测试验证

    启动微服务后,访问{网关}/doc.html完成验证

    springcloud-gateway集成knife4j的示例详解

    相关资料

    springboot2集成knife4j

    在微服务项目中引入 knife4j

    到此这篇关于springcloud-gateway集成knife4j的文章就介绍到这了,更多相关springcloud-gateway集成knife4j内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜