【Spring Boot + OpenAPI 3】开箱即用的 API 文档方案(SpringDoc + Knife4j)

文章目录

  • 写在前面
  • [一、基础方案:SpringDoc + OpenAPI 3(原生 Swagger UI)](#一、基础方案:SpringDoc + OpenAPI 3(原生 Swagger UI))
    • [1. SpringDoc 依赖](#1. SpringDoc 依赖)
    • [2. 配置文件 application.yml](#2. 配置文件 application.yml)
    • [3. Api 文档配置类 SwaggerConfig.class](#3. Api 文档配置类 SwaggerConfig.class)
    • [4. 安全配置类 SecurityConfig.class 中放行 Api 接口](#4. 安全配置类 SecurityConfig.class 中放行 Api 接口)
    • [5. 在控制器中使用](#5. 在控制器中使用)
    • [6. Api 文档访问效果](#6. Api 文档访问效果)
  • [二、增强方案:集成 Knife4j 美化与功能扩展](#二、增强方案:集成 Knife4j 美化与功能扩展)
    • [1. Knife4j 依赖](#1. Knife4j 依赖)
    • [2. 配置文件 application.yml](#2. 配置文件 application.yml)
    • [3. Api 文档配置类 SwaggerConfig.class](#3. Api 文档配置类 SwaggerConfig.class)
    • [4. 安全配置类 SecurityConfig.class 中放行 Api 接口](#4. 安全配置类 SecurityConfig.class 中放行 Api 接口)
    • [5. 在控制器中使用](#5. 在控制器中使用)
    • [6. Api 文档访问效果](#6. Api 文档访问效果)
    • [7. 其他](#7. 其他)

写在前面

API 文档的一种现代配置方案是:

  • OpenAPI:设计规范,明确规定 GET 请求不得携带 RequestBody 参数。
  • SpringDoc :Spring Boot 下基于 OpenAPI 3 的实现框架,使用 @Tag@Operation 等注解描述接口。(而基于 Swagger 2 的 SpringFox 框架及其 @Api@ApiOperation 注解已过时)
  • Swagger UI:官方提供的可视化文档前端界面。
  • Knife4j:对 Swagger UI 的增强与美化,仅替换前端展示层,不改变后端逻辑。

本文使用的依赖版本:

  • Spring Boot:2.6.13
  • SpringDoc:1.6.14
  • Knife4j:4.5.0

一、基础方案:SpringDoc + OpenAPI 3(原生 Swagger UI)

1. SpringDoc 依赖

xml 复制代码
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<version>2.6.13</version>
		</dependency>
xml 复制代码
		<!-- SpringDoc OpenAPI 替换为 SB2 兼容版本 -->
		<dependency>
			<groupId>org.springdoc</groupId>
			<artifactId>springdoc-openapi-ui</artifactId>
			<version>1.6.14</version>
		</dependency>

2. 配置文件 application.yml

SpringDoc 从 1.6.4 起已原生支持 Spring Boot 2.6+ 默认的 PathPatternParser 路径匹配策略,故无需手动指定 Ant 路径匹配器。

yml 复制代码
server:
  port: 8080
  servlet:
    context-path: /api

springdoc:
	api-docs:
		path: /v3/api-docs  # 这里配置的是相对于context-path的路径,不是绝对路径
	swagger-ui:
		path: /swagger-ui.html
		url: /v3/api-docs  # 相对路径。Swagger UI 会基于当前路径(/api/)去拼接 url

3. Api 文档配置类 SwaggerConfig.class

java 复制代码
package org.example.framework.config;

import io.swagger.v3.oas.models.Components;
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.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Swagger / OpenAPI 文档配置(供 Knife4j 使用)
 */
@Configuration
public class SwaggerConfig {

    @Bean
    public OpenAPI swaggerOpenAPI() {
        return new OpenAPI()
                .info(new Info()
                        // API 文档的主标题,会显示在文档顶部(例如:用户中心服务 API)
                        .title("XXX 项目接口文档 API") // 项目名称
                        // API 文档的版本号,建议与项目版本保持一致(例如:v1.2.0)
                        .version("1.0")
                        // API 文档的整体描述,可说明用途、注意事项、认证方式等
                        .description("这是本系统的 RESTful API 接口文档,所有接口均需通过 JWT 认证。" +
                                "请勿在生产环境随意调用写操作接口。")
                        // 联系人信息(作者/团队)
                        .contact(new Contact()
                                // 开发者或团队名称
                                .name("XXX")
                                // 联系邮箱(会显示为可点击的 mailto 链接)
                                .email("-")
                                // 个人主页、项目地址或公司官网(可选)
                                .url("-")
                        )
                )
                // 全局的JWT认证配置
                .components(new Components()
                        .addSecuritySchemes("JWT", new SecurityScheme()
                                .type(SecurityScheme.Type.HTTP)
                                .scheme("bearer")   // 必须是小写 "bearer"
                                .bearerFormat("JWT")
                                .in(SecurityScheme.In.HEADER)
                                .name("Authorization")
                        )
                )
                // 所有接口默认需要 JWT 认证,否则 swagger ui 请求头不会携带 Authorization: Bearer xxx
                .addSecurityItem(new SecurityRequirement().addList("JWT"));
    }
}

4. 安全配置类 SecurityConfig.class 中放行 Api 接口

java 复制代码
package org.example.framework.security.config;


import lombok.extern.slf4j.Slf4j;
import org.example.framework.security.filter.JwtAuthenticationFilter;
import org.example.framework.security.handler.AccessDeniedHandlerImpl;
import org.example.framework.security.handler.AuthenticationEntryPointImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * Spring Security配置
 */
@Slf4j
@EnableWebSecurity
@EnableGlobalMethodSecurity(
        prePostEnabled = true,  // 启用@PreAuthorize
        securedEnabled = true,  // 启用@Secured
        jsr250Enabled = true    // 启用@RolesAllowed(JSR-250标准注解)
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Lazy  // 延迟加载,防止循环依赖
    private JwtAuthenticationFilter jwtAuthenticationFilter;
    @Autowired
    private AuthenticationEntryPointImpl authenticationEntryPoint;
    @Autowired
    private AccessDeniedHandlerImpl accessDeniedHandler;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        log.debug("SecurityConfig configuring HttpSecurity");   // 检查Spring Security配置的加载顺序
        http
                .csrf().disable() // 关闭CSRF(RESTful API无需)
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态会话
                .and()
                .authorizeRequests()
                // --- 放行SpringDoc的路径(相对context-path) ---
                .antMatchers(
                        "/v3/api-docs",
                        "/v3/api-docs/**",    // API描述文档的JSON数据
                        "/swagger-ui/**",     // Swagger UI的所有资源(HTML, JS, CSS)
                        "/swagger-ui.html",    // Swagger UI主页面,
                        "/webjars/**",           // Swagger 可能需要的静态资源
                        "/swagger-resources/**" // Swagger 资源
                ).permitAll()
                // --- 放行自己的接口,例如登录 ---
                .antMatchers("/auth/login", "/auth/wechat/login").permitAll()
                // --- 指定路径鉴权 ---
                .antMatchers("/system/**").hasRole("ADMIN") // 角色前缀会自动添加"ROLE_"
                // --- 其他安全规则 ---
                .anyRequest().authenticated()
                .and()
                .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)   // 添加JWT过滤器
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint)    // 添加401异常处理器
                .accessDeniedHandler(accessDeniedHandler);         // 添加403异常处理器
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(); // 密码加密器
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean(); // 暴露AuthenticationManager供登录接口使用
    }
}

5. 在控制器中使用

java 复制代码
package org.example.app.controller;

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.RestController;

@Tag(name = "认证接口")
@RestController
public class TestController {

    @Operation(summary = "B端账号密码登录")
    @PostMapping("/auth/login")
    public String test() {
        return "Hello World";
    }
}

6. Api 文档访问效果

访问 http://localhost:8080/api/swagger-ui.html


二、增强方案:集成 Knife4j 美化与功能扩展

在上述方案的基础上稍作改动,即可无缝切换。

1. Knife4j 依赖

xml 复制代码
		<!-- SpringDoc OpenAPI 替换为 SB2 兼容版本 -->
		<!-- <dependency>
			<groupId>org.springdoc</groupId>
			<artifactId>springdoc-openapi-ui</artifactId>
			<version>1.6.14</version>
		</dependency> -->
		<!-- Knife4j -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
            <version>4.5.0</version>
        </dependency>

2. 配置文件 application.yml

Knife4j 4.5.0 底层是 SpringDoc 1.6.14。

SpringDoc 从 1.6.4 起已原生支持 Spring Boot 2.6+ 默认的 PathPatternParser 路径匹配策略,故无需手动指定 Ant 路径匹配器。

在上述方案的基础上需要启用 Knife4j 增强,以便访问 /doc.html,其他无需改动。

yml 复制代码
knife4j:
	enable: true  # 启用 knife4j 增强,访问 /doc.html
	basic:        # 是否启用登录认证
		enable: false
		# username: admin
		# password: 123456
	production: false   # 生产环境屏蔽

3. Api 文档配置类 SwaggerConfig.class

同上述方案,无需改动。

4. 安全配置类 SecurityConfig.class 中放行 Api 接口

较上述方案中的配置,新增放行 Knife4j 主页接口 /doc.html,其他无需改动。

java 复制代码
package org.example.framework.security.config;

...

/**
 * Spring Security配置
 */
@Slf4j
@EnableWebSecurity
@EnableGlobalMethodSecurity(
        prePostEnabled = true,  // 启用@PreAuthorize
        securedEnabled = true,  // 启用@Secured
        jsr250Enabled = true    // 启用@RolesAllowed(JSR-250标准注解)
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        ...
                // --- 放行SpringDoc的路径(相对context-path) ---
                .antMatchers(
                        "/v3/api-docs",
                        "/v3/api-docs/**",    // API描述文档的JSON数据
                        "/swagger-ui/**",     // Swagger UI的所有资源(HTML, JS, CSS)
                        "/swagger-ui.html",    // Swagger UI主页面,
                        "/webjars/**",           // Swagger 可能需要的静态资源
                        "/swagger-resources/**",    // Swagger 资源
                        "/doc.html"     // Knife4j 主页
                ).permitAll()
                ...
    }

    ...
}

5. 在控制器中使用

同上述方案,无需改动。

6. Api 文档访问效果

访问 http://localhost:8080/api/swagger-ui.html 效果同上。

访问 http://localhost:8080/api/doc.html#/home 效果如下。

7. 其他

配置启动链接接口地址,以便从启动日志中快速访问 API 文档。

  • 这里懒得做了。

之前接口文档的菜单重复,后来发现是 Knife4j 的版本和起步依赖有问题,之前的 SpringDoc 依赖也没删干净。

  • 把启动模块和框架模块中有关 API 接口文档的依赖都删掉。
  • 在根目录的 POM 文件中添加 knife4j-openapi3-spring-boot-starter 4.5.0 依赖。不要用基于 openapi2 的 4.4.0 版本。
相关推荐
foxsen_xia1 小时前
go(基础10)——错误处理
开发语言·后端·golang
robch1 小时前
Java后端优雅的实现分页搜索排序-架构2
java·开发语言·架构
她说..1 小时前
在定义Java接口参数时,遇到整数类型,到底该用int还是Integer?
java·开发语言·java-ee·springboot
两广总督是码农1 小时前
IDEA-SpringBoot热部署
java·spring boot·intellij-idea
MoFe11 小时前
【.net/.net core】【报错处理】另一个 SqlParameterCollection 中已包含 SqlParameter。
java·.net·.netcore
sang_xb1 小时前
深入解析 HashMap:从存储架构到性能优化
android·java·性能优化·架构
是店小二呀1 小时前
openEuler多核压缩性能实战:从单核到多核的算力跃升
后端
是店小二呀1 小时前
openEuler 上 Redis 性能调优与基准测试实战
后端
是店小二呀1 小时前
openEuler 25.09 系统级开发环境配置与实践(GCC + GDB + SDK)
后端