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 >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 >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)即可訪問(wè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 >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 >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); }); // 沒(méi)有開啟自動(dòng)創(chuàng)建路由,那么走配置文件中配置的路由 if (!autoCreateRouter) { finalResources = new ArrayList<>(16); gatewayProperties.getRoutes().stream() // 過(guò)濾出配置文件中定義的路由 .filter(routeDefinition -> routes.contains(routeDefinition.getId())).forEach(route -> { route.getPredicates().stream() // 過(guò)濾出設(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過(guò)濾掉網(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èn){網(wǎng)關(guān)}/doc.html
完成驗(yàn)證
相關(guān)資料
到此這篇關(guān)于springcloud-gateway集成knife4j的文章就介紹到這了,更多相關(guān)springcloud-gateway集成knife4j內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringCloudGateway?Nacos?GitlabRunner全自動(dòng)灰度服務(wù)搭建發(fā)布
- 基于SpringCloudGateway實(shí)現(xiàn)微服務(wù)網(wǎng)關(guān)的方式
- 詳解SpringCloudGateway內(nèi)存泄漏問(wèn)題
- SpringCloudGateway開發(fā)過(guò)程解析
- SpringCloud Gateway動(dòng)態(tài)路由配置詳解
- SpringCloud Gateway實(shí)現(xiàn)限流功能詳解
- SpringCloudGateway使用Skywalking時(shí)日志打印traceId解析
相關(guān)文章
APP轉(zhuǎn)盤抽獎(jiǎng)Java服務(wù)端接口詳解
這篇文章主要為大家詳細(xì)介紹了APP轉(zhuǎn)盤抽獎(jiǎng)Java服務(wù)端接口,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01SpringBoot通過(guò)源碼探究靜態(tài)資源的映射規(guī)則實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot通過(guò)源碼探究靜態(tài)資源的映射規(guī)則實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05Java中LocalDate的詳細(xì)方法舉例總結(jié)
這篇文章主要給大家介紹了關(guān)于Java中LocalDate詳細(xì)方法舉例的相關(guān)資料,LocalDate主要是用來(lái)處理日期的類,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09SSH框架網(wǎng)上商城項(xiàng)目第6戰(zhàn)之基于DataGrid的數(shù)據(jù)顯示
SSH框架網(wǎng)上商城項(xiàng)目第6戰(zhàn)之基于DataGrid的數(shù)據(jù)顯示,提供了豐富的選擇、排序、分組和編輯數(shù)據(jù)的功能支持,感興趣的小伙伴們可以參考一下2016-05-05Java中常用的設(shè)計(jì)模式之責(zé)任鏈模式詳解
這篇文章主要為大家詳細(xì)介紹了Java中常用的設(shè)計(jì)模式之責(zé)任鏈模式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-02-02Java設(shè)計(jì)模式之動(dòng)態(tài)代理
今天小編就為大家分享一篇關(guān)于Java設(shè)計(jì)模式之動(dòng)態(tài)代理,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01Java Metrics系統(tǒng)性能監(jiān)控工具的使用詳解
Metrics是一個(gè)Java庫(kù),可以對(duì)系統(tǒng)進(jìn)行監(jiān)控,統(tǒng)計(jì)一些系統(tǒng)的性能指標(biāo)。本文就來(lái)和大家詳細(xì)聊聊這個(gè)工具的具體使用,希望對(duì)大家有所幫助2022-11-11