在 springboot3.x 使用 knife4j 以及常见报错汇总_springboot3 knife4j
目录
引言:
引入依赖:
配置文件:
过滤静态资源:
增强模式:
便捷地址访问:
常见问题:
注解使用实例:
📄 文档参考地址:
SpringBoot 3.x 结合 Swagger3 (Knife4j )踩坑实录 - 古渡蓝按 - 博客园 🔍🏛️ 官方文档地址:
快速开始 | Knife4j📚💡 背景来源:
想在微服务项目使用 Knife4j,但是找了很多文档使用后访问地址无法显示 😵。经过实践和排查,终于解决了问题 ✅!
引言:
首先,重点强调 Spring Boot 3.x 只支持 OpenAPI3 规范:
- Knife4j提供的starter已经引用springdoc-openapi的jar,开发者需注意避免jar包冲突
- JDK版本必须 >= 17
- 详细Demo请参考knife4j-spring-boot3-demo
在 Spring Boot 3.x 项目中,如果你看到 swagger-annotations
依赖,通常意味着你正在使用 Springfox Swagger(如 springfox-swagger2
),而它 不兼容 Spring Boot 3.x(因为 Spring Boot 3 迁移到了 Jakarta EE 9+,而 Springfox 仍依赖旧的 javax.servlet
包)。
io.springfox springfox-swagger2 2.10.5 io.springfox springfox-swagger-ui 2.10.5
SpringDoc 是 Spring Boot 3.x 的官方推荐替代方案,完全兼容 Jakarta EE 9+:
@Api
@Tag
@ApiOperation
@Operation
@ApiParam
@Parameter
@ApiModel
@Schema
所以我们需要更换新的依赖,也就是Knife4j4.x,这样才能在 Spring Boot 3.x 项目中使用。
引入依赖:
首先引入依赖:
io.swagger.core.v3 swagger-core 2.2.20 com.github.xiaoymin knife4j-openapi3-jakarta-spring-boot-starter 4.4.0 org.springdoc springdoc-openapi-starter-webmvc-api 2.2.0 org.springframework.boot spring-boot-configuration-processor true com.fasterxml.jackson.module jackson-module-jakarta-xmlbind-annotations 2.13.3 javax.xml.bind jaxb-api 2.4.0-b180830.0359
配置文件:
我们一共要引入三个配置类和一个配置文件:
引入配置文件,这里因为我在开发微服务,所以在bootstrap.yml进行配置,如果正常开发Springboot项目的话,在application.yml配置即可:
尽需改写文档扫描包路径即可,配置成自己项目的controller包路径。
server: servlet: context-path: /content port: 63040# springdoc-openapi项目配置springdoc: swagger-ui: path: /swagger-ui.html tags-sorter: alpha operations-sorter: alpha api-docs: path: /v3/api-docs group-configs: - group: \'default\' paths-to-match: \'/**\' # 生成文档所需的扫包路径,一般为启动类目录 packages-to-scan: com.xuecheng.content.api# knife4j的增强配置,不需要增强可以不配knife4j: # 是否启用增强设置 enable: true # 是否启用登录认证 basic: enable: true username: admin password: 123456 setting: language: zh_cn enable-version: true enable-swagger-models: true swagger-model-name: 用户模块
过滤静态资源:
Spring MVC配置类,主要用于处理网站图标(favicon.ico)的请求
import jakarta.servlet.http.HttpServletRequest;import jakarta.servlet.http.HttpServletResponse;import org.springframework.boot.SpringBootConfiguration;import org.springframework.http.HttpStatus;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/** * @Classname FaviconConfiguration * @Description 添加配置文件,处理favicon.ico请求 * @Version 1.0.0 * @Date 2025/5/26 13:39 * @Created by Administrator */@SpringBootConfigurationpublic class FaviconConfiguration implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new HandlerInterceptor() { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { if (!\"GET\".equalsIgnoreCase(request.getMethod()) || !request.getRequestURI().toString().equals(\"/favicon.ico\")) { return true; } response.setStatus(HttpStatus.NO_CONTENT.value()); // 设置状态码为204 No Content return false; } }).addPathPatterns(\"/**\"); }}
增强模式:
自定义生成的Swagger/OpenAPI文档的展示信息,提供一些项目信息或者个人的信息。
import io.swagger.v3.oas.models.OpenAPI;import io.swagger.v3.oas.models.ExternalDocumentation;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;import java.util.ArrayList;import java.util.List;/** * Swagger2配置信息 * 这里分了两组显示 * 第一组是api,当作用户端接口 * 第二组是admin,当作后台管理接口 * 也可以根据实际情况来减少或者增加组 * * @author eleven_lxs * @date 2025-05-26 22:17 */@Configurationpublic class SwaggerConfig { @Bean public OpenAPI swaggerOpenAPI(){ return new OpenAPI() .info(new Info().title(\"标题\") // 信息 .contact(new Contact().name(\"作者\").email(\"邮箱\").url(\"地址\")) // 简介 .description(\"我的API文档\") // 版本 .version(\"v1\") // 许可证 .license(new License().name(\"Apache 2.0\").url(\"http://springdoc.org\"))) .externalDocs(new ExternalDocumentation() .description(\"外部文档\") .url(\"https://springshop.wiki.github.org/docs\")); }}
便捷地址访问:
而为了方便直接通过点击地址直接访问,我们编写配置类帮助我们直接访问:
import io.micrometer.common.util.StringUtils;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.context.event.ApplicationReadyEvent;import org.springframework.context.ApplicationListener;import org.springframework.context.annotation.Configuration;import org.springframework.core.env.Environment;import java.net.InetAddress;import java.net.UnknownHostException;import java.util.Arrays;import java.util.Optional;/** * @Classname DocumentationConfig * @Description TODO * @Version 1.0.0 * @Date 2025/5/26 15:28 * @Created by Administrator */@Configuration@Slf4jpublic class DocumentationConfig implements ApplicationListener { @Autowired private Environment env; @Override public void onApplicationEvent(ApplicationReadyEvent event) { String protocol = env.getProperty(\"server.ssl.key-store\") != null ? \"https\" : \"http\"; System.out.println(env); // 获取端口(添加默认值8080) String serverPort = env.getProperty(\"server.port\", \"8000\"); // 处理contextPath(避免null拼接) String contextPath = Optional.ofNullable(env.getProperty(\"server.servlet.context-path\")) .orElse(\"\"); String docPath = contextPath + \"/doc.html\"; // 获取主机地址 String hostAddress; try { hostAddress = InetAddress.getLocalHost().getHostAddress(); } catch (UnknownHostException e) { hostAddress = \"localhost\"; log.warn(\"无法获取主机IP,使用默认地址: localhost\"); } log.info(\"\"\" ---------------------------------------------------------- \\t应用程序 \"{}\" 已启动 \\t文档访问地址: \\t本地: \\t{}://localhost:{}{} \\t外部: \\t{}://{}:{}{} \\t激活配置: \\t{} ----------------------------------------------------------\"\"\", env.getProperty(\"spring.application.name\", \"默认应用\"), protocol, serverPort, docPath, protocol, hostAddress, serverPort, docPath, Arrays.toString(env.getActiveProfiles())); }}
常见问题:
如果是开发微服务,这里可能会出现 http://localhost:63040/doc.html ,这里我的问题是出自在bootstrap.yml
是Spring Cloud的配置文件,但在普通Spring Boot应用中不会自动加载,如果想使用,要添加spring-cloud-starter-bootstrap
依赖才能生效:
org.springframework.cloud spring-cloud-starter-bootstrap 4.1.5
随后在启动类下面可以添加代码进行测试:
@SpringBootApplicationpublic class ContentApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(ContentApplication.class, args); printEnvInfo(context); } private static void printEnvInfo(ConfigurableApplicationContext context) { Environment env = context.getEnvironment(); System.out.println(\"\\n=== 应用配置信息 ===\"); System.out.println(\"应用名称: \" + env.getProperty(\"spring.application.name\")); System.out.println(\"服务端口: \" + env.getProperty(\"server.port\")); System.out.println(\"上下文路径: \" + env.getProperty(\"server.servlet.context-path\")); System.out.println(\"激活Profile: \" + Arrays.toString(env.getActiveProfiles())); System.out.println(\"数据库URL: \" + env.getProperty(\"spring.datasource.url\")); System.out.println(\"Swagger路径: \" + env.getProperty(\"springdoc.swagger-ui.path\")); }}
而我为了方便,我直接配置了一个新的application.yml,发现一样好使:
server: port: 63040
另外如果还是没有显示,那么去检查你的 SecurityConfig 配置,确保 SecurityConfig 放行所有文档路径:
@Configurationpublic class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers( \"/content/swagger-ui/**\", \"/content/v3/api-docs/**\", \"/content/doc.html\", \"/content/webjars/**\" ).permitAll() .anyRequest().authenticated() ); return http.build(); }}
注解使用实例:
import com.xuecheng.base.model.PageParams;import com.xuecheng.base.model.PageResult;import com.xuecheng.content.model.dto.QueryCourseParamsDto;import com.xuecheng.content.model.po.CourseBase;import io.swagger.v3.oas.annotations.Operation;import io.swagger.v3.oas.annotations.Parameter;import io.swagger.v3.oas.annotations.tags.Tag;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RestController;import java.time.LocalDateTime;import java.util.ArrayList;import java.util.List;@Tag(name = \"课程信息管理接口\", description = \"课程信息管理接口\") // 替代 @Api@RestControllerpublic class CourseBaseInfoController { @Operation(summary = \"课程查询接口\") // 替代 @ApiOperation @PostMapping(\"/course/list\") public PageResult list( @Parameter(description = \"分页参数\") PageParams pageParams, // 替代 @ApiParam @Parameter(description = \"查询条件\") @RequestBody(required = false) QueryCourseParamsDto queryCourseParamsDto ) { CourseBase courseBase = new CourseBase(); courseBase.setName(\"测试名称\"); courseBase.setCreateDate(LocalDateTime.now()); List courseBases = new ArrayList(); courseBases.add(courseBase); return new PageResult(courseBases, 10, 1, 10); }}
import lombok.Data;import lombok.ToString;import io.swagger.v3.oas.annotations.media.Schema;@Data@ToString@Schema(name = \"PageParams\", description = \"分页查询参数\") // 类级别描述(可选)public class PageParams { @Schema(description = \"页码\", example = \"1\", defaultValue = \"1\") private Long pageNo = 1L; @Schema(description = \"每页记录数\", example = \"30\", defaultValue = \"30\") private Long pageSize = 30L; public PageParams() { } public PageParams(Long pageNo, Long pageSize) { this.pageNo = pageNo; this.pageSize = pageSize; }}