springcloudgateway聚合swagger文档

编程

需求背景

spring cloud搭建微服务系统,每个业务模块使用swagger开放文档接口查询,在业务网关模块提供swagger文档聚合查询接口,可以通过选择业务模块分类查看。

框架选型、版本及主要功能

  1. spring boot 2.1.6.RELEASE
  2. spring cloud Greenwich.SR3
  3. spring cloud gateway 2.1.3.RELEASE 网关组件
  4. knife4j 2.0.1 增强swagger ui样式,网关使用其starter依赖
  5. swagger bootstrap ui 1.9.6 增强swagger ui样式
  6. spring4all-swagger 1.9.0.RELEASE 配置化swagger参数,免去代码开发

模块职责划分

  1. swagger组件

    开发一个项目内的swagger-spring-boot-starter,整合swagger bootstrap ui 1.9.6和spring4all-swagger 1.9.0.RELEASE,对外提供@EnableSwagger注解服务

  2. 业务模块

    引用自定义的swagger-spring-boot-starter,同时在配置文件中添加本模块的swagger基础信息配置。

  3. 网关模块

    引用knife4j整合swagger,并开发filter、handler、config对多模块的swagger进行聚合

开发步骤示例

swagger组件

pom.xml文件依赖

<dependency>

<groupId>com.github.xiaoymin</groupId>

<artifactId>swagger-bootstrap-ui</artifactId>

<version>1.9.6</version>

</dependency>

<dependency>

<groupId>com.spring4all</groupId>

<artifactId>swagger-spring-boot-starter</artifactId>

<version>1.9.0.RELEASE</version>

</dependency>

自定义注解

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@EnableSwagger2Doc

@EnableSwaggerBootstrapUI

@Import(SwaggerCommandLineRunner.class)

public @interface EnableSwagger {

}

注意@EnableSwagger2Doc,@EnableSwaggerBootstrapUI注解,@EnableSwagger2Doc注解能将swagger配置文档化,避免业务模块再开发swagger的代码,@EnableSwaggerBootstrapUI就是改进了swagger ui界面。

指定swagger的默认访问端口

@Slf4j

@Component

public class SwaggerCommandLineRunner implements CommandLineRunner {

@Value("${server.port:8080}")

private String serverPort;

@Override

public void run(String... args) {

log.info("swagger url:http://localhost:" + serverPort + "/doc.html");

}

}

这样这个组件就集成完毕了,这个组件以多module的形式存在于项目公共组件中,使用maven引用即可。

业务模块开发

application中使用@EnableSwagger注解(自行开发的那个,不要搞错了)

@SpringBootApplication

@EnableDiscoveryClient

@MapperScan("com.hy.demo.**.mapper")

@EnableSwagger

public class DemoApplication {

public static void main(String[] args) {

ConfigurableApplicationContext ctx = SpringApplication.run(DemoApplication.class, args);

ctx.start();

}

}

配置文件加上swagger信息:

swagger:

enabled: true

title: hy demo

base-package: com.hy.demo

如此业务模块部分就完成了,非常简单,代码零侵入

网关开发

网关的开发是重头戏,里面需要集成knife4j(这个框架是swagger bootstrap ui的最终版本,最终版改了个名字,开发是同一个人),并且对请求url进行适配

pom.xml添加swagger的依赖

<dependency>

<groupId>com.github.xiaoymin</groupId>

<artifactId>knife4j-spring-boot-starter</artifactId>

<version>2.0.1</version>

</dependency>

配置文件gateway部分,对业务接口配置和swagger配置要单独设置routes,例如:

spring:

application:

name: gate

cloud:

gateway:

discovery:

locator:

#enabled: true0

enabled: false

lower-case-service-id: true

routes:

- id: demo

uri: lb://demo

predicates:

- Path=/api/json/hy/demo/**

- id: demoSwagger

uri: lb://demo

predicates:

- Path=/demo/**

filters:

- SwaggerHeaderFilter

- StripPrefix=1

我们假定业务转发的接口URL前缀定义:/api/json/hy/demo,demo为业务模块名称,业务接口对URL处理不需要加过滤器。

route id后缀为Swagger结尾,需要添加StripPrefix过滤器和自定义过滤器SwaggerHeaderFilter。

ResourceConfig开发,这个类的作用是从route信息里抽取业务模块信息,并且展示在swagger ui左上角的下拉框里

/**

* 获取SwaggerResources列表信息,即业务模块列表

* 列表数据填充在swagger ui左上角的下拉框里

* @description:

* @author: demo

* @create: 2020-02-25 17:15

**/

@Slf4j

@Component

@Primary

@AllArgsConstructor

public class SwaggerResourceConfig implements SwaggerResourcesProvider {

private static final String SWAGGER_URI = "/v2/api-docs";

private final RouteLocator routeLocator;

private final GatewayProperties gatewayProperties;

@Override

public List<SwaggerResource> get() {

List<SwaggerResource> resources = new ArrayList<>();

List<String> routes = new ArrayList<>();

// 只抽取后缀为Swagger的路由信息

routeLocator.getRoutes().filter(r -> r.getId().endsWith("Swagger")).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("/**", SWAGGER_URI))));

});

return resources;

}

private SwaggerResource swaggerResource(String name, String location) {

log.info("name:{},location:{}",name,location);

SwaggerResource swaggerResource = new SwaggerResource();

swaggerResource.setName(name);

swaggerResource.setLocation(location);

swaggerResource.setSwaggerVersion("2.0");

return swaggerResource;

}

}

示例效果如下图:

【图一】

swagger ui静态资源的处理:

/**

* @description:

* @author: demo

* @create: 2020-02-25 17:19

**/

@RestController

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("/swagger-resources/configuration/security")

public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {

return Mono.just(new ResponseEntity<>(

Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));

}

@GetMapping("/swagger-resources/configuration/ui")

public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {

return Mono.just(new ResponseEntity<>(

Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));

}

@GetMapping("/swagger-resources")

public Mono<ResponseEntity> swaggerResources() {

return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));

}

}

swagger 过滤器示例代码

/**

* @description:

* @author: demo

* @create: 2020-02-25 17:01

**/

@Component

public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {

private static final String HEADER_NAME = "X-Forwarded-Prefix";

private static final String SWAGGER_URI = "/v2/api-docs";

@Override

public GatewayFilter apply(Object config) {

return (exchange, chain) -> {

ServerHttpRequest request = exchange.getRequest();

String path = request.getURI().getPath();

if (!StringUtils.endsWithIgnoreCase(path,SWAGGER_URI)) {

return chain.filter(exchange);

}

String basePath = path.substring(0, path.lastIndexOf(SWAGGER_URI));

ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();

ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();

return chain.filter(newExchange);

};

}

}

业务过滤器修改

由于该组件是业务网关组件,肯定会有通用的过滤器,来完成token校验,身份证识别等功能,记得在这些过滤器将"/v2/api-docs"的URL放行,示例代码:

if (StringUtils.endsWithIgnoreCase(path,"/v2/api-docs")) {

return chain.filter(exchange);

}

测试验证

启动相应的注册中心、业务模块、网关模块进行验证,验证swagger文档、业务接口的处理能否同时满足。

专注Java高并发、分布式架构,更多技术干货分享与心得,请关注公众号:Java架构社区

可以扫左边二维码添加好友,邀请你加入Java架构社区微信群共同探讨技术

以上是 springcloudgateway聚合swagger文档 的全部内容, 来源链接: utcz.com/z/519226.html

回到顶部