springboot3.0.11-SNAPSHOT使用knife4j-openapi3所遇见的问题
作者:mmseoamin日期:2024-01-18

1.本地工作环境

ide2021

jdk17

springboot3.0.11-SNAPSHOT

2.使用knife4j-openapi3的原因

在使用springboot3写完一个项目后,想快速生成一篇接口文档,供自己观看。在网上冲浪一段时间后,发现使用Swagger文档比较合适,通过少量的注解来完成一篇复杂的文档。说干就干,直接cope网上的资料写一个demo来用,发现项目无法正常启动。在翻阅了博客后,发现Swagger2暂时无法适配springboot3。后再其他博客中发现可以使用openapi兼容springboot3,同时,knife4j是对swagger的美化,所以使用knife4j-openapi3。

3.进行配置

对应的依赖如下:


     com.github.xiaoymin
     knife4j-openapi3-jakarta-spring-boot-starter
     4.1.0

配置文件采用yml格式,所以在配置中对knife4j进行如下简单配置

# 在线文档配置
springdoc:
  swagger-ui:
    # 配置swagger-ui界面访问路径
    path: /swagger-ui.html
    # 包扫描路径
  packages-to-scan: com.pjx.sys.controller
  # 默认开启wend
  api-docs:
    enabled: true

上述的 packages-to-scan 也就是包扫描路径,是对控制层进行扫描,也就是你的controller层,只要扫描到外面那一层,不要深入到内部。路径可以直接复制。

springboot3.0.11-SNAPSHOT使用knife4j-openapi3所遇见的问题,第1张

此时还需对knife4j进行配置,才可以使用。

自己的项目中创建SwaggerConfig类进行配置

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SwaggerConfig {
    @Bean
    public OpenAPI springShopOpenAPI() {
        return new OpenAPI()
                .info(new Info().title("标题")
                        //描叙
                        .description("我的API文档")
                        //版本
                        .version("v1")
                        //作者信息,自行设置
                        .contact(new Contact().name("彭").email("11111").url("https://www.baidu.com"))
                        //设置接口文档的许可证信息
                        .license(new License().name("Apache 2.0").url("http://springdoc.org")));
    }
}

在这里基本的配置算是完成了,接下来用一个简单的demo演示

springboot3.0.11-SNAPSHOT使用knife4j-openapi3所遇见的问题,第2张

上面是对应的结构,下面分别为控制层和pojo

import com.example.test.pojo.Books;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "测试",description = "描述")
@RestController
@RequestMapping("/getBooks")
public class BookController {
    @GetMapping
    @Operation(summary = "测试接口")
    public Books getBooks(){
        Books books = new Books();
        books.setId(1);
        return books;
    }
}
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema
@Data
public class Books {
    @Schema(name = "id",description = "用户id",defaultValue = "12",example = "1")
    private Integer id;
}

以上完成后,一个简单的文档就完成了,直接看效果。

doc.html

springboot3.0.11-SNAPSHOT使用knife4j-openapi3所遇见的问题,第3张

swagger-ui

springboot3.0.11-SNAPSHOT使用knife4j-openapi3所遇见的问题,第4张

在demo完成,发现没有问题后,便开始在自己的项目中导入配置,然后出现一系列问题。

4.自己的项目中出现的问题

4.1可以访问swagger -ui但是无法访问doc.html

springboot3.0.11-SNAPSHOT使用knife4j-openapi3所遇见的问题,第5张

当时我也不知道怎么回事,在想,为什么不可以显示?为什么swagger-ui可以使用?为什么demo可以使用?程序员的三连懵逼。。。最后在浏览了大量的博客后,发现是自己脑子抽了。

首先,要知道,这些资源在哪里,他们在knife4j的jar包中,包你虽然导入了,但是资源你不告诉spring boot,这让它怎么找?找空气吗?其次,swagger-ui可以可以使用,是因为在yml文件中配置了,doc没有配置,也没有配置方法,demo可以使用,而项目中的不可以使用,是因为springboot版本太高,有时找不到资源,需要你手动告诉它,也就回到问题1了。

对应的资源如下:springboot3.0.11-SNAPSHOT使用knife4j-openapi3所遇见的问题,第6张

4.1.1解决方法

