溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

springcloud gateway集成knife4j的方法是什么

發(fā)布時(shí)間:2023-03-13 13:52:10 來源:億速云 閱讀:143 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“springcloud gateway集成knife4j的方法是什么”的相關(guān)知識(shí),小編通過實(shí)際案例向大家展示操作過程,操作方法簡(jiǎn)單快捷,實(shí)用性強(qiáng),希望這篇“springcloud gateway集成knife4j的方法是什么”文章能幫助大家解決問題。

springcloud-gateway集成knife4j

環(huán)境信息

環(huán)境信息

  • spring-boot:2.6.3

  • spring-cloud-alibaba:2021.0.1.0

  • knife4j-openapi2-spring-boot-starter:4.0.0

準(zhǔn)備工作

各微服務(wù)&網(wǎng)關(guān)引入依賴

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

微服務(wù)集成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 基礎(chǔ)信息配置。更多配置信息項(xiàng)見{@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;
    
    /**
     * 是否啟用登錄認(rèn)證
     */
    @Value("${api-info.enable-security:true}")
    private boolean enableSecurity;
    
    /**
     * 文檔標(biāo)題
     */
    @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;
    
    /**
     * 聯(lián)系人姓名
     */
    @Value("${api-info.contact-name:JustryDeng}")
    private String contactName;
    
    /**
     * 聯(lián)系人網(wǎng)址
     */
    @Value("${api-info.contact-url:https://gitee.com/JustryDeng/projects}")
    private String contactUrl;
    
    /**
     * 聯(lián)系人郵箱
     */
    @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 {
    
    /** 文檔相關(guān)資源的鏈接(需保證這些資源不需要鑒權(quán)即可訪問) */
    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() {
        // 設(shè)置請(qǐng)求頭信息
        List<SecurityScheme> result = new ArrayList<>();
        // 第一個(gè)參數(shù),自定義即可。 如: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() {
        // 設(shè)置需要登錄認(rèn)證的路徑
        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;
    }
    
}

第三步:放行相關(guān)靜態(tài)資源

對(duì)于管控了權(quán)限的應(yīng)用,應(yīng)放行以下資源

# 需要放行的資源已經(jīng)定義進(jìn)上面編寫的Knife4jConfig中
public static String[] RESOURCE_URLS = new String[]{"/webjars/**", "/swagger**", "/v2/api-docs", "/doc.html"};

網(wǎng)關(guān)集成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.cloud.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.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 網(wǎng)關(guān)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 securityConfiguration;
    
    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));
    }
    
    /**
     * 資源配置,自動(dòng)路由到微服務(wù)中的各個(gè)服務(wù)的api-docs信息
     */
    @GetMapping("/swagger-resources")
    public Mono<ResponseEntity<List<SwaggerResource>>> swaggerResources() {
        return Mono.just(new ResponseEntity<>(swaggerResourceAdapter.get(), HttpStatus.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是否開啟了根據(jù)服務(wù)發(fā)現(xiàn)自動(dòng)為服務(wù)創(chuàng)建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;
        
        /**
         * 根據(jù)當(dāng)前所有的微服務(wù)路由信息,創(chuàng)建對(duì)應(yīng)的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);
            });
            // 沒有開啟自動(dòng)創(chuàng)建路由,那么走配置文件中配置的路由
            if (!autoCreateRouter) {
                finalResources = new ArrayList<>(16);
                gatewayProperties.getRoutes().stream()
                        // 過濾出配置文件中定義的路由
                        .filter(routeDefinition -> routes.contains(routeDefinition.getId())).forEach(route -> {
                            route.getPredicates().stream()
                                    // 過濾出設(shè)置有Path Predicate的路由
                                    .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
                                    // 根據(jù)路徑拼接成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過濾掉網(wǎng)關(guān)的SwaggerResource, 我們一般也不會(huì)在網(wǎng)關(guān)中編寫業(yè)務(wù)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;
        }
        
        /**
         * 創(chuàng)建swagger資源
         *
         * @param name
         *            swagger資源名(注:一般對(duì)應(yīng) {路由id})
         * @param location
         *            swagger資源路徑(注:一般對(duì)應(yīng) {路由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;
        }
        
    }
}

測(cè)試驗(yàn)證

啟動(dòng)微服務(wù)后,訪問{網(wǎng)關(guān)}/doc.html完成驗(yàn)證

springcloud gateway集成knife4j的方法是什么

關(guān)于“springcloud gateway集成knife4j的方法是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI