Springfox3 使用说明并整合 gateway 实现文档集中化

it2023-08-16  71

未解决的坑:

1.Basic用不了,Bearer的引用方式跟以前有点不一样 2.gateway网关统一管理 集中文档只能用SWAGGER_2(2.0),不能用OAS_30(3.0.3) 3.引入基础包的bean不能使用 BeanFactoryAware(导致不能创建多个group)替换

Springfox3配置

引入包

现在只需要一个包 springboot的,不像以前需要两个,当然可以单独引用两个也行3.0的,具体可以进入这个包里看

<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency>

注解和访问地址 变更

由之前的 @EnableSwagger2 更改为 @EnableOpenApi,当然@EnableOpenAp可以放在配置类,也可以放在启动类上,项目访问地址从2.x的 http://localhost:8088/swagger-ui.html 到 3.x的 http://localhost:8088/swagger-ui/index.html 或 http://localhost:8088/swagger-ui/

注:@EnableSwagger2在springfox3版本依然可以继续使用

DocumentationType 变更

Docket构造函数中的DocumentationType指向更改:由之前的DocumentationType.SWAGGER_2 更改为 DocumentationType.OAS_30

注:DocumentationType.SWAGGER_2在springfox3版本依然可以继续使用

@Bean public Docket createDocApi() { return new Docket(DocumentationType.OAS_30) .enable(swaggerProperties.getEnabled()) .apiInfo(buildApiInfo(swaggerProperties.getDocketConfig())) .select() .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getDocketConfig().getBasePackage())) .paths(buildPredicateSelector(swaggerProperties.getDocketConfig())) .build() .securitySchemes(Collections.singletonList(chooseAuthTypeScheme())) .securityContexts(Collections.singletonList(chooseAuthTypeContext())) ; }

断言Predicate变更

以前springfox2.x会默认引入guava 包,就像这个

<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>20.0</version> <scope>compile</scope> </dependency>

自从springfox官网github被其他老外提了issue吐槽guava落后,springfox3开始用了jdk8的Predicate,自此,springfox3只支持jdk8以上版本,这点要注意。 以下是我更新后predicate的配置:

