一、背景
? ? ? ? 项目开发中前后端衔接有多种工具,我们选用的是swagger,一个版本下来复盘的时候项目组成员反馈不好用,接口难找,页面也很不美观;于是寻找集成的方式将微服务多个项目集成到一起,最终选择spring cloud gateWay +?knife4j方案,因为我们网关用的是spring cloud gateWay,knife4j相当于swagger增强版。
? ? ? ??每个单体架构中引入knife4j生成接口的在线文档,采用gateWay将后端所有接口整合到统一的入口去访问,所以需要将gateWay和knife4j结合,实现各微服务的文档聚合。
二、集成步骤
? ? ? ? 1、springboot集成knife4j
? ? ? ? ? ? 引入jar包依赖:
implementation 'com.github.xiaoymin:knife4j-spring-boot-starter:2.0.9'
implementation 'io.springfox:springfox-boot-starter:3.0.0'
? ? ? ? ? ?创建SwaggerConfiguration
@Configuration
@EnableSwagger2
@EnableKnife4j
public class SwaggerConfiguration {
@Bean
public Docket groupRestApi() {
return new Docket(DocumentationType.SWAGGER_2).groupName("teamsys-service")
.select()
.apis(RequestHandlerSelectors.basePackage("com.mlz.teamsys"))
.paths(PathSelectors.any())
.build()
.apiInfo(groupApiInfo());
}
private ApiInfo groupApiInfo() {
return new ApiInfoBuilder().title("鹏云班组-系统管理").description("鹏云班组-系统管理-接口文档").version("1.1.0").build();
}
}
? 注意:之前引入swagger的的依赖需要删除,否则会引起jar包冲突
? ? ? ? 2、网关模块聚合业务模块的swagger文档
? ? ? ? ? ? 引入jar包依赖:
implementation 'com.github.xiaoymin:knife4j-spring-boot-starter:2.0.9'
? ? ? ? ? ?重写SwaggerResourcesProvider获取路由资源:
/**
* @Description: 在网关中查询路由信息,生成对应的资源信息
*
* @Author HJW
* @Date 2022/9/30
* @Version V1.0
**/
@Component
@Primary
public class MySwaggerResourceProvider implements SwaggerResourcesProvider {
/**
* RouteLocator,GatewayProperties这两个类都是springcloud提供的springbean对象直接注入即可
*/
private final RouteLocator routeLocator;
/**
* gateway配置文件
*/
private final GatewayProperties gatewayProperties;
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = new ArrayList<>();
List<String> routes = new ArrayList<>();
routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
// 从配置文件中获取并配置SwaggerResource
gatewayProperties.getRoutes().stream()
// 过滤路由
.filter(routeDefinition -> routes.contains(routeDefinition.getId()))
//循环添加,从路由的断言中获取,一般来说路由都会配置断言Path信息,这就不多说了
.forEach(route -> {
route.getPredicates().stream()
// 获取Path信息
.filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName()))
// 开始添加SwaggerResource
.forEach(predicateDefinition -> resources.add(swaggerResource(route.getId(),
predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0")
.replace("**", "v2/api-docs?group=" + route.getId()))));
});
return resources;
}
private SwaggerResource swaggerResource(String name, String location) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion("2.0");
return swaggerResource;
}
@Autowired
public MySwaggerResourceProvider(RouteLocator routeLocator, GatewayProperties gatewayProperties) {
this.routeLocator = routeLocator;
this.gatewayProperties = gatewayProperties;
}
}
? ? ? ? ? 重写swagger-resources的访问接口:
/**
* @Description: swagger 资源信息
*
* @Author HJW
* @Date 2022/9/30
* @Version V1.0
**/
@RestController
@RequestMapping("/swagger-resources")
@RequiredArgsConstructor
public class SwaggerResourceController {
private final MySwaggerResourceProvider swaggerResourceProvider;
@RequestMapping
public ResponseEntity<List<SwaggerResource>> swaggerResources() {
return new ResponseEntity<>(swaggerResourceProvider.get(), HttpStatus.OK);
}
}
? ? ? ? ?添加请求头过滤器:
@Component
public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {
private static final String HEADER_NAME = "X-Forwarded-Prefix";
private static final String 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,URI )) {
return chain.filter(exchange);
}
ServerHttpRequest newRequest = request.mutate().path(URI).header(HEADER_NAME).build();
ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
return chain.filter(newExchange);
};
}
}
? ? ? ? yml文件添加过滤器配置
spring:
cloud:
gateway:
routes:
- id: xxx-service
uri: lb://xxx-service
predicates:
- Path=/xxx/**
filters:
- SwaggerHeaderFilter
|