Knife4j-的使用(详细教程)

news2025/2/1 16:44:50

文章目录

  • 前言
  • 一、简介
  • 二、版本参考
  • 三、基本使用
    • 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 怎么使用的教程,但是现在很多项目用的接口文档其实是 Knife4jKnife4j 它是对 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-uiui 皮肤项目。

最开始只是一个增强版本的 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.5Ui重写,底层依赖的 springfox 框架版本是 2.9.2
2.0.6~2.0.9底层 springfox 框架版本升级知 2.10.5OpenAPI 规范是 v2
3.0~3.0.3底层依赖 springfox 框架版本升级至 3.0.3OpenAPI 规范是v3
4.0~4.0 重要版本,提供 OpenAPI2OpenAPI3 两种规范供开发者自行选择,主版本统一

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.2Knife4j 2.0.0 ~ 2.0.6>=Knife4j 4.0.0
2.2.x~2.4.0Knife4j 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:不过 Knife4j4.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.RELEASEspringfox 的版本是 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 版本之后才能使用的,如果要使用这些功能,可能你还得升级 Knife4jspringfox 甚至可能要升级 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-docsKnife4j 接口文档中的接口信息数据都是来源于这个接口,可以 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 安全认证配置

通常情况下我们的接口是需要添加 tokenAuthorization 这样的请求头,这些请求头中起到安全认证的作用,我们现在是没法通过接口文档调接口时添加请求头

在这里插入图片描述

