基于老版本,实现 Spring Cloud Gateway 文档

pull/25/head
YunaiV 2023-03-04 15:40:50 +08:00
parent 59c6963f7c
commit ec280224a8
5 changed files with 165 additions and 199 deletions

View File

@ -57,8 +57,9 @@
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webflux-ui</artifactId>
<groupId>com.github.xiaoymin</groupId> <!-- 接口文档 -->
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<!-- RPC 远程调用相关 -->

View File

@ -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<GroupedOpenApi> apis(RouteDefinitionLocator locator) {
List<GroupedOpenApi> groups = new ArrayList<>();
List<RouteDefinition> 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;
}
}

View File

@ -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<ResponseEntity<List<SwaggerResource>>> swaggerResources() {
// return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
// }
//
// @GetMapping("/configuration/security")
// public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
// return Mono.just(new ResponseEntity<>(Optional.ofNullable(securityConfiguration)
// .orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
// }
//
// @GetMapping("/configuration/ui")
// public Mono<ResponseEntity<UiConfiguration>> 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<ResponseEntity<List<SwaggerResource>>> swaggerResources() {
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
}
@GetMapping("/configuration/security")
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
return Mono.just(new ResponseEntity<>(Optional.ofNullable(securityConfiguration)
.orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
}
@GetMapping("/configuration/ui")
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
return Mono.just(new ResponseEntity<>(Optional.ofNullable(uiConfiguration)
.orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
}
}

View File

@ -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<SwaggerResource> get() {
// // 将 RouteDefinition 转换成 SwaggerResource
// List<SwaggerResource> resources = new ArrayList<>();
// Set<String> 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<SwaggerResource> get() {
// 将 RouteDefinition 转换成 SwaggerResource
List<SwaggerResource> resources = new ArrayList<>();
Set<String> 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");
}
}

View File

@ -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 数组