Giter Site home page Giter Site logo

nc-spring-reactor's Introduction

NightClazz Reactor / Code Lab

Vous avez équipé votre maison d'un capteur de température, et vous souhaitez faire un programme qui récupère ses valeurs. Pour le moment nous simulerons le capteur, en émettant simplement un flux.

Exercice 1 :

Créer un Mono ou un Flux à partir d'une valeur : https://projectreactor.io/docs/core/release/reference/#_simple_ways_to_create_a_flux_or_mono_and_subscribe_to_it

Transformer une valeur : https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#map-java.util.function.Function-

Lancez les tests dans TemperatureServiceTest.

  • Implémentez la méthode getLastTemperatureAsFloat pour qu'elle retourne la température dans un Mono Le test getLastTemperatureAsFloat_should_emit_LAST_TEMPERATURE devrait réussir.

  • Implémentez la méthode getLastTemperatureData pour qu'elle souscrive au Publisher renvoyé par getLastTemperatureAsFloat et transforme le résultat émis en Temperature. Le test getLastTemperatureData_should_emit_one_value devrait réussir.

  • Complétez la méthode getLastTemperatureData pour qu'elle transforme la température en farenheit. Le test getLastTemperatureData_should_emit_LAST_TEMPERATURE_in_farenheit() devrait réussir.

Vous aurez besoin de transformer votre température avec la méthode toFahrenheit

  • Complétez la méthode getLastTemperatureDatas pour qu'elle retourne un Flux de TemperatureData Le test getLastTemperatureDatas_should_emit_all_temperatures devrait réussir.

Les valeurs des températures sont dans LAST_TEMPERATURES

  • Complétez la méthode generateTemperatureData pour qu'elle retourne un flux infini de TemperatureData. Cette méthode doit émettre un élément toutes les 100ms.

Vous aurez besoin de l'opérateur Flux.interval() pour générer le Flux Vous pouvez utiliser la méthode generateFloat()

Exercice 2 :

Le but de cet exercice est de migrer notre controller en annotation vers une RouterFunction.

Commencez par lancer les tests d'intégration dans TemperatureHandlerTest.

  1. Refactorisez le code pour utiliser les router functions.

1.1. Créez une classe WebConfig pour définir vos RouterFunction

    @Configuration
    @EnableWebFlux
    public class WebConfig implements WebFluxConfigurer {

    }

1.2. Créez des beans pour vos RouterFunction

https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-fn-router-functions

Vous devez migrer 3 routes :

  • @GetMapping(path = "/temperature/last")
  • @GetMapping(path = "/temperature/lasts")
  • @GetMapping(path = "/temperature-event",produces = MediaType.TEXT_EVENT_STREAM_VALUE)

Commencez par les tester pour vérifier que le projet fonctionne, et lancez les tests d'intégration dans TemperatureHandlerTest

    @Bean
    public RouterFunction<?> router() {
        return route()
                .path("/...", builder ->
                        builder.nest(//
                                accept(MediaType.ALL), builder2 -> //
                                        builder2//
                                                .GET("/r1", request -> temperatureHandler.getLastTemperatureData())
                                                .GET("/r2", request -> temperatureHandler...())
                                                .build()
                        ))
                .before(this::logRequest)
                .build();
    }

    @Bean
    public RouterFunction<?> routerSSE() {
        return route()
                .GET("/r3", request -> temperatureHandler.getTemperatureData())
                .build();
    }
  1. Transformez la classe TemperatureHandler pour que vos méthodes retournent des Mono<ServerResponse>.

Voici un exemple basique :

    public Mono<ServerResponse> getLastTemperatureData() {
        return ServerResponse.ok()
                .contentType(MediaType.APPLICATION_JSON)
                .body(temperatureService.getLastTemperatureData(), Temperature.class);
    }

