前言
关于 Swagger 和 OpenAPI 的介绍,请看我的另一篇文章:Spring Boot 中使用 SpringFox 整合 Swagger 3(OpenAPI 3)生成 API 文档 ,文章有介绍 Swagger 和 OpenAPI 和 Swagger 3(OpenAPI 3)的新注解介绍及使用方法,也建议你阅读本文前先去看看。
本文仅介绍在 Spring Boot 中使用 Springdoc 整合 Swagger 3.0(OpenAPI 3)。
示例代码已上传到 Github:spring-boot-springdoc-swagger3
springdoc-openapi 介绍
springdoc-openapi java 库可助于我们在 Spring Boot 项目自动生成 API 文档。springdoc-openapi 通过在运行时检查应用程序来根据 Spring 配置、类结构和各种注释推断 API 语义,自动生成 JSON/YAML 和 HTML 格式的 API 文档。
springdoc-openapi 支持:
- OpenAPI 3
- Spring Boot (v1 and v2)
- 支持 JSR-303 校验规范,如
@NotNull
,@Min
,@Max
,@Size
等注解 - swagger-ui
- OAuth 2
- GraalVM 原生镜像
Swagger 3.0(Open API 3.0)注解介绍
关于注解的介绍请看我的另一篇文章 Spring Boot 中使用 SpringFox 整合 Swagger 3(OpenAPI 3)生成 API 文档 ,里面有详细的介绍和示例代码,这里就不过多赘述了。
使用
添加依赖
编辑 pom.xml
文件,添加依赖:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.5.9</version>
</dependency>
这将自动把 swagger-ui 部署到 Spring Boot 应用中:
- 文档将以 HTML 格式展示,使用官方 swagger-ui jars
- Swagger UI 页面将通过
http://server:port/context-path/swagger-ui.html
访问 - OpenAPI 描述将通过
http://server:port/context-path/v3/api-docs
访问,提供 JSON 格式 - 文档提供
yaml
格式,位于以下路径:/v3/api-docs.yaml
启动项目后,使用浏览器访问:http://localhost/swagger-ui.html 就能看到 Swagger UI 展示的 API 文档。
添加 Swagger 配置
新增配置类 SwaggerConfig
,用于配置全局 API 文档信息:
@OpenAPIDefinition(
tags = {
@Tag(name = "用户管理", description = "用户模块操作"),
@Tag(name = "角色管理", description = "角色模块操作")
},
info = @Info(
title = "用户接口 API 文档",
description = "用户数据管理......",
version = "1.0.0",
contact = @Contact(name = "lanweihong", email = "986310747@qq.com", url = "https://www.lanweihong.com"),
license = @License(name = "Apache 2.0", url = "http://www.apache.org/licenses/LICENSE-2.0.html")
),
servers = {
@Server(description = "生产环境服务器", url = "https://xxxx.com/api/v1"),
@Server(description = "测试环境服务器", url = "https://test.xxxx.com/api/v1")
},
security = @SecurityRequirement(name = "Oauth2"),
externalDocs = @ExternalDocumentation(
description = "项目编译部署说明",
url = "http://localhost/deploy/README.md"
)
)
@Configuration
public class SwaggerConfig {
}
添加 Controller
编写 Controller:
@Tag(name = "用户管理", description = "用户数据增删改查")
@RestController
@RequestMapping("/api/users")
public class UserController {
@Operation(summary = "查询用户列表", description = "返回所有用户数据")
@GetMapping("")
public JsonResult<List<UserVO>> getUserList(@Parameter(description = "用户名") @RequestParam(value = "username", required = false) String userName) {
List<UserVO> result = new ArrayList<>();
// TODO
return JsonResult.ok(result);
}
@Operation(summary = "通过用户名查询用户", description = "根据用户名查询用户详细信息")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "请求成功"),
@ApiResponse(responseCode = "404", description = "用户不存在", content = @Content)
})
@GetMapping("/{username}")
public JsonResult<UserVO> getUserByName(@Parameter(description = "用户名", required = true) @PathVariable("username") String userName) {
// TODO
return JsonResult.ok();
}
@Operation(summary = "新增用户")
@PostMapping("")
public JsonResult<UserVO> addUser(@Parameter(required = true) @Valid @RequestBody UserParam param) {
// TODO
return JsonResult.ok();
}
@Operation(summary = "修改用户")
@PutMapping("")
public JsonResult<UserVO> updateUser(@Parameter(description = "用户参数", required = true) @Valid @RequestBody UserParam param) {
// TODO
return JsonResult.ok();
}
@Operation(summary = "删除用户")
@DeleteMapping("/{username}")
public JsonResult<UserVO> deleteUserByName(@Parameter(name = "username", in = ParameterIn.PATH, description = "用户名", required = true) @PathVariable("username") String userName) {
// TODO
return JsonResult.ok();
}
@Operation(summary = "测试新增用户接口", hidden = true)
@PostMapping("/test")
@Hidden
public JsonResult<UserVO> testAddUser(@Parameter(required = true) @Valid @RequestBody UserParam param) {
// TODO
return JsonResult.ok();
}
}
添加相关 POJO
添加
UserParam
,用于接收前端参数:@Getter @Setter @Schema(description = "用户参数实体") public class UserParam { @NotBlank(message = "用户名不能为空") @Schema(description = "用户名") private String userName; @Schema(name = "roles", description = "角色id列表") @NotNull(message = "角色id列表不能为空") @Size(min = 1) private Set<String> roleList; @NotBlank(message = "密码不能为空") @Schema(description = "密码,6-18位,包含大小写、数字及特殊字符") @Size(min = 6, max = 18) private String password; @Schema(example = "zhangsan@lanweihong.com", description = "邮箱") private String email; @Schema(description = "年龄") @Min(value = 1, message = "最小年龄为1") @Max(value = 150, message = "最大年龄为150") private Integer age; }
这里 UserParam
使用 JSR-303 Bean Validation 注解来校验参数,springdoc-openapi 会帮我们生成相应的说明信息,如下图:
全局异常处理
新增全局异常处理类 GlobalExceptionHandler
:
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(InvalidParameterException.class)
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
public JsonResult<String> bindInvalidParameterExceptionHandler(InvalidParameterException e) {
log.error("错误的请求,参数无效:", e);
return JsonResult.error(e.getMessage());
}
@ResponseStatus(code = HttpStatus.BAD_REQUEST)
@ExceptionHandler(value = BadRequestException.class)
public JsonResult<String> bindBadRequestExceptionHandler(BadRequestException e) {
log.error("错误的请求:", e);
return JsonResult.error(e.getError());
}
@ResponseStatus(code = HttpStatus.NOT_FOUND)
@ExceptionHandler(value = NotFoundException.class)
public JsonResult<String> bindNotFoundExceptionHandler(NotFoundException e) {
log.error("资源未找到:", e);
return JsonResult.error(e.getError());
}
// 其他异常处理......
}
分组
- 可以在通过配置
application.yml
来设置分组:
springdoc:
# 分组配置
group-configs:
- group: All
packagesToScan: com.lanweihong.springdoc.swagger.controller
pathsToMatch: /api/**
- group: User
packagesToScan: com.lanweihong.springdoc.swagger.controller.user
pathsToMatch: /api/users/**
- group: Role
packagesToScan: com.lanweihong.springdoc.swagger.controller.role
pathsToMatch: /api/roles/**
也可以在配置类中添加
GroupedOpenApi
:@Configuration public class SwaggerConfig { @Bean public GroupedOpenApi userApi() { return GroupedOpenApi.builder() .group("User") .pathsToMatch("/api/users/**") .build(); } @Bean public GroupedOpenApi roleApi() { return GroupedOpenApi.builder() .group("Role") .pathsToMatch("/api/roles/**") .build(); } }
注意:这两个方法只能选择一种来配置,比如在 application.yml
配置了就不要再通过代码添加 GroupedOpenApi
,否则会报错,除非你设置的 group 不一样。
- 为特定组设置自定义的 API 文档信息
在以上的 SwaggerConfig
配置类中,我们使用 @OpenAPIDefinition
来设置全局的 API 文档信息。但有时,我们想切换到某个组(group)的时候,API 文档信息显示关于这个组的相关信息,而显示全局的信息。这时,我们可以定义一个 OpenApiCustomiser
添加到 GroupedOpenApi
中:
@Configuration
public class SwaggerConfig {
@Bean
public GroupedOpenApi userApi() {
return GroupedOpenApi.builder()
.group("User")
// 指定路径
.pathsToMatch("/api/users/**")
// 指定特定的 API 文档信息
.addOpenApiCustomiser(userApiCustomiser())
.build();
}
/**
* 定义 OpenApiCustomiser ,用于指定的 group
* @return
*/
public OpenApiCustomiser userApiCustomiser() {
return openApi -> openApi.info(new io.swagger.v3.oas.models.info.Info()
.title("用户管理 API 文档")
.description("实现对用户数据的增删改查等操作")
.version("1.0")
.contact(new io.swagger.v3.oas.models.info.Contact().name("lanweihong").email("986310747@qq.com")));
}
}
在 Swagger UI 中看到 User 组的文档信息已更新显示,不再是全局的文档信息。
测试
启动项目,访问 http://localhost:8080/swagger-ui.html 访问 Swagger UI。
主页面:
请求接口描述:
分组:
实体类描述:
至此,Spring Boot 中使用 Springdoc 整合Swagger 3(OpenAPI 3)的介绍已完成。
总结
本文仅介绍常用的注解用法及配置,想要了解更多的用法请查看官方文档:OpenAPI 3 Library for spring-boot 。
使用到的代码已上传到 Github:spring-boot-springdoc-swagger3