spring cloud 整合knife4j 增强swagger
一. 介绍
Knife4j一直致力于将目前的Ui提供给更多的平台或者别的语言使用而努力,经过这么长时间的发展,Knife4j提供的轻量级聚合中间件终于诞生了,自2.0.8
版本开始,Knife4j 提供了knife4j-aggregation-spring-boot-starter
组件,该组件是一个基于Spring Boot系统的starter,他提供了以下几种能力:
- 最轻量级、最简单、最方便的聚合OpenApi规范的中间件
- 让所有的基于Spring Boot的Web体系拥有了轻松聚合OpenApi的能力
- 提供4种模式供开发者选择
- 基于本地静态JSON文件的方式聚合OpenAPI
- 基于云端HTTP接口的方式聚合
- 基于Eureka注册中心的方式聚合
- 基于Nacos注册中心的方式聚合
- 基于该starter发布了Docker镜像,跨平台与语言让开发者基于此Docker镜像轻松进行聚合OpenAPI规范
- 完美兼容所有Spring Boot版本,没有兼容性问题
- 开发者可以彻底放弃基于Zuul、Spring Cloud Gateway等复杂的聚合方式
- 兼容OpenAPI2规范以及OpenAPI3规范
二. 实际使用
1. 普通微服务引入
- 只需要引入knife4j 核心包,不需要引入ui
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-micro-spring-boot-starter</artifactId>
</dependency>
2. 网关层引入
- 网关层引入knife4j 核心 + ui 进行统一管理
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
3. 普通微服务配置
micro-cloud项目通过 micro-starter-web 统一引入配置,减少不需要的操作,请求头根据实际项目进行修改
```java /**- @ClassName SwaggerConfig
- TODO: 类文件简单描述
- @Author: 小白
- @UpdateUser: 小白
@Version: 1.0.0 */ @Configuration @AllArgsConstructor //@Profile({“!prod”}) @EnableSwagger2 @EnableConfigurationProperties(SwaggerProperty.class) public class SwaggerConfig {
private final SwaggerProperty swaggerProperties;
// 定义分隔符 private static final String splitor = “;”; @Bean public Docket createRestApi() { /**
* 这是为了我们在用 swagger 测试接口的时候添加头部信息
*/
List
pars = new ArrayList (); ParameterBuilder tokenPar = new ParameterBuilder(); tokenPar.name(“Access-Token”).description(“swagger测试用(模拟Access-Token传入)非必填 header”).modelRef(new ModelRef(“string”)).parameterType(“header”).required(false); /** * 多个的时候 就直接添加到 pars 就可以了
*/
pars.add(tokenPar.build()); return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
.paths(PathSelectors.any())
.build()
.globalOperationParameters(pars)
.enable(swaggerProperties.isEnabled())
;
}
private ApiInfo apiInfo() { return new ApiInfoBuilder()
.title(swaggerProperties.getTitle())
.description(swaggerProperties.getDescription())
.termsOfServiceUrl("")
.version(swaggerProperties.getApiVersion())
.build();
}
public static Predicate<RequestHandler> basePackage(final String basePackage) {
return input -> declaringClass(input).transform(handlerPackage(basePackage)).or(true);
}
private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
return input -> {
// 循环判断匹配
for (String strPackage : basePackage.split(splitor)) {
boolean isMatch = input.getPackage().getName().startsWith(strPackage);
if (isMatch) {
return true;
}
}
return false;
};
}
private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
return Optional.fromNullable(input.declaringClass());
}
}
- swagger 配置文件
```java
/**
* @ClassName SwaggerProperty
* TODO: 自定义swagger配置
* @Author: 小白
* @UpdateUser: 小白
* @Version: 1.0.0
*/
@Data
@ConfigurationProperties(prefix = "micro.swagger2")
public class SwaggerProperty {
/**
* 是否启用swagger,生产环境建议关闭
*/
private boolean enabled;
/**
* 文档标题
*/
private String title;
/**
* 文档描述
*/
private String description;
/**
* 客户端ID
*/
private String clientId;
/**
* 客户端密钥
*/
private String clientSecret;
/**
* 客户端授权范围
*/
private String scope;
/**
* 获取token
*/
private String accessTokenUri;
/**
* 认证地址
*/
private String userAuthorizationUri;
/**
* 文档版本
* */
private String apiVersion;
}
- 项目配置文件中,写入配置参数
micro:
swagger2:
enabled: true
title: 用户后台管理
api-version: v1
description: 用户后台管理
4. 网关层统一配置
SwaggerHandler
```java /**- @author xianrui
- @Date 2021-02-25 16:34
- @Version 1.0.0
@ https://gitee.com/xiaoym/swagger-bootstrap-ui-demo/blob/master/knife4j-spring-cloud-gateway/service-doc/src/main/java/com/xiaominfo/swagger/service/doc/handler/SwaggerHandler.java */ @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)));
}
}
- SwaggerHeaderFilter
```java
/**
* @link https://gitee.com/xiaoym/swagger-bootstrap-ui-demo/blob/master/knife4j-spring-cloud-gateway/service-doc/src/main/java/com/xiaominfo/swagger/service/doc/config/SwaggerHeaderFilter.java
* @auth xianrui
* @date 2021-02-25 16:29
*/
@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);
}
String basePath = path.substring(0, path.lastIndexOf(URI));
ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();
ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
return chain.filter(newExchange);
};
}
}
- SwaggerResourceConfig
```java /**- @Author haoxr
- @Date 2021-02-25 16:21
- @Version 1.0.0
- @ https://gitee.com/xiaoym/swagger-bootstrap-ui-demo/blob/master/knife4j-spring-cloud-gateway/service-doc/src/main/java/com/xiaominfo/swagger/service/doc/config/SwaggerResourceConfig.java */
@Slf4j @Component @Primary @AllArgsConstructor public class SwaggerResourceConfig implements SwaggerResourcesProvider {
private final RouteLocator routeLocator;
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()));
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("**", "v2/api-docs"))));
});
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;
}
} ```
5. 效果
接口文档
请求参数、响应参数指定
接口调试
离线文档导出,可选择不同格式