private Predicate<String> buildPredicateSelector(SwaggerProperties.DocketConfig config){ // base-path处理 List<java.util.function.Predicate<String>> basePath = new ArrayList<>(); for (String path : config.getBasePath()) { basePath.add(PathSelectors.ant(path)); } // exclude-path处理 List<java.util.function.Predicate<String>> excludePath = new ArrayList<>(); for (String path : config.getExcludePath()) { excludePath.add(PathSelectors.ant(path)); } // 当没有配置任何path的时候,解析/.* if (config.getBasePath().isEmpty() || config.getBasePath() == null) { //return PathSelectors.regex("/.*"); return PathSelectors.any().and(excludePath.stream().reduce(each -> true, (a,b) -> a.and(b.negate()))); } //组装 base-path 和 exclude-path return basePath.stream().reduce(each -> false, Predicate::or) //each为false原因是,如果是true,有任何or,都不会走右边 .and(excludePath.stream().reduce(each -> true, (a,b) -> a.and(b.negate()))); }

以上是springfox3的变更。

gateway网关实现集中化

说明

首先gateway默认是webflux,springfox2.x是没有整合webflux的(2.10除外),18年到现在两年没更新可能导致很多人都弃坑springfox,转openApi3了(另一个非官网组织)。而现在springfox3出现了,终于不用换包了。(主要是懒) 然后gateway这个服务同样引入上述包即可,只需引入,不用像2.10分两个注解 @EnableSwagger2WebMvc 和 @EnableSwagger2WebFlux,只需引入**@EnableOpenApi**注解即可。

Nacos 实现方式

/** * 以nacos方式聚合各个服务的swagger接口文档, 直接获取nacos存活的服务 * * @author lbj * @date 2020/09/22 18:25 */ @Primary @Component @ConditionalOnProperty(prefix = "myyshop.swagger.provider", name = "type", havingValue = "nacos", matchIfMissing = true) public class NacosSwaggerResourceProvider implements SwaggerResourcesProvider { /** * swagger2默认的url后缀 */ private static final String SWAGGER2URL = "/v2/api-docs"; private static final String OAS_30_URL = "/v3/api-docs"; @Autowired private NacosDiscoveryProperties nacosDiscoveryProperties; /** * 网关应用名称 */ @Value("${spring.application.name}") private String self; @Override public List<SwaggerResource> get() { List<SwaggerResource> resources = new ArrayList<>(); String hasIpCount = "true"; String withInstances = "false"; String pageNo = "1"; String pageSize = "1000"; String httpUrlEx = "http://%s/nacos/v1/ns/catalog/services?hasIpCount=%s&withInstances=%s&pageNo=%s&pageSize=%s&serviceNameParam=&groupNameParam=%s&namespaceId=%s"; String httpUrl = String.format(httpUrlEx, nacosDiscoveryProperties.getServerAddr(), hasIpCount, withInstances, pageNo, pageSize, nacosDiscoveryProperties.getGroup(), nacosDiscoveryProperties.getNamespace()); ResponseEntity<Map> responseEntityMap = new RestTemplate().getForEntity(httpUrl, Map.class); Map responseMap = responseEntityMap.getBody(); List<Map> serviceList = (List<Map>) responseMap.get("serviceList"); Integer count = (Integer) responseMap.get("count"); serviceList.stream().map(service -> String.valueOf(service.get("name"))).distinct() .forEach(serviceName -> { String url = "/" + serviceName.toLowerCase() + SWAGGER2URL; SwaggerResource swaggerResource = new SwaggerResource(); swaggerResource.setSwaggerVersion("2.0"); if(Objects.equals(serviceName.toLowerCase(), self)){ url = OAS_30_URL; swaggerResource.setSwaggerVersion("3.0.3"); } swaggerResource.setUrl(url); swaggerResource.setName(serviceName); resources.add(swaggerResource); }); return resources; } }

Gateway RouteLocator 实现方式

/** * 以gateway方式聚合各个服务的swagger接口文档(还可以加入healthy,去逐个匹配healthy,判断是否存活,活的话加入SwaggerResource列表,否则不加入) * * @author lbj * @date 2020/09/22 18:25 */ @Primary @Component @ConditionalOnProperty(prefix = "myyshop.swagger.provider", name = "type", havingValue = "gateway") public class GatewaySwaggerResourceProvider implements SwaggerResourcesProvider { /** * swagger2默认的url后缀 */ private static final String SWAGGER2URL = "/v2/api-docs"; private static final String OAS_30_URL = "/v3/api-docs"; /** * 网关路由 */ @Autowired private RouteLocator routeLocator; @Autowired private GatewayProperties gatewayProperties; /** * 网关应用名称 */ @Value("${spring.application.name}") private String self; @Override public List<SwaggerResource> get() { List<RouteDefinition> ds = gatewayProperties.getRoutes(); List<SwaggerResource> resources = new ArrayList<>(); List<String> routeHosts = new ArrayList<>(); // 获取所有可用的host:serviceId routeLocator.getRoutes() .filter(route -> route.getUri().getHost() != null) .filter(route -> Objects.equals(route.getUri().getScheme(), "lb")) // .filter(route -> !self.equals(route.getUri().getHost())) .subscribe(route -> routeHosts.add(route.getUri().getHost())); // 记录已经添加过的server,存在同一个应用注册了多个服务在nacos上 Set<String> dealed = new HashSet<>(); routeHosts.forEach(instance -> { // 拼接url String url = "/" + instance.toLowerCase() + SWAGGER2URL; if (!dealed.contains(url)) { dealed.add(url); SwaggerResource swaggerResource = new SwaggerResource(); swaggerResource.setUrl(url); swaggerResource.setName(instance); //swaggerResource.setSwaggerVersion("3.0.3"); resources.add(swaggerResource); } }); return resources; } }
最新回复(0)