Introduksjon til Functional Web Framework våren 5

1. Introduksjon

Spring WebFlux er et nytt funksjonelt nettrammeverk bygget med reaktive prinsipper.

I denne opplæringen lærer vi hvordan vi kan jobbe med det i praksis.

Vi baserer dette på vår eksisterende guide til Spring 5 WebFlux. I denne guiden opprettet vi en enkel reaktiv REST-applikasjon ved hjelp av kommentarbaserte komponenter. Her bruker vi det funksjonelle rammeverket i stedet.

2. Maven avhengighet

Vi trenger det samme spring-boot-starter-webflux avhengighet som definert i forrige artikkel:

 org.springframework.boot spring-boot-starter-webflux 2.2.6.RELEASE 

3. Funksjonell Web Framework

Det funksjonelle nettrammeverket introduserer en ny programmeringsmodell der vi bruker funksjoner til å rute og håndtere forespørsler.

I motsetning til den merknadsbaserte modellen der vi bruker merkekartlegginger, her skal vi bruke HandlerFunction og RouterFunctions.

På samme måte, som i de merkede kontrollerne, er den funksjonelle endepunkttilnærmingen bygget på den samme reaktive stakken.

3.1. HandlerFunction

De HandlerFunction representerer en funksjon som genererer svar for forespørsler som er sendt til dem:

@FunctionalInterface offentlig grensesnitt HandlerFunction {Monohåndtak (ServerRequest-forespørsel); }

Dette grensesnittet er primært en Funksjon, som oppfører seg veldig som en servlet.

Selv om, sammenlignet med en standard Servlet # service (ServletRequest req, ServletResponse res), HandlerFunction tar ikke svar som inputparameter.

3.2. RouterFunction

RouterFunction fungerer som et alternativ til @RequestMapping kommentar. Vi kan bruke den til å rute forespørsler til behandlerfunksjonene:

