Spring Boot - 接口文档
# 什么是 OpenApi3.0
OpenAPI 3.0.0 是 OpenAPI 规范的第一个正式版本,因为它是由 SmartBear Software 捐赠给 OpenAPI Initiative,并在 2015 年从 Swagger (opens new window) 规范重命名为 OpenAPI 规范。
OpenAPI 规范(OAS),是定义一个标准的、与具体编程语言无关的 RESTful API 的规范。OpenAPI 规范使得人类和计算机都能在「不接触任何程序源代码和文档、不监控网络通信」的情况下理解一个服务的作用。如果您在定义您的 API 时做的很好,那么使用 API 的人就能非常轻松地理解您提供的 API 并与之交互了。
如果您遵循 OpenAPI 规范来定义您的 API,那么您就可以用文档生成工具来展示您的 API,用代码生成工具来自动生成各种编程语言的服务器端和客户端的代码,用自动测试工具进行测试等等。
Spring 文档:https://springdoc.org/v2/
。
OpenApi 中文文档:https://openapi.apifox.cn/
。
Swagger OpenApi 3.0 官方文档:https://swagger.io/specification/
。
# 基本使用
定义文档的基本信息
@Configuration
public class SpringDocAutoConfiguration {
@Bean
public OpenAPI springShopOpenAPI() {
return new OpenAPI()
.info(new Info().title("SpringShop API")
.description("Spring shop sample application")
.version("v0.0.1")
.license(new License().name("Apache 2.0").url("http://springdoc.org")))
.externalDocs(new ExternalDocumentation()
.description("SpringShop Wiki Documentation")
.url("https://springshop.wiki.github.org/docs"));
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 分组使用
当有很多的接口时候,我们可以针对接口进行分组,比如登录的接口是一组,对商品的增删改查是一组。
下面模拟定义两个组:public、Admin
@Bean
public Docket publicApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("org.github.springshop.web.public"))
.paths(PathSelectors.regex("/public.*")) // 所有带有 /public 前缀的为一组
.build()
.groupName("springshop-public") // 组名
.apiInfo(apiInfo()); // apiInfo() 为该组的基本信息
}
@Bean
public Docket adminApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("org.github.springshop.web.admin"))
.paths(PathSelectors.regex("/admin.*")) // 所有带有 /admin 前缀的为一组
.apis(RequestHandlerSelectors.withMethodAnnotation(Admin.class))
.build()
.groupName("springshop-admin")
.apiInfo(apiInfo());
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 实战整合 Swagger、knife4j
针对实际项目的配置,可以将其封装成一个 started。
该整合可以使用 Swagger 的 UI,也可以使用 knife4j 的新 UI。
# pom.xml
<dependencies>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.2.11</version>
</dependency>
<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
# 属性配置类
属性配置类将配置的信息抽离到 application.yml,如作者、版本等信息,不需要在代码写死。
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@ConfigurationProperties("swagger")
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;
}
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
# 核心配置类
该类加载文档的基本信息、权限、分组等。
@Configuration
@ConditionalOnClass({OpenAPI.class})
@EnableConfigurationProperties(SwaggerProperties.class)
@ConditionalOnProperty(prefix = "springdoc.api-docs", name = "enabled", havingValue = "true", matchIfMissing = true)
public class SpringDocAutoConfiguration {
@Bean
public OpenAPI createApi(SwaggerProperties properties) {
Map<String, SecurityScheme> securitySchemas = buildSecuritySchemes();
OpenAPI openAPI = new OpenAPI()
// 接口信息
.info(buildInfo(properties))
// 接口安全配置
.components(new Components().securitySchemes(securitySchemas));
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());
}
/**
* 安全模式,这里配置通过请求头 Authorization 传递 token 参数
*/
private Map<String, SecurityScheme> buildSecuritySchemes() {
Map<String, SecurityScheme> securitySchemes = new HashMap<>();
SecurityScheme securityScheme = new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.name(HttpHeaders.AUTHORIZATION)
.scheme("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);
}
// ========== 分组 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("/" + path + "/**")
.addOperationCustomizer((operation, handlerMethod) -> operation
.addParametersItem(buildSecurityHeaderParameter()))
.build();
}
/**
* 构建 Authorization 认证请求头参数
* <p>
* 解决 Knife4j <a href="https://gitee.com/xiaoym/knife4j/issues/I69QBU">Authorize 未生效,请求header里未包含参数</a>
*
* @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
该项目内置了所有的接口作为一组。如果想为某些接口为一组,则
public class Test {
@Autowired
private SpringDocAutoConfiguration springDocAutoConfiguration;
@Bean
public GroupedOpenApi createGroup() {
return springDocAutoConfiguration.buildGroupedOpenApi("api");
}
}
2
3
4
5
6
7
8
9
这样所有前缀为 /api
的作为一组。
# application 配置信息
# ====== springdoc 配置 ====== #
springdoc:
api-docs:
enabled: true # 启用文档
path: /v3/api-docs
swagger-ui:
enabled: true
path: /swagger-ui
# ===== swagger 配置 =====#
swagger:
title: Youngkbt 开发平台
description: 提供管理后台、用户 App 的所有功能
version: 1.0.0
2
3
4
5
6
7
8
9
10
11
12
13
# 最终访问
/v3/api-docs
返回接口文档的 JSON 数据/doc.html
进入 knife4j 的 UI 页面/swagger-ui
进入 Swagger 的 UI 页面
# 常用注解
注解 | 标注位置 | 作用 |
---|---|---|
@Tag | controller 类 | 标识 controller 作用 |
@Parameter | 参数 | 标识参数作用 |
@Parameters | 参数 | 参数多重说明 |
@Schema | model 层的 JavaBean | 描述模型作用及每个属性 |
@Operation | 方法 | 描述方法作用 |
@ApiResponse | 方法 | 描述响应状态码等 |
如:
DTO
@Data
public class CustomizedWaveDTO {
@Schema(name = "id")
private Long id;
@Schema(name = "sensorId")
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
Controller
@RestController
@RequestMapping("/api/customizedWave")
@Tag(name = "自定义波形")
public class CustomizedWaveController {
@Resource
private CustomizedWaveService customizedWaveService;
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
@Operation(summary = "通过id获取自定义配置", description = "通过id获取自定义配置")
public CustomizedWaveDTO getCustomizedWave(@PathVariable("id") Long id) {
return customizedWaveService.findById(id);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# Springfox 迁移
如果之前使用了 Swagger 2,则下面是注解变化对比:
原注解 | 现注解 | 作用 |
---|---|---|
@Api | @Tag | 描述 Controller |
@ApiIgnore | @Parameter(hidden = true) @Operation(hidden = true) @Hidden | 描述忽略操作 |
@ApiImplicitParam | @Parameter | 描述参数 |
@ApiImplicitParams | @Parameters | 描述参数 |
@ApiModel | @Schema | 描述对象 |
@ApiModelProperty(hidden = true) | @Schema(accessMode = READ_ONLY) | 描述对象属性 |
@ApiModelProperty | @Schema | 描述对象属性 |
@ApiOperation(value = "foo", notes = "bar") | @Operation(summary = "foo", description = "bar") | 描述方法 |
@ApiParam | @Parameter | 描述参数 |
@ApiResponse(code = 404, message = "foo") | @ApiResponse(responseCode = "404", description = "foo") | 描述响应 |