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 170b1f96a..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,7 +1,6 @@ package cn.iocoder.yudao.gateway.swagger; -import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -9,55 +8,47 @@ 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.SecurityConfiguration; -import springfox.documentation.swagger.web.SecurityConfigurationBuilder; -import springfox.documentation.swagger.web.SwaggerResourcesProvider; -import springfox.documentation.swagger.web.UiConfiguration; -import springfox.documentation.swagger.web.UiConfigurationBuilder; +import springfox.documentation.swagger.web.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Optional; /** + * Swagger Controller + * * @author zxliu - * @create 2022-10-25 11:24 + * @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; - private final SwaggerResourcesProvider swaggerResources; - - - @Autowired - public SwaggerHandler(SwaggerResourcesProvider swaggerResources) { - this.swaggerResources = swaggerResources; - } - - - @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)); - } - - - @SuppressWarnings("rawtypes") @GetMapping("") - public Mono swaggerResources() { + 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 0a1c60183..5c61f312c 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,48 +1,70 @@ package cn.iocoder.yudao.gateway.swagger; -import java.util.ArrayList; -import java.util.List; -import lombok.AllArgsConstructor; +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.route.RouteLocator; +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; -/** - * @author zxliu - * @create 2022-10-25 11:23 - */ +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 -@AllArgsConstructor +@Slf4j public class SwaggerProvider implements SwaggerResourcesProvider { - private final RouteLocator routeLocator; - private final GatewayProperties gatewayProperties; - + @Resource + private GatewayProperties gatewayProperties; + /** + * 获得 SwaggerResource 列表 + * + * @return SwaggerResource 列表 + */ @Override public List get() { + // 将 RouteDefinition 转换成 SwaggerResource List resources = new ArrayList<>(); - List routes = new ArrayList<>(); - routeLocator.getRoutes().subscribe(route -> routes.add(route.getId())); - gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId())) - .forEach(route -> route.getPredicates().stream() - .filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName())) - .forEach(predicateDefinition -> resources.add(swaggerResource(route.getId(), - predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0") - .replace("**", "v2/api-docs")))) - ); + 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 swaggerResource(String name, String location) { + private SwaggerResource buildSwaggerResource(String name, String location) { SwaggerResource swaggerResource = new SwaggerResource(); swaggerResource.setName(name); swaggerResource.setLocation(location); @@ -50,4 +72,31 @@ public class SwaggerProvider implements SwaggerResourcesProvider { 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 -> predicateDefinition.getName().equals("Path")); + 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"); + } + } diff --git a/yudao-gateway/src/main/resources/application.yaml b/yudao-gateway/src/main/resources/application.yaml index 222dc29d9..42f9fa5e7 100644 --- a/yudao-gateway/src/main/resources/application.yaml +++ b/yudao-gateway/src/main/resources/application.yaml @@ -10,9 +10,9 @@ spring: - id: system-admin-api # 路由的编号 uri: grayLb://system-server predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组 - - Path=/admin-api/system/**,/captcha/** + - Path=/admin-api/system/** filters: - - RewritePath=/admin-api/system/v2/api-docs, /v2/api-docs + - RewritePath=/admin-api/system/v2/api-docs, /v2/api-docs # 配置,保证转发到 /v2/api-docs - id: system-app-api # 路由的编号 uri: grayLb://system-server predicates: # 断言,作为路由的匹配条件,对应 RouteDefinition 数组