在WebConfig配置类中实现WebMvcConfigurer接口,重写addResourceHandlers方法,导入资源的位置。

@Component
public class WebConfig implements WebMvcConfigurer {
 /**
     * 静态资源映射
     *
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
     registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
     registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}

如此,资源便让springboot找到了,当然,如果配置了拦截器,则需要忽略一些资源,可以在WebMvcConfigurer接口中实现addInterceptors方法,在内部用addInterceptor定义自己的拦截器,用addPathPatterns添加拦截路径和excludePatterns添加忽略路径,我的忽略路径如下

"/v3/api-docs/**", "/doc.html", "/webjars/**", "/swagger-resources", "/swagger-ui/**"

若不知道要忽略的具体资源,可以直接在浏览器的   网络  中,采用Shift+f5的方式,哪些请求报错,就忽略哪些资源。这样,doc.html便可以访问了。

4.2关于在doc.html找不到图标的问题

这个问题说大嘛也不大,但是看着浏览器报错也不是很喜欢,在网上查阅了资料后,发现可能是图标侵权了,然后后面不让用了。

springboot3.0.11-SNAPSHOT使用knife4j-openapi3所遇见的问题,第7张

4.2.1解决方法

自行在静态资源文件夹下放一张favicon.ico的图片,喜欢什么就放什么,但是后缀名要相同。一定要ico的文件。从网上下载一张喜欢的,后缀名自己改好。

springboot3.0.11-SNAPSHOT使用knife4j-openapi3所遇见的问题,第8张

放入后,并没有万事大吉了,还要让spring boot知道这个图标,不然还是无法访问,同样需要添加静态资源映射。在4.1.1方法里面添加

registry.addResourceHandler("favicon.ico").addResourceLocations("classpath:/static/");

同时在忽略路径里面添加 /favicon.ico, 也就是放行这张图,让浏览器可以找到。

最后解决完成。撒花。

开玩笑啦。

5.在实体类和控制层的简单运用。

5.1实体类

直接上代码,好吧。

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema
@Data
public class User {
    //id
    @Schema(name = "id",description = "序列号",defaultValue = "1",example = "1")
    private Integer id;
    //用户名
    @Schema(name = "username",description = "用户名",defaultValue = "not null",example = "admin")
    private String username;
    //密码
    @Schema(name = "password",description = "密码",defaultValue = "not null",example = "******")
    private String password;
    //权限id
    @Schema(name = "roleId",description = "权限id,判断是否拥有此权限",defaultValue = "not null",example = "admin")
    private Integer roleId;
    //是否默认
    @Schema(name = "is_default",description = "0为默认用户,1为普通用户",defaultValue = "1",example = "1")
    private Integer is_default;
    //权限
    @Schema(hidden = true)
    private Role role;
    //token
    @Schema(name = "token",description = "存储前端的token",defaultValue = "not null",example = "dsafasdff341234123...")
    private String token;
}

@Schema注解用于描述类的属性,description为描叙,defaultValue为默认值,example为举例子,hidden为忽略。

5.2控制层

import com.pjx.sys.service.UploadService;
import com.pjx.sys.util.R;
import com.pjx.sys.util.SYSCode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.FileNotFoundException;
@Tag(name = "上传图片")
@RestController
@RequestMapping("/adminapi/upload")
public class UploadController {
    //导入UploadService
    @Resource
    private UploadService uploadService;
    @Operation(method = "POST", summary = "更新背景图", description = "通过传入指定规格的图片,更新实验室的背景图")
    @PostMapping
    public R uploadBg(@Parameter(description = "图片对象") @RequestParam("file") MultipartFile file) {
        try {
            uploadService.uploadBg(file);
            return new R(SYSCode.CODE_SUCCESS, "上传成功");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return new R(SYSCode.CODE_ERROR, "上传失败");
    }
}

@Tag用于对API接口进行标记和分组。

@Operation用于对API接口方法进行详细的操作描述,method为方法,summary为简介,description为描叙。

@Parameter用于指定操作的参数列表。

其他的方法不全,暂时如下:

springboot3.0.11-SNAPSHOT使用knife4j-openapi3所遇见的问题,第9张

springboot3.0.11-SNAPSHOT使用knife4j-openapi3所遇见的问题,第10张