Java Spring 5 Neue Funktion Funktionales Web Framework
Geben Sie ein Beispiel an
Beginnen wir mit einigen Auszügen aus der Beispielanwendung. Im Folgenden finden Sie eine Antwortinformationsbibliothek, die Personenobjekte enthüllt. Sehr ähnlich wie die traditionelle, nicht reagierende Informationsbibliothek, außer dass sie Flux <Person> und die traditionelle Rückgaberiste <Person> zurückgibt, und der Ort, an dem Mono <Person> Person zurückgibt. Mono <void> wird als Fertigstellungsflag verwendet: Zeigt an, wann der Speichern abgeschlossen ist.
public interface personRepository {mono <person> getPerson (int id); Flux <Person> Allpeople (); Mono <Void> SavePerson (Mono <Person> Person);}So enthüllen wir eine Bibliothek mit dem neuen funktionalen Web -Framework:
Routerfunction <?> Route = Route (get ("/person/{id}"), request -> {mono <person> person = mono.justorempy (request.PathVariable ("id") .map (integer :: valueof) .Then -Repository: GetPerson. .and (Route (get ("/person"), request -> {flux <person> people = repository.allpeople (); return response Antwort.OK (). Build (repository.saveperson (Person));}));Hier werden wir vorstellen, wie man läuft, zum Beispiel in Reactor Netty:
Httphandler httphandler = Routerfunktionen
Das Letzte, was zu tun ist, ist es auszuprobieren:
$ curl 'http: // localhost: 8080/Person/1' {"Name": "John Doe", "Alter": 42}Es gibt weitere Einführungen unten, lasst uns tiefer graben!
Kernkomponenten
Ich werde das Framework einführen, indem ich die Kernkomponenten gründlich erklären: Handlerfunktion, Routerfunktion und Filterfunktion. Diese drei Schnittstellen sowie alle anderen in dem Artikel beschriebenen Typen finden Sie im Paket org.springframework.web.reactive.Function.function.
Handlerfunktion
Der Ausgangspunkt dieses neuen Frameworks ist Handlerfunktion <T>, was im Grunde genommen Funktion <Anfrage, Antwort <T >> ist, wobei Anforderung und Antwort neu definiert sind und die unveränderliche Schnittstelle den zugrunde liegenden HTTP-Nachrichten JDK-8 DSL bereitstellt. Es ist ein bequemes Build -Instrument zum Aufbau von Reaktionsunternehmen, die dem, was Sie als Reaktionsmittel sehen, sehr ähnlich sind. Entsprechend der Annotation der Handlerfunktion ist eine Methode mit @RequestMapping.
Hier ist ein einfaches Beispiel für die Verarbeitungsfunktion "Hello World", die eine Antwortmeldung mit 200 Zuständen und einer Reihe von String zurückgibt:
HandlerFunction <String> helloWorld = request -> response.ok (). Body (fromObject ("Hallo Welt"));Wie wir im obigen Beispiel gesehen haben, reagieren die Handhabungsfunktionen durch Reaktorbasis vollständig an: Sie akzeptieren Fluss, Mono oder einen anderen entsprechenden Stream -Verlag als Antworttyp.
Eine Sache zu beachten ist, dass Handlerfunktion selbst keine Nebenwirkungen hat, da sie die Antwort zurückgibt, anstatt sie als Parameter zu behandeln (siehe Servlet.Service (ServletRequest, ServletResponse), das im Wesentlichen Biconsumer <ServletRequest, ServletResponse>) ist. Es gibt viele Vorteile von keinen Nebenwirkungen: leicht zu testen, zu schreiben und zu optimieren.
Routerfunktion
Die eingehende Anforderung wird mit Routerfunktion <t> (d. H. Funktion <anfordert, optional <Handlerfunktion <t >>) an die Handlerfunktion weitergeleitet und wird bei Übereinstimmung an den Handler weitergeleitet. Andernfalls wird ein leeres Ergebnis zurückgegeben. Die Routing -Methode funktioniert ähnlich der @RequestMapping -Annotation. Es gibt jedoch einen weiteren signifikanten Unterschied: Bei Anmerkungen wird die Route auf den Bereich beschränkt, den der kommentierte Wert ausdrücken kann, und es ist schwierig, mit der Überlagerung dieser Methoden umzugehen. Bei Verwendung der Routing -Methode ist der Code vorhanden und kann leicht überschrieben oder ersetzt werden.
Im Folgenden finden Sie ein Beispiel für eine Routing -Funktion mit einer eingebetteten Verarbeitungsfunktion. Es sieht ein bisschen lang aus, aber mach dir keine Sorgen: Wir werden einen Weg finden, es kürzer zu machen.
RouterFunction <String> helloWorldRoute = Request -> {if (request.path (). Equals ("/hello -world"))) {return optional.of (r -> response.ok (). Body (FromObject ("Hello World")); } else {return optional.empty (); }};Im Allgemeinen müssen keine vollständige Routing -Methode geschrieben werden, sondern statisch statisch Routerfunktionen einführen. Wenn das Urteil erfolgreich ist, wird die Verarbeitungsmethode zurückgegeben, sonst wird das leere Ergebnis zurückgegeben. Das Folgende ist das obige Beispiel mit der Routenmethode:
Routerfunction <String> helloWorldroute = Routerfunktionen.route (Anfrage -> request.Path (). Equals ("/hello -world"), request -> response.ok (). Body (fromObject ("Hallo Welt"));Sie können RequestPredicate (statisch) importieren.
Routerfunction <String> helloWorldroute = Routerfunctions.route (RequestPredicates.Path ("/Hello -World"), Request -Antwort.OK (). Body (FromObject ("Hello World")));Kombinationsfunktionen
Zwei Routing -Funktionen können eine neue Routing -Funktion bilden, Route zu einer der beiden Verarbeitungsfunktionen: Wenn die erste Funktion nicht übereinstimmt, wird die zweite ausgeführt. Sie können zwei Routing -Funktionen wie diesen kombinieren, indem Sie Routerfunktionen aufrufen. Und ():
Routerfunction <?> Route = Route (Pfad ("/hello -world"), request -> response.ok (). Body (fromObject ("hello wort"))) .und (Route (Pfad ("/the -Answer"), Anfrage -> Antwort.OK (). Body (FromObject ("42"));Wenn der Pfad übereinstimmt /hello world, wird der oben genannte "Hello World" reagieren, und wenn /the-the-the-the-Matches, wird er gleichzeitig "42" zurückgegeben. Wenn weder übereinstimmt, wird ein leeres Optional zurückgegeben. Beachten Sie, dass die kombinierten Routing -Funktionen nacheinander ausgeführt werden. Daher ist es sinnvoll, generische Funktionen vor die spezifische Funktion zu setzen.
Sie können auch Anforderungsprädikate durch Anruf und oder kombinieren. Dies funktioniert wie folgt: für und, wenn zwei angegebene Prädikate übereinstimmen, das Ergebnis prädikt übereinstimmt, und wenn einer der beiden Spiele, dann oder übereinstimmt. Zum Beispiel:
Routerfunction <?> Route = Route (Methode (httpMethod.get) .and (Path ("/Hello -World"), Request -Antwort.OK (). Body (FromObject ("Hello World")) .and (Route (Methode (Methode (httpMethod.get)) .And (Path ("/the -and -on -us -Answer"), Request -Afo. Antwort.OK (). Körper (fromObject ("42"))));Tatsächlich werden die meisten Prädikate in RequestPredicates kombiniert! Beispielsweise ist RequestPredicates.get (String) eine Zusammensetzung von RequestPredicate.Method (httpMethod) und RequestPredicate.Path (String). Daher können wir den obigen Code als:
Routerfunction <?> Route = Route (get ("/hello world"), request -> response.ok (). Body (fromObject ("hello wort")) .und (Route (get ("/the -Answer"), Anfrage -> Antwort.Methodenreferenz
Übrigens: Bisher haben wir alle Verarbeitungsfunktionen als Inline -Lambda -Ausdrücke geschrieben. Während dies in der Demo und in kurzen Beispielen gut abschneidet, muss gesagt werden, dass es eine Tendenz gibt, "Verwirrung" zu verursachen, da Sie zwei Bedenken mischen möchten: Anfordern Sie die Routing und die Bearbeitung anfordern. Wir möchten also sehen, ob es die Dinge einfacher machen kann. Zunächst erstellen wir eine Klasse, die den Verarbeitungscode enthält:
Klasse DemoHandler {public response <string> helloWorld (Anfrageanforderung) {return response.ok (). body (fromObject ("Hallo Welt"); }/ * http://www.manongjc.com/article/1590.html */public antwort <string> Theanswer (Request Request) {return response.ok (). body (fromObject ("42"); }}Beachten Sie, dass beide Methoden ein Flag haben, das mit der Verarbeitungsfunktion kompatibel ist. Auf diese Weise können wir Methodenreferenzen verwenden:
Demohandler Handler = New Demohandler (); // oder über Dirouterfunction <?> Route = Route (Get ("/hello-world"), Handler :: HelloWorld) .und (Route (Get ("/the-antwor"), Handler :: Theanwerswer));Filterfunktion
Der von der Routing -Funktion abgebildete Pfad kann durch Aufrufen von Routerfunktionen gefiltert werden. Filter (Filterfunktion <t, r>), wobei Filterfunktion <t, r> im Wesentlichen eine bifunktion <request, Handlerfunktion <t>, Antwort <R >> ist. Der Handler -Parameter der Funktion repräsentiert das nächste Element in der gesamten Kette: Dies ist eine typische Handlerfunktion. Wenn jedoch mehrere Filter angebracht sind, kann es auch eine weitere Filterfunktion sein. Fügen wir der Route einen Protokollfilter hinzu:
// http: //www.manongjc.comrouterfunction <?> Route = Route (Get ("/hello-world"), Handler :: HelloWorld) .and (Route (get ("/the-ant-the-ant-the-ant-the-ant-the-the-on-reibs"), Handler :: theanswer) .Filter (Anfrage, Nächstes). Antwort <?> Antwort = Next.Handle (Anfrage);Es ist zu beachten, dass es optional ist, den nächsten Handler anzurufen. Dies ist sehr nützlich bei Sicherheits- und Zwischenspeichern (z. B. als nächstes anrufen, wenn der Benutzer über ausreichende Berechtigungen verfügt).
Da Route eine unendliche Routing -Funktion ist, wissen wir, welche Art von Antwortinformationen der nächste Handler zurückkehren wird. Aus diesem Grund haben wir in unserem Filter eine Antwort <?> Und reagierten auf den Körper mit Objekt. In der Handlerklasse geben beide Methoden die Antwort <string> zurück, sodass es möglich sein sollte, einen String -Reaktionskörper zu haben. Wir können dies tun, indem wir Routerfunction.andSame () anstelle von und () verwenden. Diese Kombinationsmethode erfordert, dass die Parameter -Routing -Funktion vom gleichen Typ ist. Zum Beispiel können wir alle Antworten profitieren lassen:
Routerfunction <String> Route = Route (get ("/hello-world"), Handler :: helloWorld) .andSame (Route (get ("/the-antworer"), Handler :: TheansWer) .filter ((Anfrage, nächstes)-> {Antwort <string> Antwort = nächstes. Antwort.From (Antwort) .Body (fromObject (neukörper));Mit Anmerkungen können ähnliche Funktionen mit @ControllerAdvice und/oder Servletfilter implementiert werden.
Führen Sie den Server aus
All dies ist in Ordnung, aber eine Sache, die ich vergessen habe: Wie können wir diese Funktionen auf einem tatsächlichen HTTP -Server ausführen? Die Antwort erfolgt zweifellos, indem Sie eine andere Funktion aufrufen. Sie können die Routing -Funktion mithilfe von Routerfunktionen in HttPHandler () um konvertieren. HTTPHANDLER ist eine Antwortabstraktion, die in den Frühjahr 5.0 M1 eingeführt wird: Sie können auf verschiedenen Reaktionslaufzeiten ausgeführt werden: Reaktor Netty, RxNetty, Servlet 3.1+ und Motor. In diesem Beispiel haben wir gezeigt, wie es wie die Ausführung von Route in Reactor Netty ist. Für Tomcat sieht es so aus:
Httphandler httphandler = Routerfunktionen.tohttphandler (Route); System.getProperty ("java.io.tmpdir")); tomcat.addServlet (RootContext, "Servlet", Servlet); RootContext.AddServletMapping ("/", "Servlet"); Tomcatserver.start ();Eine Sache zu beachten ist, dass der obige Code nicht vom Kontext der Spring -Anwendung abhängt. Wie JDBCtemplate und andere Frühlings -Dienstprogrammklassen ist die Verwendung des Anwendungskontexts optional: Sie können die Handler- und Routing -Funktionen im Kontext verbinden, dies ist jedoch nicht erforderlich.
Beachten Sie auch, dass Sie die Routing -Funktion auch in Handlermapping konvertieren können, damit sie im DispatcherHandler ausgeführt werden kann (kann möglicherweise eine responsive @Controller erfordern).
abschließend
Lassen Sie mich eine Schlussfolgerung durch eine kurze Zusammenfassung ziehen:
Um Ihnen ein umfassenderes Verständnis zu vermitteln, habe ich ein einfaches Beispielprojekt mit dem funktionalen Web -Framework erstellt. Adresse herunterladen
Danke fürs Lesen, ich hoffe, es kann Ihnen helfen. Vielen Dank für Ihre Unterstützung für diese Seite!