Swagger2 升级到 openapi3

本文最后更新于:2025年2月18日 下午

Swagger2 升级到 openapi3

springboot 2.2.6 -> springboot 2.7.18

由于springboot2.x最新版是2.7.18,所以为了更安全,也为了能用上之前版本缺失的配置,所以推荐升级到2.7.18,这个版本默认是开启静态资源访问的,无需再手动配置。

pom.xml

1
2
3
4
5
6
<!-- knife4j的整合了openapi3的springboot依赖 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>

application.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 接口文档增强模式
# springdoc-openapi项目配置
springdoc:
swagger-ui:
path: /swagger-ui.html
tags-sorter: alpha
operations-sorter: alpha
api-docs:
path: /v3/api-docs
group-configs: # 分组配置
- group: '用户模块'
paths-to-match: '/vr/**' # 根据controller中的请求路径匹配
packages-to-scan: org.example.controller # 指定要扫描的包
- group: '管理员模块'
paths-to-match: '/vrs/**' # 根据controller中的请求路径匹配
packages-to-scan: org.example.converter # 指定要扫描的包

# knife4j的增强配置,不需要增强可以不配
knife4j:
enable: true # 增强模式开关
production: true # 是否是生产环境,是则禁止访问接口文档
setting:
language: zh_cn

# 接口配置
api-doc:
config:
# 文档标题
title: XXX系统 - 项目对接文档
# 文档描述
description: 本文为XXX系统内部资料,未经过项目负责人允许情况下禁止借阅和传播!
# 文档版本
version: v1.0.0 - Alpha
# API服务条款地址
terms-of-service-url: localhost
# 文档作者
name: Peter Zhu
# 文档作者主页
url: http://localhost
# 文档作者邮箱
email: localhost@localhost.com

配置文件

完整配置文档参考地址:https://springdoc.org/#springdoc-openapi-core-properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.Data;
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;

/**
* Api配置类
* - 本项目接口文档地址[第三方UI]:ip地址:端口号/doc.html
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "api-doc.config")
public class ApiConfig {

/**
* 接口文档 >> 文档标题
*/
private String title;

/**
* 接口文档 >> 文档描述
*/
private String description;

/**
* 接口文档 >> 版本号
*/
private String version;

/**
* 接口文档 >> 服务条款地址
*/
private String termsOfServiceUrl;

/**
* 接口文档 >> 作者
*/
private String name;

/**
* 接口文档 >> 作者主页
*/
private String url;

/**
* 接口文档 >> 作者邮箱
*/
private String email;

/**
* 根据@Tag 上的排序,写入x-order
*
* @return the global open api customizer
*/
@Bean
public GlobalOpenApiCustomizer orderGlobalOpenApiCustomizer() {
return openApi -> {
// 全局添加鉴权参数
if(openApi.getPaths()!=null){
openApi.getPaths().forEach((s, pathItem) -> {
pathItem.readOperations().forEach(operation -> {
operation.addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION));
});
});
}
};
}

// @Bean // 用于配置分组,可在配置文件中配置
// public GroupedOpenApi userApi(){
// String[] paths = { "/**" };
// String[] packagedToMatch = { "com.xiaominfo.knife4j.demo.web" };
// return GroupedOpenApi.builder().group("用户模块")
// .pathsToMatch(paths)
// .addOperationCustomizer((operation, handlerMethod) -> operation.addParametersItem(new HeaderParameter().name("groupCode").example("测试").description("集团code").schema(new StringSchema()._default("BR").name("groupCode").description("集团code"))))
// .packagesToScan(packagedToMatch).build();
// }

@Bean // 配置文档信息
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title(title)
.contact(
new Contact()
.name(name) // 作者
.email(email) // 作者邮箱
.url(url)) // 作者主页
.version(version) // 文档版本
.description(description) // 文档描述
.termsOfService(termsOfServiceUrl) // API服务条款
.license(new License().name("Apache 2.0") // 版权信息
.url("http://doc.xiaominfoss.com")) // 版权相关地址
)
.addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION)) // 用于添加请求头的信息
.components(new Components().addSecuritySchemes(HttpHeaders.AUTHORIZATION,new SecurityScheme()
.name(HttpHeaders.AUTHORIZATION).type(SecurityScheme.Type.HTTP).scheme("bearer")));
}
}

相关注解变化

迁移后注解变更参考文档:https://springdoc.org/#migrating-from-springfox

  • Replace swagger 2 annotations with swagger 3 annotations (it is already included with springdoc-openapi-starter-webmvc-ui dependency). Package for swagger 3 annotations is io.swagger.v3.oas.annotations.
    • @Api@Tag
    • @ApiIgnore@Parameter(hidden = true) or @Operation(hidden = true) or @Hidden
    • @ApiImplicitParam@Parameter
    • @ApiImplicitParams@Parameters
    • @ApiModel@Schema
    • @ApiModelProperty(allowEmptyValue = true)@Schema(nullable = true)
    • @ApiModelProperty@Schema
    • @ApiOperation(value = "foo", notes = "bar")@Operation(summary = "foo", description = "bar")
    • @ApiParam@Parameter
    • @ApiResponse(code = 404, message = "foo")@ApiResponse(responseCode = "404", description = "foo")
  • This step is optional: Only if you have multiple Docket beans replace them with GroupedOpenApi beans.

