日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

【Spring 5】响应式Web框架实战(上)

發(fā)布時間:2024/1/17 javascript 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Spring 5】响应式Web框架实战(上) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前情概要:?
-?【Spring 5】響應(yīng)式Web框架前瞻?
-?響應(yīng)式編程總覽

1 回顧

通過前兩篇的介紹,相信你對響應(yīng)式編程和Spring 5已經(jīng)有了一個初步的了解。下面我將以一個簡單的Spring 5應(yīng)用為例,介紹如何使用Spring 5快速搭建一個響應(yīng)式Web應(yīng)用(以下簡稱RP應(yīng)用)。

2 實戰(zhàn)

2.1 環(huán)境準(zhǔn)備

首先,從GitHub下載我的這個示例應(yīng)用,地址是https://github.com/emac/spring5-features-demo。

然后,從MongoDB官網(wǎng)下載最新版本的MongoDB,然后在命令行下運(yùn)行mongod &啟動服務(wù)。

現(xiàn)在,可以先試著跑一下項目中自帶的測試用例。

./gradlew clean build

2.2 依賴介紹

接下來,看一下這個示例應(yīng)用里的和響應(yīng)式編程相關(guān)的依賴。

compile('org.springframework.boot:spring-boot-starter-webflux') compile('org.springframework.boot:spring-boot-starter-data-mongodb-reactive') testCompile('io.projectreactor.addons:reactor-test')
  • 1
  • 2
  • 3
  • spring-boot-starter-webflux: 啟用Spring 5的RP(Reactive Programming)支持,這是使用Spring 5開發(fā)RP應(yīng)用的必要條件,就好比spring-boot-starter-web之于傳統(tǒng)的Spring MVC應(yīng)用。
  • spring-boot-starter-data-mongodb-reactive: Spring 5中新引入的針對MongoDB的Reactive Data擴(kuò)展庫,允許通過統(tǒng)一的RP風(fēng)格的API操作MongoDB。
  • io.projectreactor.addons:reactor-test:?Reactor(Spring 5默認(rèn)使用的RP框架)提供的官方測試工具庫。

2.3 示例代碼

不知道你是否還記得,在本系列第一篇【Spring 5】響應(yīng)式Web框架前瞻里提到,Spring 5提供了Spring MVC注解和Router Functions兩種方式來編寫RP應(yīng)用。本篇我就先用大家最熟悉的MVC注解來展示如何編寫一個最簡單的RP Controller。

@RestController public class RestaurantController {/*** 擴(kuò)展ReactiveCrudRepository接口,提供基本的CRUD操作*/private final RestaurantRepository restaurantRepository;/*** spring-boot-starter-data-mongodb-reactive提供的通用模板*/private final ReactiveMongoTemplate reactiveMongoTemplate;public RestaurantController(RestaurantRepository restaurantRepository, ReactiveMongoTemplate reactiveMongoTemplate) {this.restaurantRepository = restaurantRepository;this.reactiveMongoTemplate = reactiveMongoTemplate;}@GetMapping("/reactive/restaurants")public Flux<Restaurant> findAll() {return restaurantRepository.findAll();}@GetMapping("/reactive/restaurants/{id}")public Mono<Restaurant> get(@PathVariable String id) {return restaurantRepository.findById(id);}@PostMapping("/reactive/restaurants")public Flux<Restaurant> create(@RequestBody Flux<Restaurant> restaurants) {return restaurants.buffer(10000).flatMap(rs -> reactiveMongoTemplate.insert(rs, Restaurant.class));}@DeleteMapping("/reactive/restaurants/{id}")public Mono<Void> delete(@PathVariable String id) {return restaurantRepository.deleteById(id);} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

可以看到,實現(xiàn)一個RP Controller和一個普通的Controller是非常類似的,最核心的區(qū)別是,優(yōu)先使用RP中最基礎(chǔ)的兩種數(shù)據(jù)類型,Flux(對應(yīng)多值)和Mono(單值),尤其是方法的參數(shù)和返回值。即便是空返回值,也應(yīng)封裝為Mono<Void>。這樣做的目的是,使得應(yīng)用能夠以一種統(tǒng)一的符合RP規(guī)范的方式處理數(shù)據(jù),最理想的情況是從最底層的數(shù)據(jù)庫(或者其他系統(tǒng)外部調(diào)用),到最上層的Controller層,所有數(shù)據(jù)都不落地,經(jīng)由各種Flux和Mono鋪設(shè)的“管道”,直供調(diào)用端。就像農(nóng)夫山泉那句著名的廣告詞,我們不生產(chǎn)水,我們只是大自然的搬運(yùn)工。

2.4 單元測試

和非RP應(yīng)用的單元測試相比,RP應(yīng)用的單元測試主要是使用了一個Spring 5新引入的測試工具類,WebTestClient,專門用于測試RP應(yīng)用。

@RunWith(SpringRunner.class) @SpringBootTest public class RestaurantControllerTests {@Testpublic void testNormal() throws InterruptedException {// start from scratchrestaurantRepository.deleteAll().block();// prepareWebTestClient webClient = WebTestClient.bindToController(new RestaurantController(restaurantRepository, reactiveMongoTemplate)).build();Restaurant[] restaurants = IntStream.range(0, 100).mapToObj(String::valueOf).map(s -> new Restaurant(s, s, s)).toArray(Restaurant[]::new);// createwebClient.post().uri("/reactive/restaurants").accept(MediaType.APPLICATION_JSON_UTF8).syncBody(restaurants).exchange().expectStatus().isOk().expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8).expectBodyList(Restaurant.class).hasSize(100).consumeWith(rs -> Flux.fromIterable(rs).log().subscribe(r1 -> {// getwebClient.get().uri("/reactive/restaurants/{id}", r1.getId()).accept(MediaType.APPLICATION_JSON_UTF8).exchange().expectStatus().isOk().expectHeader().contentType(MediaType.APPLICATION_JSON_UTF8).expectBody(Restaurant.class).consumeWith(r2 -> Assert.assertEquals(r1, r2));}));} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

創(chuàng)建WebTestClient實例時,首先要綁定一下待測試的RP Controller。可以看到,和業(yè)務(wù)類一樣,編寫RP應(yīng)用的單元測試,同樣也是數(shù)據(jù)不落地的流式風(fēng)格。

在示例應(yīng)用中可以找到更多的單元測試。

3 小結(jié)

以上就是Spring 5里第一種,相信也將會是最常用的編寫RP應(yīng)用的實現(xiàn)方式。介于篇幅原因,這篇就先到這里。下篇我將詳細(xì)介紹第二種方式,Router Functions。歡迎你到我的留言板分享,和大家一起過過招。

4 參考

  • Spring Framework Reference - WebFlux framework
  • spring-framework Reactive Tests

總結(jié)

以上是生活随笔為你收集整理的【Spring 5】响应式Web框架实战(上)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。