基于SpringBoot3.3.x版本③集成Springdoc
摘要
在微服务开发过程中,后端同学会写各种API
,每写一个API
,都需要相应的API
文档,前端同学需要根据API
文档进行开发、联调,其它后端同学也需要通过API
文档了解系统设计以及方便排查问题。
关于API
文档的工具有很多,比如常用的Swagger
、Apifox
等等,本文主要介绍Springdoc
开源库,它与Spring Boot
框架体系的集成更显丝滑。
本着"最新"原则,这篇文章依然采用最新版的Spring Boot 3.3.4
,最新版springdoc-openapi-starter 2.6.0
,最新版springdoc-openapi 1.8.0
,OpenJDK
最新LTS
版21
,IntelliJ IDEA
最新社区版2024.2.3
。
本地开发环境说明
开发用到的主要框架、工具版本如下
开发依赖 | 版本 |
---|---|
Spring Boot | 3.3.4 |
springdoc-openapi-starter | 2.6.0 |
springdoc-openapi | 1.8.0 |
JDK | 21 |
IntelliJ IDEA | 2024.2.3 |
pom.xml
- 如果依赖
spring-boot-starter-web
并且需要访问swagger-ui
,则引入springdoc-openapi-starter-webmvc-ui
- 如果依赖
spring-boot-starter-web
并且只需要访问OpenAPI endpoints
,则引入springdoc-openapi-starter-webmvc-api
- 如果依赖
spring-boot-starter-webflux
并且需要访问swagger-ui
,则引入springdoc-openapi-starter-webflux-ui
- 如果依赖
spring-boot-starter-webflux
并且只需要访问OpenAPI endpoints
,则引入springdoc-openapi-starter-webflux-api
pom
依赖如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.4</version>
<relativePath/>
</parent>
<artifactId>wen3-framework-apidoc-springdoc-demo</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
</dependencies>
</project>
如果要把actuator
加入swagger
文档,则增加以下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
如果要把Javadoc
生成swagger
文档,则增加以下依赖
<!-- 从Javadoc注释生成Swagger文档 -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-javadoc</artifactId>
<version>${springdoc-openapi-javadoc.version}</version>
<!--包含依赖 :therapi-runtime-javadoc-->
</dependency>
Controller演示类
为了演示API分组的效果,在3个不同的包下新建3个不同的Controller类
- com.wen3.springdoc.demo.controller.DemoController
package com.wen3.springdoc.demo.controller;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* @author tangheng
*/
@Slf4j
@RestController
public class DemoController {
@Autowired
private HttpServletRequest request;
@Operation(summary = "示例",description = "示例描述")
@RequestMapping(path = "/demo", method = RequestMethod.GET)
public String demo(String name) {
return "Hello," + name;
}
}
- com.wen3.springdoc.demo.controller2.DemoController2
package com.wen3.springdoc.demo.controller2;
import com.wen3.springdoc.demo.dto.UserDemo;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* @author tangheng
*/
@Slf4j
@RestController
public class DemoController2 {
@Autowired
private HttpServletRequest request;
@Operation(summary = "示例",description = "示例描述")
@RequestMapping(path = "/demo2", method = RequestMethod.POST)
public String demo2(@RequestBody UserDemo userDemo) {
return "Hello," + userDemo.getName();
}
}
- com.wen3.springdoc.demo.controller3.DemoController3
package com.wen3.springdoc.demo.controller3;
import com.wen3.springdoc.demo.dto.UserDemo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.Enumeration;
/**
* @author tangheng
*/
@Slf4j
@RestController
public class DemoController3 {
@Autowired
private HttpServletRequest request;
/**
* Javadoc描述
* @param userDemo 用户对象
* @return 字符串
*/
@Operation(summary = "演示说明1", description = "演示说明2", security={@SecurityRequirement(name = "xxx")})
@RequestMapping(path = "/demo3", method = RequestMethod.POST)
public String demo3(@RequestBody UserDemo userDemo) {
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
log.info("{}:{}", headerName, request.getHeader(headerName));
}
return "Hello," + userDemo.getName();
}
}
OpenAPI配置类
为了演示在swagger-ui
界面上测试API
的时候增加鉴权的效果,配置时增加了安全认证
package com.wen3.springdoc.demo.autoconfigure;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
import io.swagger.v3.oas.models.ExternalDocumentation;
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 org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
/**
* @author tangheng
*/
@OpenAPIDefinition(
security = @SecurityRequirement(name = "Authorization")
)
@SecurityScheme(type = SecuritySchemeType.HTTP, name = HttpHeaders.AUTHORIZATION, scheme = "bearer", bearerFormat="JWT", in = SecuritySchemeIn.HEADER)
@SecurityScheme(type = SecuritySchemeType.HTTP, name = "xxx", scheme = "bearer", bearerFormat="JWT", in = SecuritySchemeIn.HEADER)
@Configuration
public class SpringDocAutoConfiguration {
@Bean
public OpenAPI openAPI(){
return new OpenAPI()
.info(apiInfo())
.externalDocs(new ExternalDocumentation()
.description("SpringDoc Wiki Documentation")
.url("https://springdoc.org/v2"))
;
}
private Info apiInfo() {
return new Info()
.title("Wen3 Demo API Doc")
.description("springfox swagger 3.0 demo")
.version("1.0.0")
.contact(new Contact()
.name("demo")
.url("www.demo.com")
.email("demo@demo.com")
)
.license(new License()
.name("Apache 2.0")
.url("http://www.apache.org/licenses/LICENSE-2.0.txt")
);
}
}
程序配置
Springdoc
支持Swagger
官方配置,可参考:https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/
使用前缀:
springdoc.swagger-ui
api-docs
相关的配置使用前缀springdoc.api-docs
- 配置文件示例如下
server:
port: 7001
######## swagger configuration ###############
springdoc:
#如果不需要分组,就使用packages-to-scan:
# packages-to-scan: ##需要扫描的包,可以配置多个
# - com.wen3.springdoc.demo.controller
# - com.wen3.springdoc.demo.controller2
# - com.wen3.springdoc.demo.controller3
paths-to-exclude: ##配置不包含在swagger文档中的api
- /api/test/**
- /api/mockito/data
swagger-ui:
enabled: true #开启/禁止swagger,prod可以设置为false
# swagger-ui custom path
path: /swagger-ui.html
display-request-duration: true # 展示请求所耗时间ms
operations-sorter: method #api排序方式 alpha 字母 method http方法
groups-order: desc # 排序顺序
disable-swagger-default-url: true #禁用swagger-ui默认的petstore网址 默认就是swagger-ui.html
group-configs:
- group: demo
paths-to-match: /demo/**
- group: demo2
paths-to-match: /demo2/**
- group: demo3
packages-to-scan: com.wen3.springdoc.demo.controller3
api-docs:
enabled: true #开启/禁止api-docs, prod可以设置为false
# /api-docs endpoint custom path
path: /api-docs # 设置为true时, management也需要设置
model-and-view-allowed: true #运行modelAndView展示(返回页面)
use-management-port: false
# use-management-port: true
# 是否在swagger-ui中显示actuator接口文档
show-actuator: false
management:
server:
# The actuator management port has to be different from the application port.
port: 7002
endpoints:
web:
exposure:
include: '*'
启动工程
启动日志如下
访问swagger-ui
- 在浏览器输入
http://localhost:7001/swagger-ui/index.html
- 右上角有个分组的下拉列表,分别对于不同分组下的
API
结合swagger-ui对配置项进行说明
安全认证
- SpringDocAutoConfiguration在这个类上加了安全相关的注释后
@OpenAPIDefinition(
security = @SecurityRequirement(name = "Authorization")
)
@SecurityScheme(type = SecuritySchemeType.HTTP, name = HttpHeaders.AUTHORIZATION, scheme = "bearer", bearerFormat="JWT", in = SecuritySchemeIn.HEADER)
@SecurityScheme(type = SecuritySchemeType.HTTP, name = "xxx", scheme = "bearer", bearerFormat="JWT", in = SecuritySchemeIn.HEADER)
@Configuration
public class SpringDocAutoConfiguration {
}
- 对应
swagger-ui
上的Authorize
按钮
- 通过
Try it out
测试API
的时候,会带上这个请求头
show-actuator
- 如果修改以下配置
springdoc:
show-actuator: true
- 就可以在
swagger-ui
看到actuator
相关API
文档
总结
- 本文演示了在最新版
Spring Boot
怎么集成API
文档工具Springdoc
Springdoc
支持Swagger
官方配置,使用前缀springdoc.swagger-ui
,熟悉Swagger
配置的同学也可以方便的丝滑迁移到Springdoc
Springdoc
对Spring Boot
框架体系的支持比较友好,版本迭代也比较活跃,可以考虑从其它工具迁移过来,从本文的演示来看,配置还是相当简单,能体验到丝滑的程度Springdoc
写API
文档,对应的注解也随之不同Swagger
和SpringDoc
常用注解的对应关系如下:@Api → @Tag
@ApiIgnore → @Parameter(hidden = true) or @Operation(hidden = true) or @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”)