新聞中心
1. OpenApi
在正式學(xué)習(xí) Spring Doc 之前,先給大家介紹一下 OpenAPI。

OpenApi 是一個(gè)業(yè)界的 API 文檔標(biāo)準(zhǔn),是一個(gè)規(guī)范,這個(gè)規(guī)范目前有兩大實(shí)現(xiàn),分別是:
- SpringFox
- SpringDoc
其中 SpringFox 其實(shí)也就是我們之前所說(shuō)的 Swagger,SpringDoc 則是我們今天要說(shuō)的內(nèi)容。
OpenApi 就像 JDBC 一樣,制定了各種各樣的規(guī)范,而 Swagger 和 SpringDoc 則類似于各種各樣的數(shù)據(jù)庫(kù)驅(qū)動(dòng),是具體的實(shí)現(xiàn)。
所以可能很多小伙伴也發(fā)現(xiàn)了,Swagger 和 Spring Doc 有一些相似的地方,這就是因?yàn)樗麄兌甲袷亓讼嗤囊?guī)范。
不過(guò)呢,Swagger 更新有點(diǎn)慢吞吞的,為了能夠和新版的 Spring Boot 整合,還是 SpringDoc 更值得體驗(yàn)一把。
SpringDoc 支持:
- OpenAPI 3
- Spring-boot,全版本都支持。
- JSR-303 中提供的一些注解,例如@NotNull、@Min、@Max? 以及@Size 等。
- Swagger-ui:SpringDoc 提供的接口 JSON 也可以通過(guò) Swagger-ui 展示出來(lái)。
- OAuth 2
- ...
2. 引入 SpringDoc
小伙伴們知道,這種生成接口文檔的工具,一般來(lái)說(shuō)都是兩方面的功能:
- 生成接口文檔 JSON。
- 渲染接口文檔 JSON。
所以,當(dāng)我們使用 SpringDoc 的時(shí)候,如果只是想要生成接口文檔 JSON,那么只需要添加如下依賴即可:
org.springdoc
springdoc-openapi-webmvc-core
1.6.9
此時(shí),就會(huì)針對(duì)項(xiàng)目中的接口自動(dòng)生成接口的 JSON 文檔,類似下面這樣:
這樣的 JSON 信息開(kāi)發(fā)者可以自行將之繪制出來(lái),也可以使用網(wǎng)上一些現(xiàn)成的工具例如 Knife4j 之類的。當(dāng)然你要是不想費(fèi)事,也可以使用 SwaggerUI 將之繪制出來(lái),如果想使用網(wǎng)頁(yè),那么就不要使用上面的依賴,用下面這個(gè)依賴,不僅可以生成 JSON 接口,還可以生成渲染后的網(wǎng)頁(yè):
org.springdoc
springdoc-openapi-ui
1.6.9
網(wǎng)頁(yè)效果如下圖:
這個(gè)網(wǎng)頁(yè)看著眼熟,其實(shí)就是 Swagger UI。
這個(gè)網(wǎng)頁(yè)上有一個(gè)輸入框,輸入的內(nèi)容是 /v3/api-docs,這個(gè)地址就是這個(gè)網(wǎng)頁(yè)想要渲染的 JSON 的地址,如果開(kāi)發(fā)者修改了生成的 JSON API 文檔的地址,那么就需要手動(dòng)在這個(gè)輸入框中輸入一下 JSON API 文檔的地址。
默認(rèn)的 JSON API 文檔地址是:
- /v3/api-docs
默認(rèn)的網(wǎng)頁(yè) UI 地址是:
- /swagger-ui/index.html
如果需要配置,則可以在 Spring Boot 的 application.properties 中直接進(jìn)行配置:
springdoc.swagger-ui.path=/javaboy-ui
springdoc.api-docs.path=/javaboy-api
不過(guò)這兩個(gè)配置并不是真的修改了訪問(wèn)路徑,這兩個(gè)相當(dāng)于給訪問(wèn)路徑取了一個(gè)別名,訪問(wèn)這兩個(gè)時(shí)會(huì)自動(dòng)重定向到對(duì)應(yīng)的路徑上。
3. 結(jié)合 Spring Security
如果我們的項(xiàng)目中使用了 Spring Security,那么部分接口的參數(shù)可能會(huì)比較特殊,例如下面這個(gè)接口:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(@AuthenticationPrincipal User user) {
System.out.println("user = " + user);
return "hello";
}
}
這個(gè)接口的參數(shù)加上了一個(gè) @AuthenticationPrincipal 注解表示當(dāng)前登錄成功的用戶對(duì)象,這個(gè)參數(shù)在實(shí)際使用中,并不需要前端傳遞,服務(wù)端會(huì)自動(dòng)注入該參數(shù)。
但是!如果使用了 SpringDoc,通過(guò)網(wǎng)頁(yè)去調(diào)用這個(gè)接口的時(shí)候,這個(gè)參數(shù)就必須要要傳遞,對(duì)于這種問(wèn)題,我們可以引入如下依賴自動(dòng)幫我們解決:
org.springdoc
springdoc-openapi-security
1.6.9
這個(gè)依賴會(huì)自動(dòng)幫我們忽略掉接口中帶有 @AuthenticationPrincipal 注解的參數(shù),這樣我們?cè)谕ㄟ^(guò) swagger-ui 去進(jìn)行接口測(cè)試的時(shí)候就不需要傳遞這個(gè)參數(shù)了。
4. 結(jié)合 Spring Data Rest
Spring Boot 中提供了 Spring Data Rest,結(jié)合 Jpa 可以非常方便的構(gòu)建出 Restful 應(yīng)用。但是這種 Restful 應(yīng)用不需要開(kāi)發(fā)者自己寫(xiě)接口,那么怎么生成接口文檔呢(連接口在哪里都不知道)?針對(duì)于此,SpringDoc 也提供了相關(guān)的支持,我們一起來(lái)看下。
4.1 Spring Data Rest
創(chuàng)建工程
首先創(chuàng)建一個(gè) Spring Boot 工程,引入 Web 、 Jpa 、 MySQL 、Rest Repositories 依賴:
配置數(shù)據(jù)庫(kù)
主要配置兩個(gè),一個(gè)是數(shù)據(jù)庫(kù),另一個(gè)是 Jpa:
spring.datasource.username=root
spring.datasource.password=1234
spring.datasource.url=jdbc:mysql:///test02?serverTimezone=Asia/Shanghai
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.database=mysql
spring.jpa.database-platform=mysql
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
這里的配置,和 Jpa 中的基本一致。
前面三行配置了數(shù)據(jù)庫(kù)的基本信息,包括數(shù)據(jù)庫(kù)連接池、數(shù)據(jù)庫(kù)用戶名、數(shù)據(jù)庫(kù)密碼、數(shù)據(jù)庫(kù)連接地址以及數(shù)據(jù)庫(kù)驅(qū)動(dòng)名稱。
接下來(lái)的五行配置了 JPA 的基本信息,分別表示生成 SQL 的方言、打印出生成的 SQL 、每次啟動(dòng)項(xiàng)目時(shí)根據(jù)實(shí)際情況選擇是否更新表、數(shù)據(jù)庫(kù)平臺(tái)是 MySQL。
這兩段配置是關(guān)于 MySQL + JPA 的配置,沒(méi)用過(guò) JPA 的小伙伴可以參考松哥之前的 JPA 文章:http://www.javaboy.org/2019/0407/springboot-jpa.html
構(gòu)建實(shí)體類
@Entity(name = "t_book")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "book_name")
private String name;
private String author;
//省略 getter/setter
}
public interface BookRepository extends JpaRepository{
}
這里一個(gè)是配置了一個(gè)實(shí)體類 Book,另一個(gè)則是配置了一個(gè) BookRepository ,項(xiàng)目啟動(dòng)成功后,框架會(huì)根據(jù) Book 類的定義,在數(shù)據(jù)庫(kù)中自動(dòng)創(chuàng)建相應(yīng)的表,BookRepository 接口則是繼承自 JpaRepository ,JpaRepository 中自帶了一些基本的增刪改查方法。
好了,代碼寫(xiě)完了。
啥?你好像啥都沒(méi)寫(xiě)啊?是的,啥都沒(méi)寫(xiě),啥都不用寫(xiě),一個(gè) RESTful 風(fēng)格的增刪改查應(yīng)用就有了,這就是 Spring Boot 的魅力!
測(cè)試
此時(shí),我們就可以啟動(dòng)項(xiàng)目進(jìn)行測(cè)試了,使用 POSTMAN 來(lái)測(cè)試(大家也可以自行選擇趁手的 HTTP 請(qǐng)求工具)。
此時(shí)我們的項(xiàng)目已經(jīng)默認(rèn)具備了一些接口,我們分別來(lái)看:
根據(jù) id 查詢接口
- http://127.0.0.1:8080/books/{id}
這個(gè)接口表示根據(jù) id 查詢某一本書(shū):
分頁(yè)查詢
- http://127.0.0.1:8080/books
這是一個(gè)批量查詢接口,默認(rèn)請(qǐng)求路徑是類名首字母小寫(xiě),并且再加一個(gè) s 后綴。這個(gè)接口實(shí)際上是一個(gè)分頁(yè)查詢接口,沒(méi)有傳參數(shù),表示查詢第一頁(yè),每頁(yè) 20 條數(shù)據(jù)。
查詢結(jié)果中,除了該有的數(shù)據(jù)之外,也包含了分頁(yè)數(shù)據(jù):
分頁(yè)數(shù)據(jù)中:
- size 表示每頁(yè)查詢記錄數(shù)
- totalElements 表示總記錄數(shù)
- totalPages 表示總頁(yè)數(shù)
- number 表示當(dāng)前頁(yè)數(shù),從0開(kāi)始計(jì)
如果要分頁(yè)或者排序查詢,可以使用 _links 中的鏈接。http://127.0.0.1:8080/books?page=1&size=3&sort=id,desc 。
添加
也可以添加數(shù)據(jù),添加是 POST 請(qǐng)求,數(shù)據(jù)通過(guò) JSON 的形式傳遞,如下:
添加成功之后,默認(rèn)會(huì)返回添加成功的數(shù)據(jù)。
修改
修改接口默認(rèn)也是存在的,數(shù)據(jù)修改請(qǐng)求是一個(gè) PUT 請(qǐng)求,修改的參數(shù)也是通過(guò) JSON 的形式傳遞:
默認(rèn)情況下,修改成功后,會(huì)返回修改成功的數(shù)據(jù)。
刪除
當(dāng)然也可以通過(guò) DELETE 請(qǐng)求根據(jù) id 刪除數(shù)據(jù):
刪除成功后,是沒(méi)有返回值的。
不需要幾行代碼,一個(gè)基本的增刪改查就有了。
這些都是默認(rèn)的配置,這些默認(rèn)的配置實(shí)際上都是在 JpaRepository 的基礎(chǔ)上實(shí)現(xiàn)的,實(shí)際項(xiàng)目中,我們還可以對(duì)這些功能進(jìn)行定制。
查詢定制
最廣泛的定制,就是查詢,因?yàn)樵鰟h改操作的變化不像查詢這么豐富。對(duì)于查詢的定制,非常容易,只需要提供相關(guān)的方法即可。例如根據(jù)作者查詢書(shū)籍:
public interface BookRepository extends JpaRepository{
ListfindBookByAuthorContaining(@Param("author") String author);
}
注意,方法的定義,參數(shù)要有 @Param 注解。
定制完成后,重啟項(xiàng)目,此時(shí)就多了一個(gè)查詢接口,開(kāi)發(fā)者可以通過(guò) http://localhost:8080/books/search 來(lái)查看和 book 相關(guān)的自定義接口都有哪些:
查詢結(jié)果表示,只有一個(gè)自定義接口,接口名就是方法名,而且查詢結(jié)果還給出了接口調(diào)用的示例。我們來(lái)嘗試調(diào)用一下自己定義的查詢接口:
開(kāi)發(fā)者可以根據(jù)實(shí)際情況,在 BookRepository 中定義任意多個(gè)查詢方法,查詢方法的定義規(guī)則和 Jpa 中一模一樣(不懂 Jpa 的小伙伴,可以參考干貨|一文讀懂 Spring Data Jpa!,或者在松哥個(gè)人網(wǎng)站 www.javaboy.org 上搜索 JPA,有相關(guān)教程參考)。但是,這樣有一個(gè)缺陷,就是 Jpa 中方法名太長(zhǎng),因此,如果不想使用方法名作為接口名,則可以自定義接口名:
public interface BookRepository extends JpaRepository{
@RestResource(rel = "byauthor",path = "byauthor")
ListfindBookByAuthorContaining(@Param("author") String author);
}
@RestResource 注解中,兩個(gè)參數(shù)的含義:
- rel 表示接口查詢中,這個(gè)方法的 key
- path 表示請(qǐng)求路徑
這樣定義完成后,表示接口名為 byauthor ,重啟項(xiàng)目,繼續(xù)查詢接口:
除了 rel 和 path 兩個(gè)屬性之外,@RestResource 中還有一個(gè)屬性,exported 表示是否暴露接口,默認(rèn)為 true ,表示暴露接口,即方法可以在前端調(diào)用,如果僅僅只是想定義一個(gè)方法,不需要在前端調(diào)用這個(gè)方法,可以設(shè)置 exported 屬性為 false 。
如果不想暴露官方定義好的方法,例如根據(jù) id 刪除數(shù)據(jù),只需要在自定義接口中重寫(xiě)該方法,然后在該方法上加 @RestResource 注解并且配置相關(guān)屬性即可。
public interface BookRepository extends JpaRepository{
@RestResource(rel = "byauthor",path = "byauthor")
ListfindBookByAuthorContaining(@Param("author") String author);
@Override
@RestResource(exported = false)
void deleteById(Long aLong);
}
另外生成的 JSON 字符串中的集合名和單個(gè) item 的名字都是可以自定義的:
@RepositoryRestResource(collectionResourceRel = "bs",itemResourceRel = "b",path = "bs")
public interface BookRepository extends JpaRepository{
@RestResource(rel = "byauthor",path = "byauthor")
ListfindBookByAuthorContaining(@Param("author") String author);
@Override
@RestResource(exported = false)
void deleteById(Long aLong);
}
path 屬性表示請(qǐng)求路徑,請(qǐng)求路徑默認(rèn)是類名首字母小寫(xiě)+s,可以在這里自己重新定義。
其他配置
最后,也可以在 application.properties 中配置 REST 基本參數(shù):
spring.data.rest.base-path=/api
spring.data.rest.sort-param-name=sort
spring.data.rest.page-param-name=page
spring.data.rest.limit-param-name=size
spring.data.rest.max-page-size=20
spring.data.rest.default-page-size=0
spring.data.rest.return-body-on-update=true
spring.data.rest.return-body-on-create=true
配置含義,從上往下,依次是:
- 給所有的接口添加統(tǒng)一的前綴
- 配置排序參數(shù)的 key ,默認(rèn)是 sort
- 配置分頁(yè)查詢時(shí)頁(yè)碼的 key,默認(rèn)是 page
- 配置分頁(yè)查詢時(shí)每頁(yè)查詢頁(yè)數(shù)的 key,默認(rèn)是size
- 配置每頁(yè)最大查詢記錄數(shù),默認(rèn)是 20 條
- 分頁(yè)查詢時(shí)默認(rèn)的頁(yè)碼
- 更新成功時(shí)是否返回更新記錄
- 添加成功時(shí)是否返回添加記錄
這是 Spring Data Rest 的一個(gè)簡(jiǎn)單用法,接下來(lái)我們來(lái)看如何給這個(gè)生成的文檔。
4.2 生成接口文檔
對(duì)于這種你都沒(méi)看到接口的,我們只需要添加如下依賴,就可以自動(dòng)生成 API 文檔了,如下:
org.springdoc
springdoc-openapi-data-rest
1.6.9
org.springdoc
springdoc-openapi-ui
1.6.9
生成的接口文檔如下:
5. 結(jié)合 Actuator
在之前的 Spring Boot 教程中,松哥還和大家介紹過(guò) Spring Boot 中的 actuator,這個(gè)工具可以自行生成項(xiàng)目運(yùn)行數(shù)據(jù)的端點(diǎn)(endpoints),如果想把這些端點(diǎn)也納入到 SpringDoc 中來(lái),那么只需要添加如下配置即可:
springdoc.show-actuator=true
至于 SpringDoc 會(huì)顯示多少個(gè) Actuator 端點(diǎn)出來(lái),那就要看 Actuator 暴露出來(lái)多少端點(diǎn)了,最終顯示效果如下:
不過(guò)這里還有一個(gè)玩法!
SpringDoc 扮演的角色畢竟不是業(yè)務(wù)功能,而是項(xiàng)目的輔助功能,所以,我們可以將之從業(yè)務(wù)中剝離,放到 Actuator 中,畢竟 Actuator 專干這種事。那么只需要增加如下兩個(gè)配置即可:
springdoc.use-management-port=true
management.endpoints.web.exposure.include=openapi, swagger-ui
management.server.port=9090
配置完成后,將來(lái)就可以在 Actuator 中去查看接口文檔和對(duì)應(yīng)的頁(yè)面了,訪問(wèn)地址是:
- http://localhost:9090/actuator/swagger-ui/index.html
6. 切換到 Swagger
如果你在項(xiàng)目中已經(jīng)使用了 Swagger 了,那么也可以非常方便的切換到 SpringDoc 上面來(lái),切換的時(shí)候,首先引入 SpringDoc 依賴:
org.springdoc
springdoc-openapi-ui
1.6.9
Swagger 和 SpringDoc 注解的對(duì)應(yīng)關(guān)系如下:
- @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")
以前我們?cè)?Swagger 中配置接口掃描的方式如下:
@Bean
public Docket publicApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("org.github.springshop.web.public"))
.paths(PathSelectors.regex("/public.*"))
.build()
.groupName("springshop-public")
.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.*"))
.apis(RequestHandlerSelectors.withMethodAnnotation(Admin.class))
.build()
.groupName("springshop-admin")
.apiInfo(apiInfo());
}
現(xiàn)在在 SpringDoc 中則按照如下方式進(jìn)行配置即可(還可以按照注解去標(biāo)記需要生成接口文檔的方法):
@Configuration
public class SpringDocConfig {
@Bean
public GroupedOpenApi publicApi() {
return GroupedOpenApi.builder()
.group("springshop-public")
.pathsToMatch("/public/**")
.build();
}
@Bean
public GroupedOpenApi adminApi() {
return GroupedOpenApi.builder()
.group("springshop-admin")
.pathsToMatch("/admin/**")
.addOpenApiMethodFilter(method -> method.isAnnotationPresent(RequestMapping.class))
.build();
}
}
當(dāng)然,如果你并不需要對(duì)接口文檔進(jìn)行分組,那么也可以不使用 Java 配置,直接在 application.properties 中進(jìn)行配置即可:
springdoc.packages-to-scan=org.javaboy.spring_doc.controller
springdoc.paths-to-match=/**
在 SpringDoc 中,如果你想配置 Swagger UI,則可以通過(guò)如下方式進(jìn)行配置:
@Bean
OpenAPI springShopOpenAPI() {
return new OpenAPI()
.info(new Info().title("江南一點(diǎn)雨")
.description("Spring Boot 教程")
.version("v0.0.1")
.license(new License().name("Apache 2.0").url("http://www.javaboy.org")))
.externalDocs(new ExternalDocumentation()
.description("一些描述信息")
.url("https://github.com/lenve/vhr"));
}
好啦,常見(jiàn)用法大概就是這樣,感興趣的小伙伴可以去試試哦~關(guān)于 SpringDoc 的更多玩法,大家也可以參考官方文檔:springdoc.org。
名稱欄目:不用Swagger,那我用啥?
網(wǎng)站地址:http://www.dlmjj.cn/article/dpgeijj.html


咨詢
建站咨詢