@FunctionalInterface offentlig grensesnitt RouterFunction {Mono rute (ServerRequest-forespørsel); // ...}

Vanligvis kan vi importere hjelperfunksjonen RouterFunctions.route () for å lage ruter, i stedet for å skrive en komplett ruterfunksjon.

Det lar oss rute forespørsler ved å bruke en RequestPredicate. Når predikatet blir matchet, returneres det andre argumentet, behandlerfunksjonen:

offentlig statisk RouterFunction-rute (RequestPredicate predicate, HandlerFunction handlerFunction)

Fordi det rute() metoden returnerer a RouterFunction, kan vi kjede det for å bygge kraftige og komplekse rutingsopplegg.

4. Reaktiv REST-applikasjon ved bruk av funksjonelt web

I vår forrige guide opprettet vi en enkel Ansattes ledelse REST-applikasjonen bruker @RestController og WebClient.

La oss nå implementere den samme logikken ved hjelp av ruteren og behandlerfunksjonene.

Først, vi trenger å lage ruter ved hjelp av RouterFunction å publisere og konsumere våre reaktive strømmer av Ansatts.

Ruter er registrert som vårbønner og kan opprettes i alle konfigurasjonsklasser.

4.1. Enkel ressurs

La oss lage vår første rute ved hjelp av RouterFunction som utgir en singel Ansatt ressurs:

@Bean RouterFunction getEmployeeByIdRoute () {returrute (GET ("/ ansatte / {id}"), req -> ok (). Body (ansatteRepository (). FindEmployeeById (req.pathVariable ("id")), Employee.class )); }

Det første argumentet er et forespørselspredikat. Legg merke til hvordan vi brukte en statisk importert RequestPredicates.GET metoden her. Den andre parameteren definerer en behandlerfunksjon som skal brukes hvis predikatet gjelder.

Med andre ord ruter eksemplet ovenfor alle GET-forespørslene om / ansatte / {id} til EmployeeRepository # findEmployeeById (streng-id) metode.

4.2. Samlingsressurs

Deretter, for å publisere en samlingsressurs, la oss legge til en annen rute:

@Bean RouterFunction getAllEmployeesRoute () {returrute (GET ("/ ansatte"), req -> ok (). Body (ansatteRepository (). FindAllEmployees (), Employee.class)); }

4.3. Enkel ressursoppdatering

Til slutt, la oss legge til en rute for oppdatering av Ansatt ressurs:

@Bean RouterFunction updateEmployeeRoute () {returrute (POST ("/ ansatte / oppdatering"), req -> req.body (toMono (Employee.class)). DoOnNext (ansatteRepository () :: updateEmployee) .then (ok () .bygge())); }

5. Komponere ruter

Vi kan også komponere rutene sammen i en enkelt rutefunksjon.

La oss se hvordan du kan kombinere rutene som er opprettet ovenfor:

@Bean RouterFunction ComponedRoutes () {returrute (GET ("/ ansatte"), req -> ok (). Kropp (medarbeiderRepository (). FindAllEmployees (), ansatt.klasse) / {id} "), req -> ok (). body (employeeRepository (). findEmployeeById (req.pathVariable (" id ")), Employee.class))) .and (route (POST (" / ansatte / oppdatering) "), req -> req.body (toMono (Employee.class)) .doOnNext (employeeRepository () :: updateEmployee) .then (ok (). build ()))); }

Her har vi brukt RouterFunction.and () for å kombinere rutene våre.

Til slutt har vi implementert den komplette REST API som trengs for vår Ansattes ledelse applikasjon, ved hjelp av rutere og håndterere.

For å kjøre applikasjonen kan vi enten bruke separate ruter eller singelen, sammensatt en som vi opprettet ovenfor.

6. Testing av ruter

Vi kan bruke WebTestClient for å teste rutene våre.

For å gjøre det, må vi først binde rutene ved hjelp av bindToRouterFunction metode og deretter bygge testklientforekomsten.

La oss teste vår getEmployeeByIdRoute:

@Test offentlig ugyldig givenEmployeeId_whenGetEmployeeById_thenCorrectEmployee () {WebTestClient client = WebTestClient .bindToRouterFunction (config.getEmployeeByIdRoute ()) .build (); Ansatt ansatt = ny ansatt ("1", "Ansatt 1"); gitt (employeeRepository.findEmployeeById ("1")). vilReturn (Mono.just (ansatt)); client.get () .uri ("/ ansatte / 1") .bytte () .expectStatus () .isOk () .expectBody (ansatt.klasse) .isEqualTo (ansatt); }

og lignende getAllEmployeesRoute:

@Test offentlig ugyldig nårGetAllEmployees_thenCorrectEmployees () {WebTestClient client = WebTestClient .bindToRouterFunction (config.getAllEmployeesRoute ()) .build (); Liste ansatte = Arrays.asList (ny ansatt ("1", "ansatt 1"), ny ansatt ("2", "ansatt 2")); FluxmedarbeiderFlux = Flux.fromIterable (ansatte); gitt (employeeRepository.findAllEmployees ()). willReturn (employeeFlux); client.get () .uri ("/ ansatte") .utveksling () .expectStatus () .isOk () .expectBodyList (ansatt.klasse) .isEqualTo (ansatte); }

Vi kan også teste vår updateEmployeeRoute ved å hevde at vår Ansatt forekomst oppdateres via Ansattes depot:

@Test offentlig ugyldig nårUpdateEmployee_thenEmployeeUpdated () {WebTestClient client = WebTestClient .bindToRouterFunction (config.updateEmployeeRoute ()) .build (); Ansatt ansatt = ny ansatt ("1", "Medarbeider 1 oppdatert"); client.post () .uri ("/ ansatte / oppdatering") .body (Mono.just (ansatt), ansatt.klasse) .exchange () .expectStatus () .isOk (); verifisere (medarbeiderregister) .oppdatere medarbeider (ansatt); }

For mer informasjon om testing med WebTestClient se vår veiledning om å jobbe med WebClient og WebTestClient.

7. Oppsummering

I denne opplæringen introduserte vi det nye funksjonelle nettrammeverket våren 5 og så på de to kjernegrensesnittene - RouterFunction og HandlerFunction. Vi lærte også hvordan vi kan lage forskjellige ruter for å håndtere forespørselen og sende svaret.

I tillegg gjenskape vi vår Ansattes ledelse applikasjon introdusert i guide til Spring 5 WebFlux med den funksjonelle endepunktmodellen.

Som alltid kan hele kildekoden bli funnet på Github.


$config[zx-auto] not found$config[zx-overlay] not found