1、将旧版swagger依赖去掉
<!-- <!– Swagger3依赖 –>-->
<!-- <dependency>-->
<!-- <groupId>io.springfox</groupId>-->
<!-- <artifactId>springfox-boot-starter</artifactId>-->
<!-- <version>${swagger.version}</version>-->
<!-- <exclusions>-->
<!-- <exclusion>-->
<!-- <groupId>io.swagger</groupId>-->
<!-- <artifactId>swagger-models</artifactId>-->
<!-- </exclusion>-->
<!-- </exclusions>-->
<!-- </dependency>-->
2、添加knife4j依赖
主依赖pom文件中添加
<springdoc.version>1.6.15</springdoc.version>
<knife4j.version>4.3.0</knife4j.version>
<!--knife4j接口文档-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>${springdoc.version}</version>
</dependency>
在ruoyi-common添加依赖引用,也可以放在ruoyi-framework里
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
</dependency>
3、添加配置文件
删除原本src/main/java/com/ruoyi/web/core/config路径下的SwaggerConfig
在common里添加两个配置文件
SwaggerConfig
package com.ruoyi.common.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
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 java.util.HashMap;
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.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
}
}
SwaggerProperties
package com.ruoyi.common.config;
/**
* Created with IntelliJ IDEA.
*
* @Author: muluo
* @Date: 2024/09/09/19:18
* @Description:
*/
import javax.validation.constraints.NotEmpty;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Swagger 配置属性*/
@ConfigurationProperties("muluo.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;
}
修改application.yml
## Swagger配置
#swagger:
# # 是否开启swagger
# enabled: true
# # 请求前缀
## pathMapping: /dev-api
# pathMapping: /
springdoc:
api-docs:
enabled: true
path: /v3/api-docs
swagger-ui:
enabled: true
path: /swagger-ui
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: true
setting:
language: zh_cn
muluo:
swagger:
title: muluo开发平台
description: 提供管理后台、用户 App 的所有功能
version: ${ruoyi.version}
url: xxxx
email: qq.com
license: xxx
license-url: xxx
修改SecurityConfig,添加新版文档路径放行
.antMatchers( "/v3/api-docs/*", "/doc.html").permitAll()4、替换原本的swagger注解
快捷键ctrl+shift+r
依次替换
-
@Api( 替换 @Tag( name =
-
@ApiOperation( 替换 @Operation( description =
-
@ApiImplicitParams 替换 @Parameters
-
@ApiImplicitParam 替换 @Parameter
-
@ApiModel 替换 @Schema
-
@ApiModelProperty 替换 @Schema
清理掉多余的引用
修改src/main/java/com/ruoyi/web/controller/tool/TestController.java
package com.ruoyi.web.controller.tool;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.StringUtils;
/**
* swagger 用户测试方法
*
* @author ruoyi
*/
@Tag(name = "用户信息管理")
@RestController
@RequestMapping("/test/user")
public class TestController extends BaseController
{
private final static Map<Integer, UserEntity> users = new LinkedHashMap<Integer, UserEntity>();
{
users.put(1, new UserEntity(1, "admin", "admin123", "15888888888"));
users.put(2, new UserEntity(2, "ry", "admin123", "15666666666"));
}
@Operation(description = "获取用户列表")
@GetMapping("/list")
public R<List<UserEntity>> userList()
{
List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
return R.ok(userList);
}
@Operation(description = "获取用户详细")
@GetMapping("/{userId}")
public R<UserEntity> getUser(
@Parameter(name = "userId", description = "用户ID", required = true, example = "1", schema = @Schema(type = "integer"))
@PathVariable Integer userId)
{
if (!users.isEmpty() && users.containsKey(userId))
{
return R.ok(users.get(userId));
}
else
{
return R.fail("用户不存在");
}
}
@Operation(description = "新增用户")
@PostMapping("/save")
public R<String> save(
@Parameter(name = "user", description = "用户信息", required = true, schema = @Schema(implementation = UserEntity.class))
@RequestBody UserEntity user)
{
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
{
return R.fail("用户ID不能为空");
}
users.put(user.getUserId(), user);
return R.ok();
}
@Operation(description = "更新用户")
@PutMapping("/update")
public R<String> update(@RequestBody UserEntity user)
{
if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
{
return R.fail("用户ID不能为空");
}
if (users.isEmpty() || !users.containsKey(user.getUserId()))
{
return R.fail("用户不存在");
}
users.remove(user.getUserId());
users.put(user.getUserId(), user);
return R.ok();
}
@Operation(description = "删除用户信息")
@DeleteMapping("/{userId}")
public R<String> delete(
@Parameter(name = "userId", description = "用户ID", required = true, example = "1", schema = @Schema(type = "integer"))
@PathVariable Integer userId)
{
if (!users.isEmpty() && users.containsKey(userId))
{
users.remove(userId);
return R.ok();
}
else
{
return R.fail("用户不存在");
}
}
}
@Schema(description = "用户实体")
class UserEntity
{
@Schema(description = "用户ID", required = true)
private Integer userId;
@Schema(description = "用户名称", required = true)
private String username;
@Schema(description = "用户密码", required = true)
private String password;
@Schema(description = "用户手机", required = true)
private String mobile;
public UserEntity()
{
}
public UserEntity(Integer userId, String username, String password, String mobile)
{
this.userId = userId;
this.username = username;
this.password = password;
this.mobile = mobile;
}
public Integer getUserId()
{
return userId;
}
public void setUserId(Integer userId)
{
this.userId = userId;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public String getMobile()
{
return mobile;
}
public void setMobile(String mobile)
{
this.mobile = mobile;
}
}
5、访问
Swagger版本接口文档: http://ip:port/swagger-ui/index.html
Knife4j版本接口文档: http://ip:port/doc.html