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: truetitle: 用户后台管理api-version: v1description: 用户后台管理
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*/@Componentpublic class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {private static final String HEADER_NAME = "X-Forwarded-Prefix";private static final String URI = "/v2/api-docs";@Overridepublic 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;@Overridepublic 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. 效果

接口文档

请求参数、响应参数指定

接口调试

离线文档导出,可选择不同格式

