ruoyi的swagger升级Knife4j(完整版),分组和分页反参(待补充)
1.将旧版swagger依赖去掉
2.添加knife4j依赖
2.1主依赖Pom里添加
<knife4j.version>4.4.0</knife4j.version>
<!--knife4j接口文档--> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-openapi3-spring-boot-starter</artifactId> <version>${knife4j.version}</version> </dependency>
2.2在ruoyi-common添加依赖引用,也可以放在ruoyi-framework里
<dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-openapi3-spring-boot-starter</artifactId> </dependency>
3.添加配置文件
3.1删除原本的swagger配置
3.2在common里添加两个配置文件(配置非必须,不加也可以)
新建一个swagger
SwaggerConfig
package com.ruoyi.common.swagger; 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.info.License; import io.swagger.v3.oas.models.media.StringSchema; import io.swagger.v3.oas.models.parameters.Parameter; import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; import io.swagger.v3.oas.models.security.SecurityScheme.In; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import org.springdoc.core.GroupedOpenApi; import org.springdoc.core.OpenAPIService; import org.springdoc.core.PropertyResolverUtils; import org.springdoc.core.SecurityService; import org.springdoc.core.SpringDocConfigProperties; import org.springdoc.core.customizers.OpenApiBuilderCustomizer; import org.springdoc.core.customizers.ServerBaseUrlCustomizer; import org.springdoc.core.providers.JavadocProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; /** * Swagger 自动配置类,基于 OpenAPI + Springdoc 实现。 * * 友情提示: * 1. Springdoc 文档地址:<a href="https://github.com/springdoc/springdoc-openapi">仓库</a> * 2. Swagger 规范,于 2015 更名为 OpenAPI 规范,本质是一个东西 * */ // @AutoConfiguration @Configuration @ConditionalOnClass({OpenAPI.class}) @EnableConfigurationProperties(SwaggerProperties.class) @ConditionalOnProperty(prefix = "springdoc.api-docs", name = "enabled", havingValue = "true", matchIfMissing = true) // 设置为 false 时,禁用 public class SwaggerConfig { public static final String HEADER_TENANT_ID = "tenant-id"; // ========== 全局 OpenAPI 配置 ========== @Bean public OpenAPI createApi(SwaggerProperties properties) { Map<String, SecurityScheme> securitySchemas = buildSecuritySchemes(); OpenAPI openAPI = new OpenAPI() // 接口信息 .info(buildInfo(properties)) // 接口安全配置 .components(new Components().securitySchemes(securitySchemas)) .addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION)); securitySchemas.keySet().forEach(key -> openAPI.addSecurityItem(new SecurityRequirement().addList(key))); return openAPI; } /** * API 摘要信息 */ private Info buildInfo(SwaggerProperties properties) { return new Info() .title(properties.getTitle()) .description(properties.getDescription()) .version(properties.getVersion()) .contact(new Contact().name(properties.getAuthor()).url(properties.getUrl()).email(properties.getEmail())) .license(new License().name(properties.getLicense()).url(properties.getLicenseUrl())); } /** * 安全模式,这里配置通过请求头 Authorization 传递 token 参数 */ private Map<String, SecurityScheme> buildSecuritySchemes() { Map<String, SecurityScheme> securitySchemes = new HashMap<>(); SecurityScheme securityScheme = new SecurityScheme() .type(SecurityScheme.Type.APIKEY) // 类型 .name(HttpHeaders.AUTHORIZATION) // 请求头的 name .in(SecurityScheme.In.HEADER); // token 所在位置 securitySchemes.put(HttpHeaders.AUTHORIZATION, securityScheme); return securitySchemes; } /** * 自定义 OpenAPI 处理器 */ @Bean public OpenAPIService openApiBuilder(Optional<OpenAPI> openAPI, SecurityService securityParser, SpringDocConfigProperties springDocConfigProperties, PropertyResolverUtils propertyResolverUtils, Optional<List<OpenApiBuilderCustomizer>> openApiBuilderCustomizers, Optional<List<ServerBaseUrlCustomizer>> serverBaseUrlCustomizers, Optional<JavadocProvider> javadocProvider) { return new OpenAPIService(openAPI, securityParser, springDocConfigProperties, propertyResolverUtils, openApiBuilderCustomizers, serverBaseUrlCustomizers, javadocProvider); } // ========== 分组 OpenAPI 配置 ========== /** * 所有模块的 API 分组 */ @Bean public GroupedOpenApi allGroupedOpenApi() { return buildGroupedOpenApi("all", ""); } public static GroupedOpenApi buildGroupedOpenApi(String group) { return buildGroupedOpenApi(group, group); } public static GroupedOpenApi buildGroupedOpenApi(String group, String path) { return GroupedOpenApi.builder() .group(group) .pathsToMatch("/admin-api/" + path + "/**", "/app-api/" + path + "/**", "/**") .addOperationCustomizer((operation, handlerMethod) -> operation // .addParametersItem(buildTenantHeaderParameter()) .addParametersItem(buildSecurityHeaderParameter())) .build(); } /** * 构建 Authorization 认证请求头参数 * * 解决 Knife4j <a href="https://gitee.com/xiaoym/knife4j/issues/I69QBU">Authorize 未生效,请求header里未包含参数</a> * * @return 认证参数 */ private static Parameter buildSecurityHeaderParameter() { return new Parameter() .name(HttpHeaders.AUTHORIZATION) // header 名 .description("认证 Token") // 描述 .in(String.valueOf(SecurityScheme.In.HEADER)) // 请求 header .schema(new StringSchema()._default("Bearer test1").name(HEADER_TENANT_ID).description("认证 Token")); // 默认:使用用户编号为 1 } /** * 构建 Tenant 租户编号请求头参数 * @return 多租户参数 */ /* private static Parameter buildTenantHeaderParameter() { return new Parameter() .name(HEADER_TENANT_ID) // header 名 .description("租户编号") // 描述 .in(String.valueOf(SecurityScheme.In.HEADER)) // 请求 header .schema(new IntegerSchema()._default(1L).name(HEADER_TENANT_ID).description("租户编号")); // 默认:使用租户编号为 1 } */ }
package com.ruoyi.common.swagger; import javax.validation.constraints.NotEmpty; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; /** * Swagger 配置属性*/ @ConfigurationProperties("aixin.swagger") @Data public class SwaggerProperties { /** * 标题 */ @NotEmpty(message = "标题不能为空") private String title; /** * 描述 */ @NotEmpty(message = "描述不能为空") private String description; /** * 作者 */ @NotEmpty(message = "作者不能为空") private String author; /** * 版本 */ @NotEmpty(message = "版本不能为空") private String version; /** * url */ @NotEmpty(message = "扫描的 package 不能为空") private String url; /** * email */ @NotEmpty(message = "扫描的 email 不能为空") private String email; /** * license */ @NotEmpty(message = "扫描的 license 不能为空") private String license; /** * license-url */ @NotEmpty(message = "扫描的 license-url 不能为空") private String licenseUrl; }
3.3在application.yml配置文件添加需要的配置()
knife4j: enable: true setting: language: zh_cn aixin: swagger: title: fk开发平台 description: 提供管理后台、用户 App 的所有功能 version: ${ruoyi.version} url: xxxx email: qq.com license: xxx license-url: xxx
3.4修改SecurityConfig,添加新版文档路径放行
.antMatchers( "/doc.html").permitAll()
4.替换原本的swagger注解
4.1@Api替换@Tag
@Tag(name ="xxxx")
清理引用
4.2 @ApiOperation替换@Operation
@Operation(summary = "xxxx")
4.3 依次替换
- @ApiImplicitParams替换@Parameters
- @ApiImplicitParam替换@Parameter
- @ApiModel替换@Schema
- @ApiModelProperty替换@Schema
@Parameters({ @Parameter(name = "dataSourceConfigId", description = "数据源配置的编号", required = true, example = "1"), @Parameter(name = "name", description = "表名,模糊匹配", example = "yudao"), @Parameter(name = "comment", description = "描述,模糊匹配", example = "芋道") }) 表名 @Schema(description="分页参数") 字段 @Schema(description = "每页条数,最大值为 100", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
最后启动,访问地址即可
5动态表单的使用
没开启动态表单,则当时很多表单数据时,则无法使用
如下,
没开启,只有一行
在开启后可以有多行表单参数
如下,在最有一行输入完后,会动态往下加一行
6反参显示文档字段
如下
主要是反参包装类必须是泛型(官网文档说明了这点)
反差包装
/** * 通用返回 * * @param <T> 数据泛型 */ @Data public class CommonResult<T> implements Serializable { /** * 错误码 * */ private Integer code; /** * 返回数据 */ private T data; /** * 错误提示,用户可阅读 * */ private String msg; /** * 将传入的 result 对象,转换成另外一个泛型结果的对象 * * 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。 * * @param result 传入的 result 对象 * @param <T> 返回的泛型 * @return 新的 CommonResult 对象 */ public static <T> CommonResult<T> error(CommonResult<?> result) { return error(result.getCode(), result.getMsg()); } public static <T> CommonResult<T> error(Integer code, String message) { Assert.isTrue(!(HttpStatus.SUCCESS ==code), "code 必须是错误的!"); CommonResult<T> result = new CommonResult<>(); result.code = code; result.msg = message; return result; } public static <T> CommonResult<T> success(T data) { CommonResult<T> result = new CommonResult<>(); result.code = HttpStatus.SUCCESS; result.data = data; result.msg = ""; return result; } public static <T> CommonResult<T> success() { CommonResult<T> result = new CommonResult<>(); result.code = HttpStatus.SUCCESS; result.data = null; result.msg = ""; return result; } public static boolean isSuccess(Integer code) { return Objects.equals(code, HttpStatus.SUCCESS); } @JsonIgnore // 避免 jackson 序列化 public boolean isSuccess() { return isSuccess(code); } @JsonIgnore // 避免 jackson 序列化 public boolean isError() { return !isSuccess(); } // ========= 和 Exception 异常体系集成 ========= /** * 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常 */ public void checkError() throws ServiceException { if (isSuccess()) { return; } // 业务异常 throw new ServiceException(msg, code); } /** * 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常 * 如果没有,则返回 {@link #data} 数据 */ @JsonIgnore // 避免 jackson 序列化 public T getCheckedData() { checkError(); return data; } public static <T> CommonResult<T> error(ServiceException serviceException) { return error(serviceException.getCode(), serviceException.getMessage()); } }
7只扫描有@Tag的controller
@Component public class OnlyTagOperationCustomizer implements OperationCustomizer { @Override public io.swagger.v3.oas.models.Operation customize(io.swagger.v3.oas.models.Operation operation, HandlerMethod handlerMethod) { // 检查 Controller 是否有 @Tag 注解 Tag tagAnnotation = handlerMethod.getBeanType().getAnnotation(Tag.class); if (tagAnnotation == null) { return null; // 如果没有 @Tag,移除接口 } return operation; } }
干净了不少,方便导出文档
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 我与微信审核的“相爱相杀”看个人小程序副业
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~