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

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


咨詢
建站咨詢
