javascript
Spring Web-Flux – Cassandra后端的功能样式
在上一篇文章中,我介紹了Spring Web-Flux的基礎(chǔ)知識(shí),它表示Spring框架的Web層中的響應(yīng)式支持。
我已經(jīng)展示了使用Spring Data Cassandra并在Spring Web Layers中使用傳統(tǒng)注釋支持的端到端示例, 大致如下:
... import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; ...@RestController @RequestMapping("/hotels") public class HotelController {@GetMapping(path = "/{id}")public Mono<Hotel> get(@PathVariable("id") UUID uuid) {...}@GetMapping(path = "/startingwith/{letter}")public Flux<HotelByLetter> findHotelsWithLetter(@PathVariable("letter") String letter) {...}}除了返回類型外,這看起來(lái)像傳統(tǒng)的Spring Web注釋,這些端點(diǎn)不是返回域類型,而是通過(guò)在Reactor-Core中實(shí)現(xiàn)Mono和Flux的實(shí)現(xiàn)返回Publisher類型,而Spring-Web則將內(nèi)容流回。
在本文中,我將介紹一種不同的公開(kāi)端點(diǎn)的方法-使用功能樣式而不是注釋樣式。 讓我承認(rèn),對(duì)于我了解暴露Web終結(jié)點(diǎn)的功能樣式的理解,我發(fā)現(xiàn)Baeldung的文章和Rossen Stoyanchev的文章非常寶貴。
將注釋映射到路線
讓我從一些基于注釋的端點(diǎn)開(kāi)始,一個(gè)是檢索實(shí)體,另一個(gè)是保存實(shí)體:
@GetMapping(path = "/{id}") public Mono<Hotel> get(@PathVariable("id") UUID uuid) {return this.hotelService.findOne(uuid); }@PostMapping public Mono<ResponseEntity<Hotel>> save(@RequestBody Hotel hotel) {return this.hotelService.save(hotel).map(savedHotel -> new ResponseEntity<>(savedHotel, HttpStatus.CREATED)); }在公開(kāi)端點(diǎn)的功能風(fēng)??格中,每個(gè)端點(diǎn)都將轉(zhuǎn)換為RouterFunction ,它們可以組成以創(chuàng)建應(yīng)用程序的所有端點(diǎn),如下所示:
package cass.web;import org.springframework.http.MediaType; import org.springframework.web.reactive.function.server.RouterFunction;import static org.springframework.web.reactive.function.server.RequestPredicates.*; import static org.springframework.web.reactive.function.server.RouterFunctions.*;public interface ApplicationRoutes {static RouterFunction<?> routes(HotelHandler hotelHandler) {return nest(path("/hotels"),nest(accept(MediaType.APPLICATION_JSON),route(GET("/{id}"), hotelHandler::get).andRoute(POST("/"), hotelHandler::save)));} }有一些輔助功能(嵌套,路由,GET,接受等),可以輕松地將所有RouterFunction組合在一起。 找到合適的RouterFunction后,該請(qǐng)求由HandlerFunction處理,該函數(shù)在上述示例中由HotelHandler抽象,并且保存和獲取功能如下所示:
import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono;import java.util.UUID;@Service public class HotelHandler {...public Mono<ServerResponse> get(ServerRequest request) {UUID uuid = UUID.fromString(request.pathVariable("id"));Mono<ServerResponse> notFound = ServerResponse.notFound().build();return this.hotelService.findOne(uuid).flatMap(hotel -> ServerResponse.ok().body(Mono.just(hotel), Hotel.class)).switchIfEmpty(notFound);}public Mono<ServerResponse> save(ServerRequest serverRequest) {Mono<Hotel> hotelToBeCreated = serverRequest.bodyToMono(Hotel.class);return hotelToBeCreated.flatMap(hotel ->ServerResponse.status(HttpStatus.CREATED).body(hotelService.save(hotel), Hotel.class));}... }這是原始基于注釋的項(xiàng)目支持的所有API的完整RouterFunction的樣子:
import org.springframework.http.MediaType; import org.springframework.web.reactive.function.server.RouterFunction;import static org.springframework.web.reactive.function.server.RequestPredicates.*; import static org.springframework.web.reactive.function.server.RouterFunctions.*;public interface ApplicationRoutes {static RouterFunction<?> routes(HotelHandler hotelHandler) {return nest(path("/hotels"),nest(accept(MediaType.APPLICATION_JSON),route(GET("/{id}"), hotelHandler::get).andRoute(POST("/"), hotelHandler::save).andRoute(PUT("/"), hotelHandler::update).andRoute(DELETE("/{id}"), hotelHandler::delete).andRoute(GET("/startingwith/{letter}"), hotelHandler::findHotelsWithLetter).andRoute(GET("/fromstate/{state}"), hotelHandler::findHotelsInState)));} }測(cè)試功能路線
測(cè)試這些路由也很容易,Spring Webflux提供了一個(gè)WebTestClient來(lái)測(cè)試路由,同時(shí)提供模擬其背后的實(shí)現(xiàn)的能力。
例如,為了測(cè)試通過(guò)ID的get端點(diǎn),我將WebTestClient綁定到之前定義的RouterFunction,并使用它提供的斷言來(lái)測(cè)試行為。
import org.junit.Before; import org.junit.Test; import org.springframework.test.web.reactive.server.WebTestClient; import reactor.core.publisher.Mono;import java.util.UUID;import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when;public class GetRouteTests {private WebTestClient client;private HotelService hotelService;private UUID sampleUUID = UUID.fromString("fd28ec06-6de5-4f68-9353-59793a5bdec2");@Beforepublic void setUp() {this.hotelService = mock(HotelService.class);when(hotelService.findOne(sampleUUID)).thenReturn(Mono.just(new Hotel(sampleUUID, "test")));HotelHandler hotelHandler = new HotelHandler(hotelService);this.client = WebTestClient.bindToRouterFunction(ApplicationRoutes.routes(hotelHandler)).build();}@Testpublic void testHotelGet() throws Exception {this.client.get().uri("/hotels/" + sampleUUID).exchange().expectStatus().isOk().expectBody(Hotel.class).isEqualTo(new Hotel(sampleUUID, "test"));} }結(jié)論
定義路由的功能方式絕對(duì)不同于基于注釋的方式–我喜歡這是定義端點(diǎn)以及如何處理端點(diǎn)調(diào)用的更為明確的方式,注釋總是給人更多的感覺(jué)。神奇。
我在github存儲(chǔ)庫(kù)中有完整的工作代碼,它可能比本文中的代碼更容易遵循。
翻譯自: https://www.javacodegeeks.com/2017/04/spring-web-flux-functional-style-cassandra-backend.html
總結(jié)
以上是生活随笔為你收集整理的Spring Web-Flux – Cassandra后端的功能样式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: idea 编写javafx_用JavaF
- 下一篇: PCF上的Spring Cloud合同和