From ec280224a828f05753f106e31cea9c4ed0855e63 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 4 Mar 2023 15:40:50 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E4=BA=8E=E8=80=81=E7=89=88=E6=9C=AC?= =?UTF-8?q?=EF=BC=8C=E5=AE=9E=E7=8E=B0=20Spring=20Cloud=20Gateway=20?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-gateway/pom.xml | 5 +- .../config/SpringDocConfiguration.java | 35 --- .../yudao/gateway/swagger/SwaggerHandler.java | 108 +++++----- .../gateway/swagger/SwaggerProvider.java | 204 +++++++++--------- .../src/main/resources/application.yaml | 12 +- 5 files changed, 165 insertions(+), 199 deletions(-) delete mode 100644 yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/config/SpringDocConfiguration.java diff --git a/yudao-gateway/pom.xml b/yudao-gateway/pom.xml index 2b1b27e69..cef02f3d9 100644 --- a/yudao-gateway/pom.xml +++ b/yudao-gateway/pom.xml @@ -57,8 +57,9 @@ - org.springdoc - springdoc-openapi-webflux-ui + com.github.xiaoymin + knife4j-spring-boot-starter + 3.0.3 diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/config/SpringDocConfiguration.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/config/SpringDocConfiguration.java deleted file mode 100644 index ea54f01de..000000000 --- a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/config/SpringDocConfiguration.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.gateway.config; - -import lombok.extern.slf4j.Slf4j; -import org.springdoc.core.GroupedOpenApi; -import org.springframework.cloud.gateway.route.RouteDefinition; -import org.springframework.cloud.gateway.route.RouteDefinitionLocator; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Lazy; - -import java.util.ArrayList; -import java.util.List; - -@Slf4j -@Configuration -public class SpringDocConfiguration { - private static final String SERVER_NAME_SUFFIX = "-api"; - - @Bean - @Lazy(false) - public List apis(RouteDefinitionLocator locator) { - List groups = new ArrayList<>(); - List definitions = locator.getRouteDefinitions().collectList().block(); - for (RouteDefinition definition : definitions) { - log.info("id: " + definition.getId() + " " + definition.getUri().toString()); - } - definitions.stream() - .filter(routeDefinition -> routeDefinition.getId().matches(".*"+SERVER_NAME_SUFFIX)) - .forEach(routeDefinition -> { - String name = routeDefinition.getId().replaceAll(SERVER_NAME_SUFFIX, ""); - GroupedOpenApi.builder().pathsToMatch("/" + name + "/**").group(name).build(); - }); - return groups; - } -} diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/swagger/SwaggerHandler.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/swagger/SwaggerHandler.java index 3b30a4786..7cae3c810 100644 --- a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/swagger/SwaggerHandler.java +++ b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/swagger/SwaggerHandler.java @@ -1,54 +1,54 @@ -//package cn.iocoder.yudao.gateway.swagger; -// -// -//import org.springframework.beans.factory.annotation.Autowired; -//import org.springframework.http.HttpStatus; -//import org.springframework.http.ResponseEntity; -//import org.springframework.web.bind.annotation.GetMapping; -//import org.springframework.web.bind.annotation.RequestMapping; -//import org.springframework.web.bind.annotation.RestController; -//import reactor.core.publisher.Mono; -//import springfox.documentation.swagger.web.*; -// -//import javax.annotation.Resource; -//import java.util.List; -//import java.util.Optional; -// -///** -// * Swagger Controller -// * -// * @author zxliu -// * @date 2022-10-25 11:24 -// */ -//@RestController -//@RequestMapping("/swagger-resources") -//public class SwaggerHandler { -// -// @Resource -// private SwaggerResourcesProvider swaggerResources; -// -// @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") // 只有 @Autowired 可以实现可选注入 -// @Autowired(required = false) -// private SecurityConfiguration securityConfiguration; -// @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") // 只有 @Autowired 可以实现可选注入 -// @Autowired(required = false) -// private UiConfiguration uiConfiguration; -// -// @GetMapping("") -// public Mono>> swaggerResources() { -// return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK))); -// } -// -// @GetMapping("/configuration/security") -// public Mono> securityConfiguration() { -// return Mono.just(new ResponseEntity<>(Optional.ofNullable(securityConfiguration) -// .orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK)); -// } -// -// @GetMapping("/configuration/ui") -// public Mono> uiConfiguration() { -// return Mono.just(new ResponseEntity<>(Optional.ofNullable(uiConfiguration) -// .orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK)); -// } -// -//} +package cn.iocoder.yudao.gateway.swagger; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; +import springfox.documentation.swagger.web.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Optional; + +/** + * Swagger Controller + * + * @author zxliu + * @date 2022-10-25 11:24 + */ +@RestController +@RequestMapping("/swagger-resources") +public class SwaggerHandler { + + @Resource + private SwaggerResourcesProvider swaggerResources; + + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") // 只有 @Autowired 可以实现可选注入 + @Autowired(required = false) + private SecurityConfiguration securityConfiguration; + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") // 只有 @Autowired 可以实现可选注入 + @Autowired(required = false) + private UiConfiguration uiConfiguration; + + @GetMapping("") + public Mono>> swaggerResources() { + return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK))); + } + + @GetMapping("/configuration/security") + public Mono> securityConfiguration() { + return Mono.just(new ResponseEntity<>(Optional.ofNullable(securityConfiguration) + .orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK)); + } + + @GetMapping("/configuration/ui") + public Mono> uiConfiguration() { + return Mono.just(new ResponseEntity<>(Optional.ofNullable(uiConfiguration) + .orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK)); + } + +} diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/swagger/SwaggerProvider.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/swagger/SwaggerProvider.java index 8b1cb86a3..03aee0fbc 100644 --- a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/swagger/SwaggerProvider.java +++ b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/swagger/SwaggerProvider.java @@ -1,102 +1,102 @@ -//package cn.iocoder.yudao.gateway.swagger; -// -//import cn.hutool.core.collection.CollUtil; -//import cn.hutool.core.util.StrUtil; -//import lombok.extern.slf4j.Slf4j; -//import org.springframework.cloud.gateway.config.GatewayProperties; -//import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; -//import org.springframework.cloud.gateway.route.RouteDefinition; -//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 javax.annotation.Resource; -//import java.util.ArrayList; -//import java.util.HashSet; -//import java.util.List; -//import java.util.Set; -// -///** -// * Swagger 资源的 Provider 实现类 -// * -// * @author zxliu -// * @date 2022-10-25 11:23 -// */ -//@Component -//@Primary -//@Slf4j -//public class SwaggerProvider implements SwaggerResourcesProvider { -// -// @Resource -// private GatewayProperties gatewayProperties; -// -// /** -// * 获得 SwaggerResource 列表 -// * -// * @return SwaggerResource 列表 -// */ -// @Override -// public List get() { -// // 将 RouteDefinition 转换成 SwaggerResource -// List resources = new ArrayList<>(); -// Set serviceNames = new HashSet<>(); // 已处理的服务名,避免重复 -// gatewayProperties.getRoutes().forEach(route -> { -// // 已存在的服务,直接忽略 -// String serviceName = route.getUri().getHost(); -// if (StrUtil.isEmpty(serviceName)) { -// return; -// } -// if (!serviceNames.add(serviceName)) { -// return; -// } -// -// // 获得 Path PredicateDefinition -// String path = getRoutePath(route); -// if (path == null) { -// return; -// } -// -// // 重要:构建最终的 SwaggerResource 对象 -// resources.add(buildSwaggerResource(serviceName, path)); -// }); -// return resources; -// } -// -// private SwaggerResource buildSwaggerResource(String name, String location) { -// SwaggerResource swaggerResource = new SwaggerResource(); -// swaggerResource.setName(name); -// swaggerResource.setLocation(location); -// swaggerResource.setSwaggerVersion("2.0"); -// return swaggerResource; -// } -// -// /** -// * 获得路由的 Path -// * -// * ① 输入: -// * predicates: -// * - Path=/admin-api/system/** -// * ② 输出: -// * /admin-api/system/v2/api-docs -// * -// * @param route 路由 -// * @return 路由 -// */ -// private String getRoutePath(RouteDefinition route) { -// PredicateDefinition pathDefinition = CollUtil.findOne(route.getPredicates(), -// predicateDefinition -> "Path".equals(predicateDefinition.getName())); -// if (pathDefinition == null) { -// log.info("[get][Route({}) 没有 Path 条件,忽略接口文档]", route.getId()); -// return null; -// } -// String path = pathDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0"); -// if (StrUtil.isEmpty(path)) { -// log.info("[get][Route({}) Path 的值为空,忽略接口文档]", route.getId()); -// return null; -// } -// return path.replace("/**", "/v2/api-docs"); -// } -// -//} +package cn.iocoder.yudao.gateway.swagger; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.config.GatewayProperties; +import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; +import org.springframework.cloud.gateway.route.RouteDefinition; +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 javax.annotation.Resource; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Swagger 资源的 Provider 实现类 + * + * @author zxliu + * @since 2022-10-25 11:23 + */ +@Component +@Primary +@Slf4j +public class SwaggerProvider implements SwaggerResourcesProvider { + + @Resource + private GatewayProperties gatewayProperties; + + /** + * 获得 SwaggerResource 列表 + * + * @return SwaggerResource 列表 + */ + @Override + public List get() { + // 将 RouteDefinition 转换成 SwaggerResource + List resources = new ArrayList<>(); + Set serviceNames = new HashSet<>(); // 已处理的服务名,避免重复 + gatewayProperties.getRoutes().forEach(route -> { + // 已存在的服务,直接忽略 + String serviceName = route.getUri().getHost(); + if (StrUtil.isEmpty(serviceName)) { + return; + } + if (!serviceNames.add(serviceName)) { + return; + } + + // 获得 Path PredicateDefinition + String path = getRoutePath(route); + if (path == null) { + return; + } + + // 重要:构建最终的 SwaggerResource 对象 + resources.add(buildSwaggerResource(serviceName, path)); + }); + return resources; + } + + private SwaggerResource buildSwaggerResource(String name, String location) { + SwaggerResource swaggerResource = new SwaggerResource(); + swaggerResource.setName(name); + swaggerResource.setLocation(location); + swaggerResource.setSwaggerVersion("3.0.3"); + return swaggerResource; + } + + /** + * 获得路由的 Path + * + * ① 输入: + * predicates: + * - Path=/admin-api/system/** + * ② 输出: + * /admin-api/system/v3/api-docs + * + * @param route 路由 + * @return 路由 + */ + private String getRoutePath(RouteDefinition route) { + PredicateDefinition pathDefinition = CollUtil.findOne(route.getPredicates(), + predicateDefinition -> "Path".equals(predicateDefinition.getName())); + if (pathDefinition == null) { + log.info("[get][Route({}) 没有 Path 条件,忽略接口文档]", route.getId()); + return null; + } + String path = pathDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0"); + if (StrUtil.isEmpty(path)) { + log.info("[get][Route({}) Path 的值为空,忽略接口文档]", route.getId()); + return null; + } + return path.replace("/**", "/v3/api-docs"); + } + +} diff --git a/yudao-gateway/src/main/resources/application.yaml b/yudao-gateway/src/main/resources/application.yaml index b4be75ede..6a3a6257c 100644 --- a/yudao-gateway/src/main/resources/application.yaml +++ b/yudao-gateway/src/main/resources/application.yaml @@ -12,37 +12,37 @@ spring: predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 - Path=/admin-api/system/** filters: - - RewritePath=/admin-api/system/v2/api-docs, /v2/api-docs # 配置,保证转发到 /v2/api-docs + - RewritePath=/admin-api/system/v3/api-docs, /v3/api-docs # 配置,保证转发到 /v3/api-docs - id: system-app-api # 路由的编号 uri: grayLb://system-server predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 - Path=/app-api/system/** filters: - - RewritePath=/app-api/system/v2/api-docs, /v2/api-docs + - RewritePath=/app-api/system/v3/api-docs, /v3/api-docs - id: infra-admin-api # 路由的编号 uri: grayLb://infra-server predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 - Path=/admin-api/infra/** filters: - - RewritePath=/admin-api/infra/v2/api-docs, /v2/api-docs + - RewritePath=/admin-api/infra/v3/api-docs, /v3/api-docs - id: infra-app-api # 路由的编号 uri: grayLb://infra-server predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 - Path=/app-api/infra/** filters: - - RewritePath=/app-api/infra/v2/api-docs, /v2/api-docs + - RewritePath=/app-api/infra/v3/api-docs, /v3/api-docs - id: bpm-admin-api # 路由的编号 uri: grayLb://bpm-server predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 - Path=/admin-api/bpm/** filters: - - RewritePath=/admin-api/bpm/v2/api-docs, /v2/api-docs + - RewritePath=/admin-api/bpm/v3/api-docs, /v3/api-docs - id: report-admin-api # 路由的编号 uri: grayLb://report-server predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 - Path=/admin-api/report/** filters: - - RewritePath=/admin-api/report/v2/api-docs, /v2/api-docs + - RewritePath=/admin-api/report/v3/api-docs, /v3/api-docs - id: report-jmreport # 路由的编号(积木报表) uri: grayLb://report-server predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组