添加以下配置:

    /**
     * 安全模式,这里指定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. 因兼容性问题引起项目启动失败

在这里插入图片描述

在这里插入图片描述

简单来说就是版本冲突了,可能是 Knife4jswagger 的版本相冲突,或者是和 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/762807.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机组成2——存储系统

1. 硬件构成、工作原理、评价指标 2.主存储器 基本构成为DRAM&SRAMROM&#xff0c;工作原理为串行访问特点是采用多体交叉提高读取速度 RAM工作原理 SRAM的读写过程如下&#xff1a; WE控制读写&#xff1b; CS为片选信号&#xff1b; VCC为接地端&#xff1b; GND为…

GitLab 16.1创建新成员

GitLab 16.1界面有明显的变化,Admin Area在界面中不容易找到。 下面是找到Admin Area的方法。 本来是可以通过红框的链接找到Admin Area,但是这链接是http://127.0.0.1:8000/root,无法直接访问。 这里有两个方法进入。 方法1 将链接直接改成服务器ip,例如服务器ip是19…

【技术指南】3D转换工具HOOPS Exchange的功能特征和典型使用场景全解析(二)

什么是 HOOPS Exchange&#xff1f;HOOPS Exchange 是一组软件库&#xff0c;可以帮助开发人员在开发应用程序时读取和写入主流的 2D 和 3D 格式。HOOPS Exchange 支持 在主流的3D 文件格式中读取 CAD 数据&#xff0c;并支持将 3D 数据转换为 PRC 数据格式&#xff0c;这是一种…

Godot实用代码-存取存档的程序设计

1. Settings.gd 全局变量 用于保存玩家设置 对应Settings.json 2. Data.gd 全局变量 用于保存玩具数据 对应Data.json 实践逻辑指南 1.在游戏开始的时候&#xff08;游戏场景入口的_ready()处&#xff0c; Settings.gd

ceph对象存储和安装dashborad

一、ceph–RadosGW对象存储 数据不需要放置在目录层次结构中&#xff0c;而是存在于平面地址空间内的同一级别&#xff1b; 应用通过唯一地址来识别每个单独的数据对象; 每个对象可包含有助于检索的元数据&#xff1b; 在Ceph中的对象存储网关中&#xff0c;通过RESTful API在…

医院制剂研发与真实世界评价论坛圆满闭幕

医院制剂是新药的摇篮和宝库&#xff0c;现代科技为医院制剂的研发和转化赋能。在新时代新政策下&#xff0c;2023年07月16日&#xff0c;由湖南省药学会医院制剂研发与真实世界评价专业委员会&#xff08;下称“专委会”&#xff09;主委单位湖南易能生物医药有限公司&#xf…

划片机的技术分解

划片机是一种切割设备&#xff0c;主要用于将硬脆材料&#xff08;如硅晶圆、蓝宝石基片、LED基片等&#xff09;分割成较小的单元。其工作原理是以强力磨削为划切机理&#xff0c;通过空气静压电主轴带动刀片与工件接触点的划切线方向呈直线运动&#xff0c;将每一个具有独立电…

Java 设计模式——观察者模式

目录 1.概述2.结构3.案例实现3.1.抽象观察者3.2.观察对象3.3.具体观察者3.4.具体观察对象3.5.测试 4.优缺点5.使用场景6.JDK 源码解析——Observable / Observer6.1.Observable 类6.2.Observer 接口6.3.案例 1.概述 观察者模式 (Observer Pattern) 是一种行为型设计模式&#…

如何管理数据库用户

目录 一、数据库用户管理 新建用户 查询数据库中的用户 重命名用户名 删除用户 修改当前用户密码 修改其他用户密码 二、数据库用户授权 授权 允许用户在指定终端远程连接MySQL并拥有指定权限 撤销权限 授权用户权限总结 一、数据库用户管理 新建用户 命令&#x…

DP485替代MAX485 RS485/RS422 收发器芯片

DP485E 是一款 5V 供电、半双工、低功耗、低摆率&#xff0c;完全满足 TIA/EIA-485 标准要求的 RS-485收发器。DP485E 工作电压范围为 4.75~5.25V&#xff0c;具备失效安全&#xff08;fail-safe&#xff09;、过温保护、限流保护、过压保护&#xff0c;控制端口热插拔输入等功…

phoenix os在vmware workstation上的安装

一、点击创建新的虚拟机配置 选择“安装程序光盘映像文件”&#xff0c;选择你刚刚下好的PhoenixOS ISO镜像文件&#xff0c;点击下一步 分配虚拟机大小。随便你分配&#xff0c;只要大小恰当(系统大小预计会安装软件的大小3G以上的缓存及其他文件存放空间)&#xff0c;反正我就…

opencv -11 图像运算之按位逻辑运算(图像融合图像修复和去除)

按位逻辑运算是一种对图像进行像素级别的逻辑操作的方法&#xff0c;使用OpenCV的按位逻辑运算函数可以对图像进行位与&#xff08;AND&#xff09;、位或&#xff08;OR&#xff09;、位非&#xff08;NOT&#xff09;和位异或&#xff08;XOR&#xff09;等操作。 通俗点就是…

Java NIO 和 AIO 总结

title: Java NIO 和 AIO 总结 date: 2023-05-10 13:21:26 tags: NIOAIO categories:开发知识及其他 cover: https://cover.png feature: false 1. NIO Java NIO (New IO) is an alternative IO API for Java, meaning alternative to the standard Java IO and Java Networkin…

Unity Arduino 串口通信

一、Unity端发送消息&#xff0c;Arduino端接收消息 通过串口通信 Arduino端 #include <Arduino.h>#define PIN_KEY 5 uint item;void setup() {item 0;Serial.begin(115200);pinMode(PIN_KEY, OUTPUT); }void loop() {if(Serial.available()>0){item Serial.rea…

跨网络的通信过程、路由的作用以及默认网关

如下网络拓扑图&#xff0c;交换机0所在的网段为192.168.1.0/24&#xff0c;交换机1所在网段为192.168.2.0/24&#xff0c;且各自有2台主机&#xff1a; 假设PC0&#xff08;192.168.1.10/32&#xff09;要跟PC4&#xff08;192.168.2.11/32&#xff09;通信&#xff0c;如何实…

上海亚商投顾:沪指缩量调整 3D打印概念股逆势大涨

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大指数今日缩量调整&#xff0c;午后一度均跌超1%&#xff0c;尾盘跌幅略有收窄&#xff0c;保险等权重板块走低…

【中危】Apache Airflow ODBC Provider 远程代码执行漏洞

漏洞描述 Apache Airflow 是一个开源的任务和工作流管理平台&#xff0c;ODBC Provider 是 Apache Airflow 的一个数据库管理/插件。 Apache Airflow ODBC Provider 受影响版本中&#xff0c;由于 odbc.py#driver 方法未对用户可控的 ODBC 驱动程序参数(driver)有效过滤&…

vue - 常见的性能优化

文章目录 vue使用中常见的性能优化1&#xff0c; v-for 遍历避免同时使用 v-if2&#xff0c; 如果需要使用v-for给每项元素绑定事件时 可以使用事件代理**3&#xff0c; 一些数据不做响应式4&#xff0c;一些页面采用keep-alive缓存组件5&#xff0c;第三方UI库按需导入6&#…

Selenium如何定位动态元素?

在经常做自动化过程中&#xff0c;我们没有打开新页面、没有alert、没有frame、加了挺好的等待时间&#xff0c;但是还是定位不到元素&#xff1f;很有可能是你要定位的元素的属性是动态的&#xff0c;即每次打开页面&#xff0c;这个元素的id或者class等元素属性是动态生成的。…

低代码平台缓解了程序员日渐不足的尴尬局面

编者按&#xff1a;如今即便是编程语言学习难度的降低&#xff0c;也不足以跟上计算机应用的快速发展&#xff0c;为了提高软件开发效率&#xff0c;满足市场需求&#xff0c;低代码平台的可视化开发、组件化和框架化降低了开发的技术门槛&#xff0c;让更多人能参与到软件开发…