Spring Boot - 接口文档
# Spring Boot - 接口文档
# 1. OpenAPI 3.0基础概念
OpenAPI 3.0是一个用于定义RESTful API的开放规范标准,它是由SmartBear Software在2015年将原本的Swagger规范捐赠给OpenAPI Initiative后重命名而来的。通过OpenAPI规范,我们可以实现以下目标:
- 在不接触源代码和文档、不监控网络通信的情况下,使人类和计算机都能理解API的作用
- 统一的API描述方式,与具体编程语言无关
- 便于API的展示、调试和测试,降低API使用成本
OpenAPI规范的核心价值在于标准化API的描述方式,开发者只需按照规范定义API,就可以使用各种工具自动生成文档、客户端代码和服务器端框架,极大提高了API开发和管理效率。
相关资源链接:
- Spring文档:https://springdoc.org/v2/ (opens new window)
- OpenAPI中文文档:https://openapi.apifox.cn/ (opens new window)
- Swagger OpenAPI 3.0官方文档:https://swagger.io/specification/ (opens new window)
# 2. OpenAPI基本使用配置
要在Spring Boot项目中启用OpenAPI文档功能,首先需要配置一个OpenAPI对象,定义文档的基本信息,如标题、描述、版本等。
/**
* OpenAPI基本配置类
* 用于定义API文档基本信息,如标题、描述、版本、外部文档链接等
*/
@Configuration
public class SpringDocAutoConfiguration {
/**
* 创建OpenAPI实例,配置API文档的元数据
* @return 配置完成的OpenAPI对象
*/
@Bean
public OpenAPI springShopOpenAPI() {
return new OpenAPI()
// 设置API基本信息
.info(new Info()
.title("SpringShop API") // API标题
.description("Spring shop示例应用程序接口文档") // 描述信息
.version("v0.0.1") // API版本号
.license(new License()
.name("Apache 2.0") // 许可证名称
.url("http://springdoc.org"))) // 许可证URL
// 设置外部文档链接
.externalDocs(new ExternalDocumentation()
.description("SpringShop Wiki文档")
.url("https://springshop.wiki.github.org/docs"));
}
}
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
这段配置实现了:
- 创建一个基本的OpenAPI配置,包含API文档标题、描述、版本等基本信息
- 配置API的许可证信息
- 关联外部的详细文档链接
当配置完成后,Spring Boot会自动生成API文档,可以通过特定的端点访问。
# 3. API分组功能配置与使用
在实际项目中,API接口通常会按照功能模块或访问权限进行分组,以提高文档的可读性和可管理性。OpenAPI支持接口分组功能,可以将不同模块或不同权限的接口归类展示。
/**
* API分组配置示例
* 将接口按照前缀路径或包路径进行分组
*/
@Configuration
public class SwaggerGroupConfiguration {
/**
* 配置公共API分组
* 匹配所有/public开头的API接口
* @return 公共API的Docket配置
*/
@Bean
public Docket publicApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
// 按包路径匹配Controller
.apis(RequestHandlerSelectors.basePackage("org.github.springshop.web.public"))
// 按URL路径匹配,这里匹配所有/public前缀的路径
.paths(PathSelectors.regex("/public.*"))
.build()
// 设置分组名称
.groupName("springshop-public")
// 设置该分组的API信息
.apiInfo(apiInfo());
}
/**
* 配置管理员API分组
* 匹配所有/admin开头的API接口或带有@Admin注解的方法
* @return 管理员API的Docket配置
*/
@Bean
public Docket adminApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
// 按包路径匹配Controller
.apis(RequestHandlerSelectors.basePackage("org.github.springshop.web.admin"))
// 按URL路径匹配,这里匹配所有/admin前缀的路径
.paths(PathSelectors.regex("/admin.*"))
// 也可以按方法注解匹配
.apis(RequestHandlerSelectors.withMethodAnnotation(Admin.class))
.build()
// 设置分组名称
.groupName("springshop-admin")
// 设置该分组的API信息
.apiInfo(apiInfo());
}
/**
* 定义API文档的基本信息
* @return ApiInfo对象
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("SpringShop API文档")
.description("提供SpringShop所有接口的详细说明")
.version("1.0.0")
.build();
}
}
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
这段配置实现了:
- 创建两个API分组:公共API和管理员API
- 公共API匹配所有以
/public
开头的接口路径 - 管理员API匹配所有以
/admin
开头的接口路径,或带有@Admin
注解的方法 - 为每个分组配置独立的名称和API信息
通过分组功能,用户可以在文档UI界面中切换不同的API分组,更方便地查找和使用所需的接口。
# 4. 实战整合:SpringDoc、Swagger与Knife4j
在实际项目中,我们通常需要整合多种工具来增强API文档的功能和用户体验。下面演示如何整合SpringDoc、Swagger和Knife4j,打造全面的API文档解决方案。
# 4.1 Maven依赖配置
<!-- API文档相关依赖 -->
<dependencies>
<!-- SpringDoc核心依赖,提供OpenAPI 3.0支持 -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.7.0</version>
</dependency>
<!-- Swagger注解依赖,提供API文档注解 -->
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.2.11</version>
</dependency>
<!-- Knife4j UI界面,美化API文档展示效果 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-springdoc-ui</artifactId>
<version>3.0.3</version>
</dependency>
</dependencies>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 4.2 属性配置类
创建一个属性配置类,将文档的基本信息抽离到配置文件中,便于维护和修改。
/**
* Swagger属性配置类
* 用于从配置文件中加载API文档配置项
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties("swagger") // 绑定配置文件中swagger前缀的配置项
public class SwaggerProperties {
/**
* API文档标题
*/
@NotEmpty(message = "标题不能为空")
private String title;
/**
* API文档描述
*/
@NotEmpty(message = "描述不能为空")
private String description;
/**
* API文档作者
*/
@NotEmpty(message = "作者不能为空")
private String author;
/**
* API文档版本号
*/
@NotEmpty(message = "版本不能为空")
private String version;
/**
* API文档联系人URL
*/
@NotEmpty(message = "扫描的 package 不能为空")
private String url;
/**
* API文档联系人邮箱
*/
@NotEmpty(message = "扫描的 email 不能为空")
private String email;
/**
* API文档许可证名称
*/
@NotEmpty(message = "扫描的 license 不能为空")
private String license;
/**
* API文档许可证URL
*/
@NotEmpty(message = "扫描的 license-url 不能为空")
private String licenseUrl;
}
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
# 4.3 核心配置类
创建一个核心配置类,实现API文档的详细配置,包括安全认证、分组设置等高级功能。
/**
* SpringDoc自动配置类
* 用于配置OpenAPI文档的生成和展示
*/
@Configuration
@ConditionalOnClass({OpenAPI.class}) // 当存在OpenAPI类时才启用此配置
@EnableConfigurationProperties(SwaggerProperties.class) // 启用SwaggerProperties配置类
@ConditionalOnProperty(prefix = "springdoc.api-docs", name = "enabled", havingValue = "true", matchIfMissing = true) // 当springdoc.api-docs.enabled为true时启用
public class SpringDocAutoConfiguration {
/**
* 创建OpenAPI实例,配置API文档的基本信息和安全方案
* @param properties 从配置文件加载的Swagger属性
* @return 配置完成的OpenAPI对象
*/
@Bean
public OpenAPI createApi(SwaggerProperties properties) {
// 构建安全方案
Map<String, SecurityScheme> securitySchemas = buildSecuritySchemes();
// 创建OpenAPI对象并配置基本信息和安全方案
OpenAPI openAPI = new OpenAPI()
// 配置API基本信息
.info(buildInfo(properties))
// 配置安全方案
.components(new Components().securitySchemes(securitySchemas));
// 为所有接口添加安全要求
securitySchemas.keySet().forEach(key ->
openAPI.addSecurityItem(new SecurityRequirement().addList(key)));
return openAPI;
}
/**
* 构建API基本信息
* @param properties Swagger属性
* @return Info对象
*/
private Info buildInfo(SwaggerProperties properties) {
return new Info()
.title(properties.getTitle())
.description(properties.getDescription())
.version(properties.getVersion());
}
/**
* 构建安全方案
* 配置通过请求头Authorization传递token参数的认证方式
* @return 安全方案映射
*/
private Map<String, SecurityScheme> buildSecuritySchemes() {
Map<String, SecurityScheme> securitySchemes = new HashMap<>();
// 创建Bearer Token认证方案
SecurityScheme securityScheme = new SecurityScheme()
.type(SecurityScheme.Type.HTTP) // HTTP认证类型
.name(HttpHeaders.AUTHORIZATION) // 认证头名称
.scheme("bearer") // Bearer认证方案
.in(SecurityScheme.In.HEADER); // 在请求头中
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);
}
// ========== API分组配置 ==========
/**
* 创建包含所有API的分组
* @return GroupedOpenApi对象
*/
@Bean
public GroupedOpenApi allGroupedOpenApi() {
return buildGroupedOpenApi("all", "");
}
/**
* 构建API分组,使用分组名作为路径前缀
* @param group 分组名称
* @return GroupedOpenApi对象
*/
public static GroupedOpenApi buildGroupedOpenApi(String group) {
return buildGroupedOpenApi(group, group);
}
/**
* 构建API分组,指定分组名和路径前缀
* @param group 分组名称
* @param path 路径前缀
* @return GroupedOpenApi对象
*/
public static GroupedOpenApi buildGroupedOpenApi(String group, String path) {
return GroupedOpenApi.builder()
.group(group) // 设置分组名称
.pathsToMatch("/" + path + "/**") // 设置匹配的路径
// 为每个操作添加Authorization请求头参数
.addOperationCustomizer((operation, handlerMethod) -> operation
.addParametersItem(buildSecurityHeaderParameter()))
.build();
}
/**
* 构建认证请求头参数
* 解决Knife4j Authorize未生效的问题
* @return 认证参数
*/
private static Parameter buildSecurityHeaderParameter() {
return new Parameter()
.name(HttpHeaders.AUTHORIZATION) // 参数名
.description("认证Token") // 参数描述
.in(String.valueOf(SecurityScheme.In.HEADER)) // 参数位置
.schema(new StringSchema()._default("Bearer xxx")); // 参数模式和默认值
}
}
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# 4.4 应用配置文件
在application.yml
中配置API文档的属性:
# SpringDoc配置
springdoc:
api-docs:
enabled: true # 启用API文档生成
path: /v3/api-docs # API文档JSON数据路径
swagger-ui:
enabled: true # 启用Swagger UI
path: /swagger-ui # Swagger UI访问路径
# Swagger配置信息
swagger:
title: 企业开发平台API文档 # API文档标题
description: 提供管理后台、用户App的所有功能接口说明 # API文档描述
version: 1.0.0 # API文档版本
author: 开发团队 # 作者
url: https://www.example.com # 联系URL
email: contact@example.com # 联系邮箱
license: Apache 2.0 # 许可证
licenseUrl: https://www.apache.org/licenses/LICENSE-2.0 # 许可证URL
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 4.5 访问路径
配置完成后,可以通过以下路径访问API文档:
/v3/api-docs
:返回API文档的JSON数据/doc.html
:访问Knife4j的美化UI界面/swagger-ui
:访问原生Swagger UI界面
这样就完成了SpringDoc、Swagger和Knife4j的整合,既能够使用SpringDoc生成符合OpenAPI 3.0规范的文档,又能够通过Swagger和Knife4j提供友好的UI界面。
# 5. OpenAPI常用注解
在实际开发中,我们需要使用各种注解来描述API的详细信息。下面是常用注解的详细说明和使用示例:
注解 | 标注位置 | 作用 |
---|---|---|
@Tag | Controller类 | 标识Controller的作用 |
@Parameter | 方法参数 | 描述API参数的作用 |
@Parameters | 方法参数 | 批量描述多个参数 |
@Schema | 模型类及其属性 | 描述模型及属性的作用 |
@Operation | Controller方法 | 描述API方法的作用 |
@ApiResponse | Controller方法 | 描述API响应状态码等 |
# 5.1 模型(DTO)注解
/**
* 自定义波形数据传输对象
* 用于API接口的请求参数或返回结果
*/
@Data
public class CustomizedWaveDTO {
@Schema(name = "id", description = "波形配置唯一标识")
private Long id;
@Schema(name = "sensorId", description = "关联的传感器ID")
private Long sensorId;
@Schema(
name = "extensionType",
description = "扩展类型,可选值:speed(速度)、accelerated(加速度)等",
title = "speed->速度,accelerated->加速度..."
)
private String extensionType;
@Schema(
name = "waveType",
description = "波形类型:频谱图->2,包络分析图->3等",
title = "频谱图->2,包络分析图->3..."
)
private String waveType;
@Schema(
name = "lowCut",
description = "滤波初始频率",
title = "滤波初始频率"
)
private Double lowCut;
@Schema(
name = "highCut",
description = "滤波截止频率",
title = "滤波截止频率"
)
private Double highCut;
@Schema(
name = "bandwidth",
description = "滤波宽带",
title = "滤波宽带"
)
private Double bandwidth;
}
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
# 5.2 Controller注解
/**
* 自定义波形控制器
* 提供波形相关的API接口
*/
@RestController
@RequestMapping("/api/customizedWave")
@Tag(name = "自定义波形", description = "提供波形配置的创建、查询、修改和删除功能")
public class CustomizedWaveController {
@Resource
private CustomizedWaveService customizedWaveService;
/**
* 根据ID获取自定义波形配置
* @param id 波形配置ID
* @return 波形配置详情
*/
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@Operation(
summary = "通过ID获取自定义波形配置",
description = "根据波形配置的唯一标识获取详细配置信息"
)
@ApiResponse(
responseCode = "200",
description = "成功获取波形配置",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = CustomizedWaveDTO.class))
)
@ApiResponse(
responseCode = "404",
description = "指定ID的波形配置不存在"
)
public CustomizedWaveDTO getCustomizedWave(
@Parameter(description = "波形配置的唯一ID", required = true)
@PathVariable("id") Long id
) {
return customizedWaveService.findById(id);
}
/**
* 创建新的自定义波形配置
* @param waveDTO 波形配置信息
* @return 创建成功的波形配置(包含ID)
*/
@RequestMapping(method = RequestMethod.POST)
@Operation(
summary = "创建自定义波形配置",
description = "创建新的波形分析配置信息"
)
public CustomizedWaveDTO createCustomizedWave(
@Parameter(description = "波形配置信息", required = true)
@RequestBody CustomizedWaveDTO waveDTO
) {
return customizedWaveService.create(waveDTO);
}
/**
* 更新自定义波形配置
* @param id 配置ID
* @param waveDTO 更新的配置信息
* @return 更新后的配置信息
*/
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
@Operation(
summary = "更新波形配置",
description = "根据ID更新已有的波形配置信息"
)
public CustomizedWaveDTO updateCustomizedWave(
@Parameter(description = "波形配置ID", required = true)
@PathVariable("id") Long id,
@Parameter(description = "更新的配置信息", required = true)
@RequestBody CustomizedWaveDTO waveDTO
) {
waveDTO.setId(id);
return customizedWaveService.update(waveDTO);
}
/**
* 删除自定义波形配置
* @param id 配置ID
* @return 操作结果
*/
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
@Operation(
summary = "删除波形配置",
description = "根据ID删除波形配置"
)
public String deleteCustomizedWave(
@Parameter(description = "波形配置ID", required = true)
@PathVariable("id") Long id
) {
customizedWaveService.delete(id);
return "删除成功";
}
}
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
在上面的示例中:
- 使用
@Tag
注解描述整个Controller的功能 - 使用
@Operation
注解描述每个API方法的功能 - 使用
@Parameter
注解描述API方法的参数 - 使用
@ApiResponse
注解描述API方法的响应 - 使用
@Schema
注解描述DTO类及其属性
通过这些注解,可以生成详细的API文档,方便前端开发人员理解和使用API。
# 6. 从Springfox迁移到SpringDoc的注解对照表
如果项目之前使用的是基于Swagger 2的Springfox,现在需要迁移到基于OpenAPI 3.0的SpringDoc,可以参考以下注解对照表进行迁移:
Springfox注解(Swagger 2) | SpringDoc注解(OpenAPI 3.0) | 作用说明 |
---|---|---|
@Api | @Tag | 描述Controller |
@ApiIgnore | @Parameter(hidden = true)或@Operation(hidden = true)或@Hidden | 隐藏API元素 |
@ApiImplicitParam | @Parameter | 描述方法参数 |
@ApiImplicitParams | @Parameters | 描述多个方法参数 |
@ApiModel | @Schema | 描述数据模型 |
@ApiModelProperty(hidden = true) | @Schema(accessMode = READ_ONLY) | 描述模型属性为只读 |
@ApiModelProperty | @Schema | 描述模型属性 |
@ApiOperation(value="x", notes="y") | @Operation(summary="x", description="y") | 描述API方法 |
@ApiParam | @Parameter | 描述方法参数 |
@ApiResponse(code=404, message="x") | @ApiResponse(responseCode="404", description="x") | 描述API响应 |
迁移示例:
Springfox (旧):
@Api(tags = "用户管理")
@RestController
public class UserController {
@ApiOperation(value = "获取用户信息", notes = "根据用户ID获取详细信息")
@ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "Long")
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
}
2
3
4
5
6
7
8
9
10
11
SpringDoc (新):
@Tag(name = "用户管理")
@RestController
public class UserController {
@Operation(summary = "获取用户信息", description = "根据用户ID获取详细信息")
@Parameter(name = "id", description = "用户ID", required = true, schema = @Schema(type = "integer", format = "int64"))
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
}
2
3
4
5
6
7
8
9
10
11
通过参考此对照表,可以将现有项目从Springfox平滑迁移到SpringDoc,享受OpenAPI 3.0带来的更多功能和优势。