user.java实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.example.enums.User.GenderStatus;

import java.util.Date;

/**
* 用户注册类【AO】
* 说明:UserAO 用于处理用户的输入数据,通常用于将请求数据转换为内部的 DTO 或 BO。
*/
@Data
@Schema(defaultValue = "用户注册类")
public class UserRegistrationAO {

/**
* 用户输入类 >>> 用户名
*/
@Schema(allowableValues = "用户名",name = "username")
private String username;

/**
* 用户输入类 >>> 密码
*/
@Schema(allowableValues = "密码",name = "password")
private String password;

/**
* 用户输入类 >>> 生日
*/
@Schema(allowableValues = "生日",name = "birthday")
private Date birthday;

/**
* 用户输入类 >>> 性别(0男,1女)
*/
@Schema(allowableValues = "性别",name = "gender")
private GenderStatus gender;

/**
* 用户输入类 >>> 联系方式
*/
@Schema(allowableValues = "联系方式",name = "phone")
private String phone;

/**
* 用户输入类 >>> 邮箱
*/
@Schema(allowableValues = "邮箱",name = "email")
private String email;

/**
* 用户输入类 >>> 地址
*/
@Schema(allowableValues = "地址",name = "address")
private String address;

}

枚举类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.Getter;

/**
* 性别状态枚举类
*/
@Getter
public enum GenderStatus {

MAN(0,"男"),
WOMEN(1,"女");

@EnumValue
private final int value;

@JsonValue //json数据返回描述信息
private final String message;


GenderStatus(int value, String message) {
this.value = value;
this.message = message;
}
}

Controller控制层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.example.mapper.VisitorRecordsMapper;
import org.example.model.domain.VisitorRecordsDO;
import org.example.result.Result;
import org.example.result.Result200;
import org.example.result.Result201;
import org.example.service.VisitorRecordsService;
import org.example.model.vo.VisitorRecordsVO;
import org.springframework.web.bind.annotation.*;

import javax.validation.constraints.NotBlank;
import java.io.File;
import java.util.List;
import java.util.Properties;
import java.util.UUID;

@RestController
@RequestMapping(value = "vr")
@ApiResponses({
@ApiResponse(responseCode = "200",description = "请求成功!"),
@ApiResponse(responseCode = "201",description = "上传失败!")
})
@Tag(name = "访问记录")
@CrossOrigin
@RequiredArgsConstructor
public class VisitorRecordsController {

private final VisitorRecordsService visitorRecordsService;
private final VisitorRecordsMapper visitorRecordsMapper;

@ApiOperationSupport(author = "Peter")
@Operation(summary = "分页查询所有记录")
@GetMapping("queryAllByPages")
public Result<Page<VisitorRecordsVO>> queryAllVisitorRecordsByPage(
@NotBlank
@Parameter(name = "num")
@RequestParam(defaultValue = "1")
Integer num,
@NotBlank
@Parameter(name = "size")
@RequestParam(defaultValue = "10")
Integer size) {

Page<VisitorRecordsDO> page = new Page<>(num, size);
Page<VisitorRecordsVO> page1 = new Page<>(num, size);
visitorRecordsService.page(page);

//设置页数据
page1.setRecords(BeanUtil.copyToList(page.getRecords(), VisitorRecordsVO.class));
//设置总记录数
page1.setTotal(page.getTotal());
//设置总页数
page1.setPages(page.getPages());

return Result200.ok(page1);
}
}

Result.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

/**
* 全局统一返回结果类
*/
@Data
@Schema(defaultValue = "Result",description = "响应类")
public class Result<T> {

@Schema(defaultValue = "响应码",name = "code",description = "响应码")
private Integer code;

@Schema(defaultValue = "响应信息",name = "message",description = "响应信息")
private String message;

@Schema(defaultValue = "响应数据",name = "data",description = "响应数据")
private T data;

public Result(){}
// 返回数据
public static <T> Result<T> build(T data) {
Result<T> result = new Result<>();
if (data != null)
result.setData(data);
return result;
}


public static <T> Result<T> build(T body, Integer code, String message) {
Result<T> result = build(body);
result.setCode(code);
result.setMessage(message);
return result;
}


public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
Result<T> result = build(body);
result.setCode(resultCodeEnum.getCode());
result.setMessage(resultCodeEnum.getMessage());
return result;
}
/**
* 操作成功
* @param data baseCategory1List
* @param <T> 泛型
* @return Result
*/
public static<T> Result<T> ok(T data){
return build(data,ResultCodeEnum.SUCCESS);
}
public Result<T> message(String msg){
this.setMessage(msg);
return this;
}
public Result<T> code(Integer code){
this.setCode(code);
return this;
}

}

启动后访问:localhost/doc.html


Swagger2 升级到 openapi3
https://superlovelace.top/2024/11/07/swagger升级到openapi/
作者
棱境
发布于
2024年11月7日
更新于
2025年2月18日
许可协议