首頁 > 科技

用 WebFlux 寫個 CURD 是什麼體驗?

2021-06-18 19:33:48

WebFlux 最為人所詬病的是資料庫的支援問題,畢竟資料是一個應用的生命,我們接觸的大部分應用程式都是有資料庫的,而 WebFlux 在這一方面的支援行一直比較弱,這也是大家總是吐槽它的原因。

不過從 Spring5 開始,這一問題得到了一定程度的緩解。

Spring 官方在 Spring5 釋出了響應式 Web 框架 Spring WebFlux 之後急需能夠滿足非同步響應的資料庫互動 API,不過由於缺乏標準和驅動,Pivotal 團隊開始自己研究響應式關係型資料庫連線 Reactive Relational Database Connectivity,並提出了 R2DBC 規範 API 用來評估可行性並討論資料庫廠商是否有興趣支援響應式的非同步非阻塞驅動程式。最早只有 PostgreSQL 、H2、MSSQL 三家資料庫廠商,不過現在 MySQL 也加入進來了,這是一個極大的利好。目前 R2DBC 的最新版本是 0.9.0.RELEASE。

今天我們還是先來看看 WebFlux+MongoDB 的用法,畢竟這是 WebFlux 較早支援的資料庫之一,各種 API 都比較成熟,我們一步一步來。

項目創建

方便起見,我們這裡就直接創建 Spring Boot 項目,首先創建一個 Spring Boot 項目,引入 MongoDB 依賴和 WebFlux 依賴,如下:

注意我們這裡選擇的 MongoDB 依賴是 Spring Data Reactive MongoDB,千萬別選錯了。

項目創建完成後,我們先在 application.properties 中對 MongoDB 進行簡單配置,如下(如果小夥伴們尚不熟悉 MongoDB 的操作,可以在公眾號底部選單找到鬆哥原創的 MongoDB 教程):

spring.data.mongodb.port=27017spring.data.mongodb.host=127.0.0.1spring.data.mongodb.username=madminspring.data.mongodb.password=m123spring.data.mongodb.database=testspring.data.mongodb.authentication-database=admin

配置完 MongoDB 後,我們的準備工作就算完成了。

實體類與 Dao

接下來我們需要準備一個操作的實體類,這些都是 JPA 的基本操作,鬆哥就不再贅述,如果小夥伴們不熟悉的話,可以公號後臺回覆 666 檢視原創的 Spring Boot 教程,裡邊有涉及到,實體類如下:

@Documentpublic class User {    @Id    private String id;    private String username;    private String address;
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getAddress() { return address; }
public void setAddress(String address) { this.address = address; }}

接下來我們再提供一個實體類操作的介面,如下:

@EnableMongoRepositoriespublic interface UserDao extends ReactiveMongoRepository<User,String> {}

自定義一個空的介面繼承自 ReactiveMongoRepository,裡邊什麼都不用寫,這套路就和鬆哥之前視訊中介紹的 JPA 的用法如出一轍(畢竟都是 Spring Data 家族),所以這塊就沒啥好說的,不贅述。

測試介面

接下來我們來看看測試介面。

3.1 新增

首先我們來看看新增資料。

@RestController@RequestMapping("/user")public class UserController {    @Autowired    UserDao userDao;
@PostMapping("/") public Mono<User> addUser(@RequestBody User user) { return userDao.save(user); }}

新增完成後,返回剛剛新增成功的物件。save 方法的返回值就是 Mono。

我們來看看測試效果:

3.2 查詢

再來看看查詢效果:

@GetMapping("/")public Flux<User> getAll() {    return userDao.findAll();}@GetMapping(value = "/stream/all", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<User> streamGetAll() {    return userDao.findAll();}

我們提供了兩個查詢介面,一個就是返回 Flux,裡邊包含多個物件,還有一個我設定了響應的 Content-Type 為 text/event-stream,通過響應式流返回資料,具體參見【服務端推送資料,除了 WebSocket 你還能想到啥?】一文。

我們來看看查詢效果:

可以看到兩種不同的查詢方式返回的資料格式也有差異。前者是以陣列形式一次性返回資料,後者是以 SSE 的形式多次返回資料。

3.3 刪除

再來看看刪除。

按照 RESTful 規範,如果刪除成功請求響應碼就是 200,如果刪除失敗請求響應碼就是 404,因此,我們開發出來的介面如下:

@DeleteMapping("/{id}")public Mono<ResponseEntity<Void>> deleteUser(@PathVariable String id) {    return userDao.findById(id)            .flatMap(user -> userDao.delete(user).then(Mono.just(new ResponseEntity<Void>(HttpStatus.OK))))            .defaultIfEmpty(new ResponseEntity(HttpStatus.NOT_FOUND));}

首先從資料庫中查詢出相關的資料,然後呼叫 flatMap,在 flatMap 中對資料進行刪除處理,刪除完成後,給出一個 200 的響應碼,如果查詢的時候沒有查詢到資料,就給一個 404 響應碼。

可以看到,刪除成功後,響應碼為 200:

刪除失敗後,響應碼為 404:

3.4 修改

再來看看修改,和前面的刪除類似,先查詢,再修改:

@PutMapping("/")public Mono<ResponseEntity<User>> updateUser(@RequestBody User user) {    return userDao.findById(user.getId())            .flatMap(u -> userDao.save(user))            .map(u->new ResponseEntity<User>(u,HttpStatus.OK))            .defaultIfEmpty(new ResponseEntity(HttpStatus.NOT_FOUND));}

如果修改的資料不存在的話,就會給出一個 404 響應:

3.5 自定義查詢方法

好啦,今天我們就用 WebFlux 寫了一個簡單的 CURD,大家先來感受下 WebFlux 的基本用法。


IT145.com E-mail:sddin#qq.com