微服务gateway聚合swagger文档解决
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了微服务gateway聚合swagger文档解决,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含8608字,纯文字阅读大概需要13分钟。
内容图文
gateway网关聚合swagger2文档,由于gateway网关需要排除spring-web依赖,使用的是webFlux,故需要对swagger做一些配置
如下在对应的地方排除web依赖:
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
增加swagger依赖:这个依赖包括了ui和swagger
<!--knife4j版本的swagger-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.4</version>
</dependency>
微服务通用模块中增加自定义注册swagger模块文档: 只有当配置了swagger扫描的服务会自动生成文档
package com.wm.blog_config.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.bind.BindResult;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
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.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.Properties;
/**
* 文档配置
*/
@Configuration
@ConditionalOnProperty(name = "swagger.basepackage")
@EnableSwagger2
public class Knife4jConfig implements EnvironmentAware, WebMvcConfigurer {
private String basePackage;
private String createName;
private String serviceName;
private String description;
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
//.title("swagger-bootstrap-ui-demo RESTful APIs")
.description(this.description)
.termsOfServiceUrl("http://www.xx.com/")
.contact(this.createName)
.version("2.0")
.build())
//分组名称
.groupName(this.serviceName)
.select()
//这里指定Controller扫描包路径,从配置文件中读取
.apis(RequestHandlerSelectors.basePackage(this.basePackage))
.paths(PathSelectors.any())
.build();
}
@Override
public void setEnvironment(Environment environment) {
Iterable<ConfigurationPropertySource> sources = ConfigurationPropertySources.get(environment);
Binder binder = new Binder(sources);
BindResult<Properties> bindResult = binder.bind("swagger", Properties.class);
Properties properties= bindResult.get();
this.basePackage = properties.getProperty("basepackage");
this.createName = properties.getProperty("service.developer");
this.serviceName = properties.getProperty("service.name");
this.description = properties.getProperty("service.description");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars*").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
在网关服务中增加转发处理逻辑:
package com.wm.blog_gateway.config.swagger;
import com.alibaba.fastjson.JSONObject;
import com.wm.blog_common.entity.TRoute;
import com.wm.blog_common.util.StringUtil;
import com.wm.blog_gateway.dao.TRouteDAO;
import com.wm.blog_gateway.vo.RoutePredicateVo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteLocator;
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 java.util.*;
/**
*
*/
@Slf4j
@Component
@Primary
@AllArgsConstructor
public class SwaggerResourceConfig implements SwaggerResourcesProvider {
@Autowired
private ApiDocConfig apiDocConfig;
@Autowired
private RouteLocator routeLocator;
@Autowired
private TRouteDAO tRouteDAO;
/**
* 当请求文档服务时会调用这个接口,这里扩展我们转发逻辑和定义的文档名称
* @return
*/
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = new ArrayList<>();
List<String> routes = new ArrayList<>();
// 取出gateway的route
routeLocator.getRoutes().subscribe(route -> {
// 根据文档提供者过滤
if (apiDocConfig.getProviders().contains(route.getId()))
routes.add(route.getId());
});
// 结合配置的route-路径(Path),和route过滤,只获取有效的route节点
//查询数据库中所有的路由信息
List<TRoute> routeList = Optional
.ofNullable(tRouteDAO.list())
.orElse(Collections.emptyList());
if (CollectionUtils.isNotEmpty(routeList)) {
for (TRoute route : routeList) {
if (routes.contains(route.getRouteId())) {
if(StringUtil.isNotEmpty(route.getPredicates())){
List<RoutePredicateVo> routePredicateVoList = JSONObject.parseArray(route.getPredicates(), RoutePredicateVo.class);
try {
if (CollectionUtils.isNotEmpty(routePredicateVoList)) {
String genKey;
RoutePredicateVo routePredicateVo = routePredicateVoList.stream().filter(routePredicate -> routePredicate.getArgs().containsKey(NameUtils.GENERATED_NAME_PREFIX + "0")).findFirst().orElse(null);
if (routePredicateVo != null) {
genKey = routePredicateVo.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", "/v2/api-docs?group=blog_admin");
resources.add(swaggerResource(route.getRouteId(), genKey,"2.0"));
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
}
}
return resources;
}
private SwaggerResource swaggerResource(String name, String location, String version) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion(version);
return swaggerResource;
}
}
由于再gateway中不能使用@EnableSwagger等注解(因为它默认是spring mvc),故需要我们自定义给定访问controller,如下
package com.wm.blog_gateway.controller;
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 java.util.Optional;
/**
* 因为Gateway里没有配置SwaggerConfig,而运行Swagger-ui又需要依赖一些接口 ,同时使用gateway后(用到了webFlux排除掉了web),不能引入@EnableSwagger等注解,故自定义swagger的接口
* 因为Swagger暂不支持webflux项目,所以Gateway里不能配置SwaggerConfig
*/
@RestController
@RequestMapping("/swagger-resources")
public class SwaggerHandler {
@Autowired(required = false)
private SecurityConfiguration securityConfiguration;
@Autowired(required = false)
private UiConfiguration uiConfiguration;
private final SwaggerResourcesProvider swaggerResources;
@Autowired
public SwaggerHandler(SwaggerResourcesProvider swaggerResources) {
this.swaggerResources = swaggerResources;
}
@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));
}
@GetMapping("")
public Mono<ResponseEntity> swaggerResources() {
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
}
}
我的动态网关是配置在数据库中的:
在每个文档服务中配置,请求的路径:这是自定义swagger拉取接口的路径,默认是/v2/api-docs
springfox:
documentation:
swagger:
v2:
path: /blog/v2/api-docs
原因是swagger会调用如下的接口(swagger源码):
可以看到,是会优先读取你自定义的配置路径的,如果没有则默认它自己的路径:
我们测试下文档路径
ui页面如下
这篇博客不是网站的解决方案,只是指出关键点,具体可以查看我的项目地址,分支是dev-nacos
https://gitee.com/banjuanliunian/mock_blog
有问题欢迎指出
内容总结
以上是互联网集市为您收集整理的微服务gateway聚合swagger文档解决全部内容,希望文章能够帮你解决微服务gateway聚合swagger文档解决所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。