Cet exemple fonctionne, mais ne gère pas le cas où notre méthode ne renvoie aucune valeur. Voici un autre exemple :

    public Mono<ServerResponse> demo2() {
        return temperatureService.getLastTemperatureData()
                .flatMap(res -> ok()
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(fromObject(res)))
                .switchIfEmpty(notFound().build());
    }
  • Vous pouvez également gérer le cas où votre publisher vous renvoie un signal d'erreur :
    public Mono<ServerResponse> demoWithError() {
        return temperatureService.getLastTemperatureData()
                .flatMap(res -> ok()
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(fromObject(res)))
                .doOnError(res->ServerResponse.status(500).build())
                .switchIfEmpty(notFound().build());
    }
  • Le test d'intégration doit toujours fonctionner, néanmoins vous allez devoir ajouter votre classe de configuration dans la configuration de votre test :
     @RunWith(SpringRunner.class)
     @WebFluxTest(TemperatureHandler.class)
     @ContextConfiguration(classes = {
             TemperatureHandler.class,
             TemperatureService.class,
             WebConfig.class
     })
     public class TemperatureHandlerTest {
     }
  1. Améliorez vos routerFunction

Ajoutez la méthode .before() dans vos router functions pour logguer toutes les requêtes entrantes.

Exercice 3 :

Dans cet exercice nous allons appeler les API précédemment créées. Pour cela nous allons utiliser WebClient ( https://www.baeldung.com/spring-5-webclient ), que nous allons initialiser puis utiliser.

Le WebClient est initialisé dans notre constructeur.

Pour cet exercice les tests se feront grâce à la classe. Vous devez préalablement démarrer votre module API.

  1. Mono

Implémentez la méthode getLastData() pour appeler votre route /temperature/last qui renvoie un Mono

  1. Flux

Implémentez la méthode getLastDatas() pour appeler votre route /temperature/lasts qui renvoie un Flux

  1. ServerSentEvent

Implémentez la méthode getTemperatureEvent() pour appeler votre route /temperature-event qui renvoie des ServerSentEvent. Pour ce cas, vous devrez transformer votre Flux de cette manière : .bodyToFlux(typeReference);

Exercice 4 :

Nous souhaitons souscrire aux événements provenants du module API (http://localhost:8081/temperature-event) et effectuer plusieurs opérations :

  • aggrégation de plusieurs températures en une seule
  • calculer la temperature moyenne de cette liste
  • persister la température moyenne en base de données
  1. Le module Data dispose des dépendances suivantes
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
    </dependency>
    <dependency>
        <groupId>de.flapdoodle.embed</groupId>
        <artifactId>de.flapdoodle.embed.mongo</artifactId>
        <version>2.2.0</version>
    </dependency>
  1. Ajoutez une interface TemperatureRepository utilisez la classe document Temperature à votre disposition.

  2. Dans la classe DataService modifiez la méthode temperatureEventFlux() afin qu'elle effectue les opérations suivantes :

    1. Souscrire aux événements en utilisant la méthode webClient.getTemperatureEvent()

    2. Un mapping de type de Flux<ServerSentEvent> vers Temperature Vous pouvez utiliser la classe JacksonConverter

    3. Un calcul de moyenne de température pour 10 températures Vous pouvez utiliser la méthode computeAverage(List<Float> floatList)

    4. La création d'un document mongo Vous pouvez utiliser la méthode buildDocument(Float aFloat)

    5. La persistence en base de données

  3. Terminez d'implémenter la méthode DataController#getAll() afin qu'elle retourne tous les documents de la collection temperature.

  4. Testez dans un navigateur que votre implémentation fonctionne via la route http://localhost:8082/all

Exercice 5 :

Nous souhaitons que notre module front affiche en temps réel les nouvelles moyennes de températures calculées et persistées. Pour ce faire vous allez mettre en oeuvre l'API Processor.

  1. Ecrivez une classe TemperatureProcessor qui exposera des beans de DirectProcessor et de FluxSink.

    On utilisera l'implémentation DirectProcessor, l'API expose deux méthodes permettant sa mise en oeuvre :

    • DirectProcessor.create() : Retourne une instance de DirectProcessor sur la quelle il est possible d'effectuer une souscription
    • DirectProcessor#sink() : Retourne une instance de FluxSink qui permet de pousser de la donnée
  2. Modifier la classe MongoListener afin que cette dernière notifie le Processor de chaque document persisté

  3. Completez la méthode DataController#getTemperatureEvent() afin de souscrire au Processor

    • Vous pouvez chaîner l'opérateur log() afin d'afficher des logs sur les connexions en cours
  4. Exécutez le front afin de vérifier le bon fonctionnement

nc-spring-reactor's People

Contributors

mboix avatar remieven avatar sebvelay avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.