在使用SpringCloud搭建分布式应用的过程中,我们需要暴露每个微服务的Swagger接口文档,方便开发交互。为了避免暴露内部服务,我们希望能够将所有微服务的接口文档聚合起来。这样所有开发人员只需要访问统一的Swagger界面即可。

Swagger的接口文档Api和页面

Swagger本身提供一个单页面的接口文档,所有数据通过和springfox.documentation.swagger.web.ApiResponseController交互获得。首先通过"/swagger-resources"获取swagger资源信息,得到的响应结果如下:

[
	{
		name: "default",
		url:"/v2/api-docs",
		swaggerVersion:"2.0",
		location:"/v2/api-docs"
	}
]

可以看出,swagger资源信息是一个个接口组构成的数组,每个接口组包含一些属性描述这个接口组,其中name是swagger生成的接口组的组名。如图所示。

url代表swagger接口组的信息获取地址,例子中的swagger接口组default的信息可以通过localhost:8081/v2/api-docs获取。

我们要聚合不同微服务接口组的swagger文档,需要在网关处获取所有应用的swagger资源信息。所以我们需要在网关处实现"/swagger-resources"接口,使得通过这个接口可以获取所有我们需要展示的swagger文档资源。

聚合Swagger资源

首先,在网关处引入swagger相关依赖。

		<!--接口文档-->
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>${swagger.fox.version}</version>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>${swagger.fox.version}</version>
		</dependency>

实现一个获取其他所有应用swagger资源的SwaggerResourceProvider,代码如下:


import lombok.AllArgsConstructor;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import com.wangccloud.cloud.common.core.config.FilterIgnorePropertiesConfig;

import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author wangc
 * 聚合接口文档注册
 */
@Component
@Primary
@AllArgsConstructor
public class SwaggerProvider implements SwaggerResourcesProvider {
	public static final String API_URI = "/v2/api-docs";
	private final RouteDefinitionRepository routeDefinitionRepository;
	private final FilterIgnorePropertiesConfig filterIgnorePropertiesConfig;


	@Override
	public List<SwaggerResource> get() {
		List<SwaggerResource> resources = new ArrayList<>();
		List<RouteDefinition> routes = new ArrayList<>();
		routeDefinitionRepository.getRouteDefinitions().subscribe(route -> routes.add(route));
		routes.forEach(routeDefinition -> routeDefinition.getPredicates().stream()
			    //Path和名字一致
				.filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName()))
				.filter(predicateDefinition -> !filterIgnorePropertiesConfig.getSwaggerProviders().contains(routeDefinition.getId()))
				.forEach(predicateDefinition -> resources.add(swaggerResource(routeDefinition.getId(),
						predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0")
								.replace("/**", API_URI)))));
		return resources.stream().sorted(Comparator.comparing(SwaggerResource::getName))
				.collect(Collectors.toList());
	}

	private SwaggerResource swaggerResource(String name, String location) {
		SwaggerResource swaggerResource = new SwaggerResource();
		swaggerResource.setName(name);
		swaggerResource.setLocation(location);
		swaggerResource.setSwaggerVersion("2.0");
		return swaggerResource;
	}
}

实现/sweagger-resources下的三个接口,代码如下:

/**
     * swagger聚合接口,三个接口都是swagger-ui.html需要访问的接口
     *
     * @author wangc
     * @date 2019.11.10
     */
    @RestController
    @RequestMapping("/swagger-resources")
    public class SwaggerResourceController {
        private SwaggerProvider swaggerProvider;
    
        @Autowired
        public SwaggerResourceController(SwaggerProvider swaggerProvider) {
            this.swaggerProvider = swaggerProvider;
        }
    
        @RequestMapping(value = "/configuration/security")
        public ResponseEntity<SecurityConfiguration> securityConfiguration() {
            return new ResponseEntity<>(SecurityConfigurationBuilder.builder().build(), HttpStatus.OK);
        }
    
        @RequestMapping(value = "/configuration/ui")
        public ResponseEntity<UiConfiguration> uiConfiguration() {
            return new ResponseEntity<>(UiConfigurationBuilder.builder().build(), HttpStatus.OK);
        }
    
        @RequestMapping
        public ResponseEntity<List<SwaggerResource>> swaggerResources() {
            return new ResponseEntity<>(swaggerProvider.get(), HttpStatus.OK);
        }
    }

访问聚合Swagger页面

此时,即可通过网关地址http://gateway/swagger-ui.html访问到所有的swagger接口文档资源。通过切换箭头处的接口组即可查看不同应用的swagger接口文档。