SpringDoc的使用
概述
OpenApi是一个用于描述、定义和共享 RESTful API文档的规范,目前最新规范是OpenAPI 3.0。
Swagger是一个用于设计和测试RESTful API的工具。它提供了API描述、请求和响应示例、API测试和文档生成等丰富的功能。目前最新版本是Swagger3,支持OpenAPI3.0规范。
OpenAPI定义一种标准的格式来表示API文档,而Swagger是一个实现OpenAPI规范的工具。
SpringFox和SpringDoc是Spring社区维护的一个非官方项目,分别帮助开发者将Swagger 2、Swagger 3集成到Spring中。SpringFox已经很久没有更新,因此SpringDoc无疑是更好的选择。
SpringDoc项目由以下各个模块构成,不同模块具有不同的功能。
Swagger官网:https://swagger.io/
SpringFox项目:https://github.com/springfox/springfox
SpringDoc项目:https://github.com/springdoc/springdoc-openapi
SpringDoc文档:https://springdoc.org/
SpringDoc
SpringDoc 是一个用于生成 OpenAPI 文档的库,特别适用于 Spring Boot 应用程序。
添加依赖
如果使用 Maven,可以在 pom.xml 中添加以下依赖:
<!-- springdoc -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.7.0</version>
</dependency>
如果使用 Gradle,可以在 build.gradle 中添加:
implementation 'org.springdoc:springdoc-openapi-ui:1.7.0'
配置 Springdoc
在Spring Boot 应用程序中,通常不需要额外配置,Springdoc会自动扫描控制器和模型。可以在 application.properties
或application.yml
中进行一些基本配置,例如:
# Docs API配置
springdoc:
swagger-ui:
# API文档, 默认路径:swagger-ui/index.html, 通过http://localhost:8080/docs/index.html访问
path: /docs/index.html
# 开启Swagger UI界面
enabled: true
# 根据HTTP方法对API路径进行排序
operations-sorter: method
api-docs:
# OpenAPI的路径描述,默认路径:/v3/api-docs, 通过http://localhost:8080/docs/api访问文档描述
# OpenAPI描述定义默认为JSON格式, 通过http://localhost:8080/docs/api.yaml获取yaml格式
path: /docs/api
# 开启api-docs
enabled: true
# 配置需要生成接口文档的扫描包路径
packages-to-scan: cn.ybzy.demo
# 配置需要生成接口文档的接口路径
paths-to-match: /test/**,/user/**
创建 REST 控制器
创建一个简单的 REST 控制器,Springdoc会自动生成对应的 API 文档。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/test")
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, World!";
}
}
访问 API 文档
启动Spring Boot 应用程序后,可以通过以下URL访问生成的 API 文档:
1.访问Swagger UI: http://localhost:8080/docs/index.html
2.访问OpenAPI 文档: http://localhost:8080/docs/api
访问 http://localhost:8080/docs/api.yaml
获取yaml格式的文件
添加注释和描述
可以使用注解来添加更多信息,例如使用@Tag、@Operation、@ApiResponse
等来描述API:
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "测试API接口", description = "这是一个关于测试API接口的描述")
@RequestMapping("/test")
@RestController
public class HelloController {
@Operation(summary = "获取问候信息", description = "返回一个简单的问候信息")
@ApiResponse(responseCode = "200", description = "成功")
@GetMapping("/hello")
public String hello() {
return "Hello, World!";
}
}
查看Swagger UI:
查看OpenAPI 文档:
自定义配置
可以创建一个配置类来自定义 Springdoc 的行为:设置标题、描述和版本等。还可以对API进行分组:按模块、按功能划分API。
@Configuration
public class OpenApiConfig {
/**
* 配置自定义的 OpenAPI 规范
* 通过 @Bean 注解声明该方法返回一个 Spring Bean,该 Bean 是一个 OpenAPI 对象
* 该方法允许通过 Spring Context 初始化 OpenAPI 对象,并自定义 API 的标题、版本、描述等信息
*
* @return 自定义的 OpenAPI 对象
*/
@Bean
public OpenAPI customOpenAPI() {
// 创建并配置 OpenAPI 对象
return new OpenAPI()
.info(new Info()
.title("我的 API") // 设置 API 标题
.version("v0.0.1") // 设置 API 版本
.description("这是一个示例 API") // 设置 API 描述
.license(new License().name("Apache 2.0").url("http://example.com")) // 设置 API 的许可证信息,包括许可证名称和 URL
.contact(new Contact()
.name("开发者") // 设置联系人名称
.url("http://example.com") // 设置联系人的 URL
.email("developer@example.com"))) // 设置联系人的电子邮件地址
.externalDocs(new ExternalDocumentation()
.description("外部文档的描述") // 设置外部文档的描述
.url("http://example.com")); // 设置外部文档的 URL
}
/**
* 配置并返回一个GroupedOpenApi实例,用于指定一组API接口
*
* @return GroupedOpenApi实例,配置了组名为"test",匹配路径为"/test/**"的接口
*/
@Bean
public GroupedOpenApi testApi() {
return GroupedOpenApi.builder()
.group("test") // 设置组名
.pathsToMatch("/test/**") // 设置需要匹配的路径模式
.build();
}
}
查看Swagger UI:
查看OpenAPI 文档:
还可以在配置文件中配置分组信息
# Docs API配置
springdoc:
swagger-ui:
path: /docs/index.html
enabled: true
group-configs:
- group: '测试1'
paths-to-match: /test/**
- group: '测试2'
paths-to-match: /test/**
常用注解
注解 | 描述 |
---|---|
@Tag | 为一组 API 操作添加标签,便于在文档中组织和分组。 |
@Operation | 描述一个 API 操作,包括摘要和详细描述。 |
@Parameter | 描述方法参数,包括路径变量、请求体和查询参数。 |
@Schema | 描述数据模型的属性和结构,通常用于模型类或 API 方法的参数和返回值。 |
@ApiResponse | 描述单个 HTTP 响应状态码的详细信息。 |
@ApiResponses | 描述多个 HTTP 响应状态码的详细信息。 |
@RequestBody | 指定请求体的内容类型和结构。 |
@Content | 描述响应内容的类型和格式。 |
@SecurityRequirement | 描述 API 操作所需的安全要求,例如认证和授权。 |
@Hidden | 指定某个 API 操作或模型在文档中隐藏。 |
@Deprecated | 表示某个 API 操作或模型已被弃用。 |
@ArraySchema | 描述数组类型的响应内容,通常用于返回列表。 |
@ExampleObject | 提供示例对象,用于 API 文档中展示请求或响应的示例。 |
@MediaType | 指定请求或响应的媒体类型。 |
@Link | 描述 API 之间的链接关系。 |
@ParameterObject | 描述复合参数对象,通常用于请求体中的复杂结构。 |
详细示例
创建一个更详细、简单的图书管理API REST控制器示例,展示如何使用Springdoc 生成 API 文档的同时,处理不同的 HTTP 方法和请求参数。
创建模型类
首先,定义一个图书模型类 Book:
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
@Schema(description = "图书信息")
public class Book {
@Schema(description = "图书ID", example = "1")
private Long id;
@Schema(description = "图书标题", example = "Spring Boot 入门")
private String title;
@Schema(description = "图书作者", example = "张三")
private String author;
}
创建REST控制器
接下来,创建一个 BookController 控制器,提供 CRUD 操作:
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@Tag(name = "图书管理API接口", description = "这是一个关于图书管理API接口的描述")
@RestController
@RequestMapping("/books")
public class BookController {
private final List<Book> books = new ArrayList<>();
@Operation(summary = "获取所有图书", description = "返回图书列表", method = "GET")
@ApiResponse(responseCode = "200", description = "成功", content = @Content(mediaType = "application/json", schema = @Schema(implementation = Book.class)))
@GetMapping
public List<Book> getAllBooks() {
return books;
}
@Operation(summary = "根据ID获取图书", description = "通过图书ID获取图书信息", method = "GET")
@ApiResponse(responseCode = "200", description = "成功")
@ApiResponse(responseCode = "404", description = "未找到图书")
@GetMapping("/{id}")
public Book getBookById(@Parameter(description = "图书ID", required = true) @PathVariable Long id) {
return books.stream()
.filter(book -> book.getId().equals(id))
.findFirst()
.orElse(null);
}
@Operation(summary = "添加新图书", description = "创建新的图书记录", method = "POST")
@ApiResponse(responseCode = "201", description = "图书创建成功")
@PostMapping
public Book createBook(@Parameter(description = "图书信息", required = true) @RequestBody Book book) {
books.add(book);
return book;
}
@Operation(summary = "更新图书信息", description = "根据ID更新图书信息", method = "PUT")
@ApiResponse(responseCode = "200", description = "图书更新成功")
@ApiResponse(responseCode = "404", description = "未找到图书")
@PutMapping("/{id}")
public Book updateBook(@Parameter(description = "图书ID", required = true) @PathVariable Long id,
@Parameter(description = "图书信息", required = true) @RequestBody Book updatedBook) {
for (int i = 0; i < books.size(); i++) {
if (books.get(i).getId().equals(id)) {
books.set(i, updatedBook);
return updatedBook;
}
}
return null; // 或者抛出异常
}
@Operation(summary = "删除图书", description = "根据ID删除图书", method = "DELETE")
@ApiResponse(responseCode = "204", description = "图书删除成功")
@ApiResponse(responseCode = "404", description = "未找到图书")
@DeleteMapping("/{id}")
public void deleteBook(@Parameter(description = "图书ID", required = true) @PathVariable Long id) {
books.removeIf(book -> book.getId().equals(id));
}
}
查看Swagger UI与OpenAPI
1.查看Swagger UI:
查看Book对象的Schema信息:
2.查看OpenAPI 文档:
安全策略类型
概述
在OpenAPI规范中,安全策略类型(SecurityScheme.Type)用于定义API的认证机制。SpringDoc通过SecurityScheme类来配置这些认证机制。
安全策略类型有以下几种:
HTTP
用于基于HTTP的认证机制,如Basic Auth或Bearer Token。
例如,Bearer Token认证用于JWT令牌认证。
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info().title("API Documentation").version("v1"))
.addSecurityItem(new SecurityRequirement().addList("bearerAuth"))
.components(new io.swagger.v3.oas.models.Components()
.addSecuritySchemes("bearerAuth",
new SecurityScheme().type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")
.in(SecurityScheme.In.HEADER)
.name("Authorization")));
}
APIKEY
用于通过API密钥进行认证。
API密钥可以在请求头、查询参数或cookie中传递。
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info().title("API Documentation").version("v1"))
.addSecurityItem(new SecurityRequirement().addList("apiKeyAuth"))
.components(new io.swagger.v3.oas.models.Components()
.addSecuritySchemes("apiKeyAuth",
new SecurityScheme().type(SecurityScheme.Type.APIKEY)
.in(SecurityScheme.In.HEADER)
.name("token")));
}
OAUTH2
用于OAuth2认证。
适用于需要授权码、客户端凭证、密码或隐式授权的应用程序。
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info().title("API Documentation").version("v1"))
.addSecurityItem(new SecurityRequirement().addList("oauth2Auth"))
.components(new io.swagger.v3.oas.models.Components()
.addSecuritySchemes("oauth2Auth",
new SecurityScheme().type(SecurityScheme.Type.OAUTH2)
.flows(new OAuthFlows()
.authorizationCode(new OAuthFlow()
.authorizationUrl("https://example.com/oauth/authorize")
.tokenUrl("https://example.com/oauth/token")))));
}
OPENIDCONNECT
用于OpenID Connect认证。
扩展了OAuth2,增加了身份认证层。
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info().title("API Documentation").version("v1"))
.addSecurityItem(new SecurityRequirement().addList("openIdAuth"))
.components(new io.swagger.v3.oas.models.Components()
.addSecuritySchemes("openIdAuth",
new SecurityScheme().type(SecurityScheme.Type.OPENIDCONNECT)
.openIdConnectUrl("https://example.com/.well-known/openid-configuration")));
}
MUTUALTLS
用于安全性要求较高的环境中认证。
客户端和服务器双方都需要提供证书以验证彼此的身份。
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info().title("API Documentation").version("v1"))
.addSecurityItem(new SecurityRequirement().addList("mutualTLS"))
.components(new io.swagger.v3.oas.models.Components()
.addSecuritySchemes("mutualTLS",
new SecurityScheme().type(Type.MUTUALTLS)));
}
}
请求头配置认证token
如果项目中所有接口的认证是通过请求头中包含一个认证Token,那么如何通过SpringDoc的配置来全局定义这个Token作为安全要求呢?以下是如何在SpringDoc中配置全局的认证Token的步骤。
代码实现
配置类通过OpenAPI bean添加了一个全局的请求头,名为token。当访问生成的API文档(例如:http://localhost:8080/swagger-ui.html)时,所有接口都会包含这个token请求头。
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
// 定义组件,包括安全方案
.components(new Components()
// 在安全方案中添加"token",用于认证
.addSecuritySchemes("TokenAuth",
// 创建一个新的HTTP安全方案
new SecurityScheme()
// 设置安全方案的名称为"BearerAuth"
.name("token")
// 指定认证方案的作用域为请求头(HEADER)
.in(SecurityScheme.In.HEADER)
// 指定安全方案的类型为HTTP
.type(SecurityScheme.Type.APIKEY)));
}
}
验证
查看Swagger UI:
可以看到多了一个授权的按钮,输入获取到的认证Token,点击Authorize之后,发送的请求都会自动在请求头中加上字段为token,值为输入值,从而实现了接口的认证。
Springdoc和Spring Security集成
在使用 Spring Security 的项目中,配置 Springdoc 以支持安全性(如 JWT 认证)通常涉及到几个步骤。
添加依赖
确保在 pom.xml
或 build.gradle
中添加Spring Security 和 Springdoc 的依赖。
Maven 示例:
<!-- springdoc -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.7.0</version>
</dependency>
<!-- security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Gradle 示例:
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springdoc:springdoc-openapi-ui:1.7.0'
配置Spring Security
创建一个 Spring Security 配置类,设置基本的安全规则。以下是一个简单的示例:配置一个默认认证用户,允许所有用户访问 Swagger UI 和 API 文档,但需要认证才能访问其他 API。
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
/**
* 配置认证管理器,定义内存中的用户认证
*
* @param auth AuthenticationManagerBuilder实例,用于构建认证管理器
* @throws Exception 配置过程中可能出现的异常
*/
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 设置内存中的用户认证
auth.inMemoryAuthentication()
// 创建一个用户名为"admin"的用户
.withUser("admin")
// 设置密码为"admin123",并使用"{noop}"标记表示密码不加密
.password("{noop}admin123")
// 赋予该用户"ADMIN"角色
.roles("ADMIN");
}
@Override
/**
* 配置 Spring Security
* @param http HttpSecurity 对象,用于配置与 HTTP 安全相关的设置
* @throws Exception 配置过程中可能抛出的异常
*/
protected void configure(HttpSecurity http) throws Exception {
// 根据需要禁用 CSRF
http.csrf().disable()
// 配置请求的授权规则
.authorizeRequests()
// 允许无需认证即可访问 Swagger UI 和 API 文档
// 这里注释了springdoc的yml配置,使用默认路径
.antMatchers(
"/v3/api-docs/**",
"/swagger-ui.html",
"/swagger-ui/**")
.permitAll()
// 其他所有请求都需要经过认证
.anyRequest().authenticated()
// 使用 HTTP Basic 认证,或根据需要配置其他认证方式
.and().httpBasic();
}
}
配置Springdoc以支持安全性
在 SpringDoc 中,@SecurityRequirement 注解用于为 OpenAPI 文档中的特定 API 操作指定安全要求。这通常用于定义需要特定认证机制(例如 JWT、OAuth2 等)的 API。
@RestController
public class BookController {
@Operation(summary = "获取所有图书", security = @SecurityRequirement(name = "bearerAuth"))
@GetMapping("/books")
public List<Book> getAllBooks() {
}
}
通过全局配置来一次性设置所有接口的安全要求,而不需要在每个接口上单独配置 @SecurityRequirement 注解。在OpenAPI对象中通过addSecurityItem方法和SecurityScheme对象,启用基于JWT的认证功能。
/**
* 配置自定义的 OpenAPI 规范
* 通过 @Bean 注解声明该方法返回一个 Spring Bean,该 Bean 是一个 OpenAPI 对象
* 该方法允许通过 Spring Context 初始化 OpenAPI 对象,并自定义 API 的标题、版本、描述等信息
*
* @return 自定义的 OpenAPI 对象
*/
@Bean
public OpenAPI customOpenAPI() {
// 创建并配置 OpenAPI 对象
return new OpenAPI()
.info(new Info()
.title("我的 API") // 设置 API 标题
.version("v0.0.1") // 设置 API 版本
.description("这是一个示例 API") // 设置 API 描述
.license(new License().name("Apache 2.0").url("http://example.com")) // 设置 API 的许可证信息,包括许可证名称和 URL
.contact(new Contact()
.name("开发者") // 设置联系人名称
.url("http://example.com") // 设置联系人的 URL
.email("developer@example.com"))) // 设置联系人的电子邮件地址
.externalDocs(new ExternalDocumentation()
.description("外部文档的描述") // 设置外部文档的描述
.url("http://example.com")) // 设置外部文档的 URL
// 添加安全需求项,指定使用"BearerAuth"安全方案
.addSecurityItem(new SecurityRequirement().addList("BearerAuth"))
// 定义组件,包括安全方案等
.components(new Components()
// 在安全方案中添加"BearerAuth",用于认证
.addSecuritySchemes("BearerAuth",
// 创建一个新的HTTP安全方案
new SecurityScheme()
// 设置安全方案的名称为"BearerAuth"
.name("BearerAuth")
// 指定安全方案的类型为HTTP
.type(SecurityScheme.Type.HTTP)
// 设置认证方式为"bearer"
.scheme("bearer")
// 指定bearer token的格式为JWT
.bearerFormat("JWT")));
}
验证
访问:http://localhost:8080/swagger-ui/index.html
,查看Swagger UI:
可以看到多了一个授权的按钮,输入获取到的认证头信息,然后就可以访问需要登录认证的接口了,需注意不要加bearer前缀