文章目录
- 前言
- 一、简介
- 二、版本参考
- 三、基本使用
- 1. 导入相关依赖
- 2. 比对效果
- 3. 增强特性应用
- 四、Spring-Cloud 整合
- 1. 项目准备
- 2. 实现步骤
- 2.1 依赖引入
- 2.2 编写配置类
- 2.2.1基础信息配置
- 2.2.2 配置接口信息
- 2.2.3 安全认证配置
- 2.3 常用注解的使用
- 2.3.1 @Api
- 2.3.2 @ApiOperation
- 2.3.3 @ApiModel
- 2.3.4 @ApiModelProperty
- 2.4 网关整合
- 2.5 项目下载
- 五、拓展
- 1. 文件导入导出相关
- 六、可能会遇到的问题
前言
之前有写过 swagger
怎么使用的教程,但是现在很多项目用的接口文档其实是 Knife4j
,Knife4j
它是对 swagger
在线接口文档的一个增强,按照官网的话说就是给 swagger
做了一个更好看皮肤的同时加了一些新的功能,本章内容我会向大家介绍在项目中如整合 knife4j
以及一些使用的细节。
上篇:Swagger-的使用(详细教程)
如果你之前没有接使用过 swagger
的话,建议先看下上篇博客。
一、简介
官方文档:https://doc.xiaominfo.com/docs/quick-start
开源地址:https://gitee.com/xiaoym/knife4j
关于 Knife4j
的介绍官方文档其实解释得很清楚了,我就简单 copy 一下了。
Knife4j
的前身是 swagger-bootstrap-ui
,前身 swagger-bootstrap-ui
是一个纯 swagger-ui
的 ui
皮肤项目。
最开始只是一个增强版本的 swagger
的前端 ui
,但是随着项目的发展,面对越来越多的个性化需求,不得不编写后端 Java
代码以满足新的需求。最后项目更名为 Knife4j
是希望它能像一把匕首一样小巧,轻量,并且功能强悍,更名也是希望把它做成一个为 Swagger
接口文档服务的通用性解决方案,不仅仅只是专注于前端 ui
。
Knife4j 由国人程序员萧明于 2017 年开源,距今为止 Star
数已经超过了 6.1k
了。
我们可以多关注下官方文档中的 增强特性
这里详细介绍了 Knife4j
的一些特性功能,很多都是用得上的。
接口文档展示:
Knife4j 采用了 Vue + And Design Vue 组件进行重写,页面大体长这样。
对比 swagger
生成的接口文档,Knife4j
生成的接口文档就让人看起来更舒服一点。
并且支持导出离线文档
二、版本参考
knife4j 目前主要支持以 Java 开发为主,并且支持 Spring MVC、Spring Boot、Spring Cloud 框架的集成使用。
Knife4j
的版本说明:
版本 | 说明 |
---|---|
1.9.6 | 蓝色皮肤风格,开始更名,增加更多后端模块 |
2.0~2.0.5 | Ui重写,底层依赖的 springfox 框架版本是 2.9.2 |
2.0.6~2.0.9 | 底层 springfox 框架版本升级知 2.10.5 ,OpenAPI 规范是 v2 |
3.0~3.0.3 | 底层依赖 springfox 框架版本升级至 3.0.3 , OpenAPI 规范是v3 |
4.0~ | 4.0 重要版本,提供 OpenAPI2 和 OpenAPI3 两种规范供开发者自行选择,主版本统一 |
Knife4j
的依赖引入要和 Spring-boot
版本相匹配,所以得首先确保你项目中所使用的 Spring-boot
版本,以下是一些常见的 Spring-boot
版本及其对应的 Knife4j
版本兼容推荐:
Spring Boot版本 | Knife4j Swagger2规范 | Knife4j OpenAPI3规范 |
---|---|---|
1.5.x~2.0.0 | <Knife4j 2.0.0 | >=Knife4j 4.0.0 |
2.0~2.2 | Knife4j 2.0.0 ~ 2.0.6 | >=Knife4j 4.0.0 |
2.2.x~2.4.0 | Knife4j 2.0.6 ~ 2.0.9 | >=Knife4j 4.0.0 |
2.4.0~2.7.x | >=Knife4j 4.0.0 | >=Knife4j 4.0.0 |
>= 3.0 | >=Knife4j 4.0.0 | >=Knife4j 4.0.0 |
如果你不考虑使用 Knife4
j提供的服务端增强功能,引入 Knife4j
的 纯 Ui 版本
没有任何限制,只需要考虑不同的规范即可。
规范说明:
针对 Swagger2 规范和 OpenAPI3 规范的说明:
在Spring Boot框架中,Knife4j 对于服务端将 Spring 的开放接口解析成 Swagger2 或者 OpenAPI3 规范的框架,也是依赖的第三方框架组件。说明如下:
- Swagger2 规范:依赖 Springfox 项目,该项目目前几乎处于停更状态,但很多老项目依然使用的是该规范,所以 Knife4j 在更新前端 Ui 的同时也继续保持了兼容
- OpenAPI3 规范:依赖 Springdoc 项目,更新发版频率非常快,建议开发者尽快迁移过来使用 OpenAPI3 规范,Knife4j后面的重心也会在这里。
ps:不过 Knife4j
的 4.0.0
版本在 Maven
上我是没有看到也不知道为什么 T.T ~~。
三、基本使用
1. 导入相关依赖
上面说到了 Knife4j
的依赖引入要兼容 Spring-boot
的版本,除此之外,有些低版本的 Knife4j
还需要保留 swagger
的相关依赖,并且 Knife4j
的版本要和 springfox
的版本相兼容,但是有些高版本的 Knife4j
是不需要引入 swagger
相关的依赖的,例如 3.0.3
版本。
比如说我的项目(Swagger-的使用(详细教程) - 文章中搭建的 Spring-Boot
项目)中 Spring-Boot
的版本是 2.1.4.RELEASE
, springfox
的版本是 2.9.2
,所以我要引入的 Knife4j
的版本应该在 2.0~2.0.5
之间,并且还要保留 swagger
的相关依赖。
所以我引入了 2.0.5
版本的 Knife4j
,比如:
<!-- knife4j -->
<!-- http://127.0.0.1:8080/doc.html -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.5</version>
</dependency>
2. 比对效果
我在 Swagger-的使用(详细教程) 这篇博客中提供的项目中引入这个依赖,Knife4j
的整合就基本完成了,可以看下效果:
swagger
接口文档默认地址:http://localhost:8080/swagger-ui.html#
Knife4j
接口文档默认地址:http://127.0.0.1:8080/doc.html
原 swagger 接口文档
Knife4j 接口文档
3. 增强特性应用
关于 Knife4j
的增强特性,我们可以参考官方文档来,比如说这个访问页面加权控制
按照官方的文档就是在配置文件中添加:
knife4j:
# 开启增强配置
enable: true
# 开启Swagger的Basic认证功能,默认是false
basic:
enable: true
# Basic认证用户名
username: test
# Basic认证密码
password: 123
这样的配置就行了,复制这个配置,然后重启服务,打开 Knife4j
效果如下:
PS:这些增强特性大多都是要 Knife4j 2.0.7
版本之后才能使用的,如果要使用这些功能,可能你还得升级 Knife4j
、springfox
甚至可能要升级 spring-boot
的版本,比如我刚刚就升级了下这些框架的版本才起作用的。
四、Spring-Cloud 整合
1. 项目准备
之前是使用 Spring-boot 对 knife4j
进行整合,现在的项目普遍是微服务化的,而且在 Spring-cloud
整合 knife4j
的时候有些配置是需要注意的,一不小心就会踩坑,所以我重新搭建了一个 Spring-cloud-alibaba
的项目来整合 knife4j
作为示范仅供大家参考。
该项目只有一个网关、两个服务、和一个公共的模块,甚至连数据库都不需要连接,就很简单的 spring-cloud
项目,并且写了个 说明文档
,帮助有需要的可以顺利的运行起来。
每个服务都写了四个接口用于接口测试:
------------------- 项目下载 -------------------
链接:百度网盘
提取码:hk94
-----------------------------------------------
2. 实现步骤
2.1 依赖引入
这里我就将 Knife4j
整合到 common-core
这个模块中作为示范。
因为我搭建的这个 Spring-Cloud
它的 Spring-Boot
的版本是 2.5.2
,所以我选择使用 Knife4j - 3.0.3
版本,在 pom.xml (common-core)
中引入依赖:
<!-- knife4j -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
并且不需要引入 Swagger
相关的依赖。
这个时候 Knife4j
在线文档基本就整合进来了,比如我将项目跑起来之后,打开 system
服务的 Knife4j 文档
是这样的:
访问: http://ip:port/doc.html
可以看到和 swagger
一样,Knife4j
也有基本信息、接口信息和组这几类信息,同时多了文档管理、接口统计等信息。
值得一提的是在这里有个 分组 Url :/v3/api-docs
,Knife4j
接口文档中的接口信息数据都是来源于这个接口,可以 http://ip:port/v3/api-docs
看到接口信息的 json
数据:
2.2 编写配置类
虽然说引入 Knife4j
的依赖之后,就能直接打开接口文档,但是有些信息还是需要通过配置类去配置的,比如基本信息、接口扫描规则等等。Knife4j
的配置大体和 swagger
一致,因为它底层就是 swagger
,所以以下配置类的编写大致可以参考 Swagger-的使用(详细教程)。
在 config
目录下新建 SwaggerConfig
类:
编写代码如下:
@Configuration
@EnableSwagger2 //开启 Swagger2
@EnableKnife4j //开启 knife4j,可以不写
@EnableAutoConfiguration
@ConditionalOnProperty(name = "swagger.enable", matchIfMissing = true)
public class SwaggerConfig {
}
虽然编写了配置类,但是这个配置类并不一定生效,服务启动的时候还是会采用 Knife4j
默认的配置,怎么才能让 Knife4j
采取你编写的配置类呢?可以写一个注解指定容器加载你写的配置类,添加在启动类上:
注解代码如下:
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({ SwaggerConfig.class })
public @interface EnableCustomSwagger {
}
2.2.1基础信息配置
和 swagger
一样,通过 docket
来配置文档的基本信息,基本信息设置在 ApiInfo
这个对象中。
ApiInfo 中默认的基本设置:
- title:Api Documentation
- description:Api Documentation
- version:1.0
- termsOfServiceUrl:urn:tos
- contact:无
- license:Apache 2.0
- licenseUrl:http://www.apache.org/licenses/LICENSE-2.0
SwaggerConfig.java
配置文件添加以下内容:
@Bean
public Docket docket() {
// 创建一个 swagger 的 bean 实例
return new Docket(DocumentationType.SWAGGER_2)
// 配置基本信息
.apiInfo(apiInfo())
;
}
/**
* 基本信息设置
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
// 标题
.title("多加辣-接口文档")
// 描述
.description("众里寻他千百度,慕然回首那人却在灯火阑珊处")
// 服务条款链接
.termsOfServiceUrl("https://www.baidu.com")
// 许可证
.license("swagger-的使用(详细教程)")
// 许可证链接
.licenseUrl("https://blog.csdn.net/xhmico/article/details/125353535")
// 联系我
.contact(new Contact(
"米大傻",
"https://blog.csdn.net/xhmico?type=blog",
"mico8080@163.com"))
// 版本
.version("1.0")
.build();
}
当然这些基本信息的数据你也可以放在配置文件中,重启服务查看:
可以看到基本信息已经是按照配置类配置所展示的。
2.2.2 配置接口信息
默认情况下,Knife4j
是会展示所有的接口信息的,包括最基础的 basic-error
相关的接口,而我编写的接口仅仅只是 test-controller
相关的,所以需要将那些与业务无关的接口过滤掉,可这样配置:
@Bean
public Docket docket() {
// 创建一个 swagger 的 bean 实例
return new Docket(DocumentationType.SWAGGER_2)
// 配置基本信息
.apiInfo(apiInfo())
// 配置接口信息,设置扫描接口
.select()
/*
* RequestHandlerSelectors
* .any() // 扫描全部的接口,默认
* .none() // 全部不扫描
* .basePackage("com.mike.server") // 扫描指定包下的接口,最为常用
* .withClassAnnotation(RestController.class) // 扫描带有指定注解的类下所有接口
* .withMethodAnnotation(PostMapping.class) // 扫描带有只当注解的方法接口
*/
// 此包路径下的类,才生成接口文档
.apis(RequestHandlerSelectors.basePackage("com.mike.server"))
// 加了 RestController 注解的类,才生成接口文档
.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
// 加了 ApiOperation 注解的方法,才生成接口文档
//.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) // @ApiOperation:swagger 常用注解,用户标注方法描述
/*
* PathSelectors
* .any() // 满足条件的路径,该断言总为true
* .none() // 不满足条件的路径,该断言总为false(可用于生成环境屏蔽 swagger)
* .ant("/user/**") // 满足字符串表达式路径
* .regex("") // 符合正则的路径
*/
.paths(PathSelectors.any())
.build();
}
因为这个配置比较灵活,可以有很多种方法实现,能达成目标即可,重启项目测试:
可以看到只剩下自己写的接口信息了。
2.2.3 安全认证配置
通常情况下我们的接口是需要添加 token
、Authorization
这样的请求头,这些请求头中起到安全认证的作用,我们现在是没法通过接口文档调接口时添加请求头
添加以下配置:
/**
* 安全模式,这里指定token通过Authorization头请求头传递
*/
private List<SecurityScheme> securitySchemes() {
List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
apiKeyList.add(new ApiKey("Authorization", "Authorization", "header"));
return apiKeyList;
}
/**
* 安全上下文
*/
private List<SecurityContext> securityContexts() {
List<SecurityContext> securityContexts = new ArrayList<>();
securityContexts.add(
SecurityContext.builder()
.securityReferences(defaultAuth())
.operationSelector(o -> o.requestMappingPattern().matches("/.*"))
.build());
return securityContexts;
}
/**
* 默认的全局鉴权策略
*/
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
List<SecurityReference> securityReferences = new ArrayList<>();
securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
return securityReferences;
}
修改 docket()
方法:
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.mike.server"))
.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
.paths(PathSelectors.any())
.build()
// 安全模式
.securitySchemes(securitySchemes())
// 安全上下文
.securityContexts(securityContexts())
.pathMapping("/");
}
重启项目测试:
现在就能为接口添加请求头了。
2.3 常用注解的使用
2.3.1 @Api
该注解用在请求的类上,表示对类的说明。
相关属性:
tags
:说明该类的作用,可以在前台界面上看到的注解- value:该参数无意义,在UI界面上看不到,不需要配置
用法:
@Api(tags = "【测试-方法】")
public class TestController {
...
}
例如:
名称由 test-controller
改为 测试-方法
。
2.3.2 @ApiOperation
该注解用来对某个方法/接口进行描述。
该注解的使用详情可参见博客: Swagger @ApiOperation 注解详解
用法:
@GetMapping("/get/{id}")
@ApiOperation(value = "get-测试方法")
public Result<TestDto> testGet(@PathVariable("id") Long id) {
...
}
例如:
2.3.3 @ApiModel
该注解是作用于类上面的,是用来描述类的一些基本信息的。
相关属性:
value
:提供类的一个备用名,如果不设置,默认情况下将使用 class 类的名称description
:对于类,提供一个详细的描述信息- parent:这个属性用于描述的是类的一些父类信息
- discriminator:这个属性解释起来比较麻烦,因为这个类主要体现在断言当中
- subTypes:可以通过这个属性,指定我们想要使用的子类
用法:
@Data
@ApiModel(value = "TestDto", description = "测试dto")
public class TestDto {
...
}
例如:
2.3.4 @ApiModelProperty
它的作用是添加和操作属性模块的数据。
该注解的使用详情可参见博客: @ApiModelProperty注解的用法
用法:
@Data
@ApiModel(value = "TestDto", description = "测试dto")
public class TestDto {
@ApiModelProperty(value = "名称")
private String name;
@ApiModelProperty(value = "值")
private String value;
}
例如:
2.4 网关整合
现在接口文档是能够打开了,但是一个服务对于一个接口文档,在 Spring-Cloud
中,我们可以将每个服务的接口文档全部都整合到 Gateway
中,也就是说我们只要从 Gateway
中打开接口文档就能很方便的切换查看各服务的接口文档,例如:
需要聚合各个服务的 swagger
接口,代码如下:
SwaggerProvider.java
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.config.ResourceHandlerRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import java.util.ArrayList;
import java.util.List;
/**
* 聚合系统接口
*
* @author system
*/
@Component
@Slf4j
@Primary
public class SwaggerProvider implements SwaggerResourcesProvider, WebFluxConfigurer {
/**
* Swagger2默认的url后缀
*/
public static final String SWAGGER2URL = "/v2/api-docs";
/**
* 网关路由
*/
@Autowired
private RouteLocator routeLocator;
@Autowired
private GatewayProperties gatewayProperties;
/**
* 聚合其他服务接口
*
* 注意:
* 在 Gateway 中聚合 swagger,需要在每一个路由配置中添加 filters-StripPrefix 的配置,这是为了在转发之前剔除路径的前缀
* 比如:
* - id: mike_user
* uri: lb://mike-server-user
* predicates:
* - Path=/user/**
* filters:
* - StripPrefix=1
*
* StripPrefix=1 就剔除了 /user
*
* 其次是如果在 SwaggerConfig 中有配置 groupName,则需要修改 SWAGGER2URL = "/v2/api-docs"
* 比如:
* 设置 .groupName("mike")
* 则改为 SWAGGER2URL = "/v2/api-docs?group=mike"
*/
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resourceList = new ArrayList<>();
List<String> routes = new ArrayList<>();
// 获取网关中配置的 route
routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
gatewayProperties.getRoutes().stream()
.filter(routeDefinition -> routes
.contains(routeDefinition.getId()))
.forEach(routeDefinition -> routeDefinition.getPredicates().stream()
.filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName()))
.forEach(predicateDefinition -> resourceList
.add(swaggerResource(routeDefinition.getId(), predicateDefinition.getArgs()
.get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", SWAGGER2URL)))));
return resourceList;
}
private SwaggerResource swaggerResource(String name, String location) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion("2.0");
return swaggerResource;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
/* swagger-ui 地址 */
registry.addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
}
}
SwaggerHandler.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.*;
import java.util.Optional;
@RestController
@RequestMapping("/swagger-resources")
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("/configuration/security")
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()),
HttpStatus.OK));
}
@GetMapping("/configuration/ui")
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
}
@SuppressWarnings("rawtypes")
@GetMapping("")
public Mono<ResponseEntity> swaggerResources() {
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
}
}
重启服务即可:
PS:如果你的网关中有一些安全认证上判断,还得将文档相关的接口 /v2/api-docs
添加至白名单,要不然接口文档可能会报错,例如:
#自定义配置
custom:
whiteList:
- '/*/v2/api-docs'
2.5 项目下载
------------------- 项目下载 -------------------
链接:百度网盘
提取码:400m
-----------------------------------------------
五、拓展
1. 文件导入导出相关
有关上传文件相关的接口,如果想要通过 Knife4j
选择文件
需要在方法上添加 @ApiImplicitParam(name = "file", value = "文件", dataTypeClass = MultipartFile.class, required = true)
这样一段代码即可,例如:
@ApiOperation(value = "示例:导入-方式一")
@PostMapping("/importDate")
@ApiImplicitParam(name = "file", value = "文件", dataTypeClass = MultipartFile.class, required = true)
public ResponseBean importDate(@RequestPart("file") MultipartFile file) {
testService.importDate(file);
return ResponseBean.success();
}
有关下载或者是导出文件相关的接口,如果想要通过 Knife4j
下载文件
需要在相关的接口上将 @ApiOperation
注解的 produces
属性设置为 application/octet-stream
,例如:
@GetMapping("/export")
@ApiOperation(value = "示例:导出-方式一", produces = "application/octet-stream")
public ResponseBean export(@RequestParam(value = "loginName", required = false) @ApiParam(value = "登录名", required = false) String loginName) {
testService.export(loginName);
return ResponseBean.success();
}
六、可能会遇到的问题
1. 因兼容性问题引起项目启动失败
简单来说就是版本冲突了,可能是 Knife4j
和 swagger
的版本相冲突,或者是和 spring-boot
的版本相冲突。
解决方法:
根据 Knife4j
的官方文档引入相适配的依赖版本。
2. 配置增强特性不起作用
这些增强特性大多都是要 Knife4j 2.0.7
版本之后才能使用的,如果要使用这些功能,需要引入更高版本的 Knife4j
依赖,同时这也可能会出现版本冲突。
3. Spring-Boot 2.6 和 springfox 不兼容问题
这个情况我其实没有遇到过,要是你的项目 Spring-Boot
版本在 2.6.0
以上,可以在 SwaggerConfig
类中添加以下这段代码看是否能解决你的问题:
/**
* 解决springboot2.6 和springfox不兼容问题
*/
@Bean
@SuppressWarnings("all")
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
}
return bean;
}
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
List<T> copy = mappings.stream()
.filter(mapping -> mapping.getPatternParser() == null)
.collect(Collectors.toList());
mappings.clear();
mappings.addAll(copy);
}
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
try {
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
field.setAccessible(true);
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
};
}
4. 配置类不起作用
虽然编写了配置类,但是这个配置类并不一定生效,服务启动的时候还是会采用 Knife4j
默认的配置,怎么才能让 Knife4j
采取你编写的配置类呢?可以写一个注解指定容器加载你写的配置类,添加在启动类上:
注解代码如下:
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({ SwaggerConfig.class })
public @interface EnableCustomSwagger {
}
然后重启服务。
5. 网关接口文档异常
这个出现的可能性比较多,我就例举两个我遇到过的:
首先是在网关配置文件中的路由配置中,没有添加 filters-StripPrefix
的配置,例如:
- id: mike_user
uri: lb://mike-server-user
predicates:
- Path=/user/**
filters:
- StripPrefix=1
或者是你在 SwaggerConfig.java
配置类中配置了 groupName
,倘如你配置的组名为 mike
,那么你应该在 SwaggerProvider.java
文件中将 SWAGGER2URL
的值改为:"/v2/api-docs?group=mike"
,例如:
@Component
@Slf4j
@Primary
public class SwaggerProvider implements SwaggerResourcesProvider, WebFluxConfigurer {
/**
* Swagger2默认的url后缀
*/
public static final String SWAGGER2URL = "/v2/api-docs?group=mike";
...
}
上篇:Swagger-的使用(详细教程)
参考博客:
SpringBoot整合Knife4j:https://blog.csdn.net/weixin_48418701/article/details/128415992
再见Swagger UI 国人开源了一款超好用的 API 文档生成框架,真香:https://zhuanlan.zhihu.com/p/438031681?utm_id=0