Routing in Play-Anwendungen in Java

Routing in Play-Anwendungen in Java

1. Überblick

Routing ist ein gängiges Konzept, das in den meisten Webentwicklungs-Frameworks einschließlichSpring MVC vorkommt.

Eine Route ist ein URL-Muster, das einem Handler zugeordnet ist. Der Handler kann eine physische Datei sein, z. B. ein herunterladbares Asset in der Webanwendung oder eine Klasse, die die Anforderung verarbeitet, z. B. ein Controller in einer MVC-Anwendung.

In diesem Tutorial werden wir den Aspekt des Routings bei der Entwicklung von Webanwendungen mitPlay Framework untersuchen.

2. Konfiguration

Zunächst müssen wir eine Java Play-Anwendung erstellen. Die Details zum Einrichten des Play Frameworks auf einem Computer finden Sie in unserenintroductory article.

Am Ende des Setups sollten wir eine funktionierende Play-Anwendung haben, auf die wir über einen Browser zugreifen können.

3. HTTP-Routing

Woher weiß Play, welcher Controller zu konsultieren ist, wenn wir eine HTTP-Anfrage senden? Die Antwort auf diese Frage liegt in der Konfigurationsdatei vonapp/conf/routes.

Der Router von Play übersetzt HTTP-Anforderungen in Aktionsaufrufe. HTTP requests are considered to be events in MVC architecture und der Router reagieren darauf, indem sie in der Dateiroutes nachfragen, für welchen Controller und welche Aktion in diesem Controller ausgeführt werden soll.

Jedes dieser Ereignisse stellt einem Router zwei Parameter zur Verfügung: einen Anforderungspfad mit seiner Abfragezeichenfolge und die HTTP-Methode der Anforderung.

4. Grundlegendes Routing mit Spiel

Damit der Router seine Arbeit erledigen kann, muss die Dateiconf/routesZuordnungen von HTTP-Methoden und URI-Mustern zu geeigneten Controller-Aktionen definieren:

GET     /     controllers.HomeController.index
GET     /     assets/*file controllers.Assets.versioned(path="/public", file: Asset)

Alle Routendateien müssen auch die statischen Ressourcen im Ordnerplay-routing/publiczuordnen, die dem Client auf dem Endpunkt/assetszur Verfügung stehen. Beachten Sie die Syntax zum Definieren von HTTP-Routen und die Controller-Aktionspacedes URI-Mustersspaceder HTTP-Methode.

5. URI-Muster

In diesem Abschnitt werden wir ein wenig auf URI-Muster eingehen.

5.1. Statische URI-Muster

Die ersten drei oben genannten URI-Muster sind statisch. Dies bedeutet, dass die Zuordnung der URLs zu Ressourcen ohne weitere Verarbeitung in den Controller-Aktionen erfolgt.

Solange eine Controllermethode aufgerufen wird, gibt sie eine statische Ressource zurück, deren Inhalt vor der Anforderung ermittelt wird.

5.2. Dynamische URI-Muster

Das letzte obige URI-Muster ist dynamisch. Dies bedeutet, dass die Controller-Aktion, die eine Anforderung für diese URIs bedient, einige Informationen aus der Anforderung benötigt, um die Antwort zu bestimmen. In diesem Fall wird ein Dateiname erwartet.

Normalerweise empfängt der Router ein Ereignis, wählt den Pfad aus der URL aus, decodiert die Segmente und leitet sie an den Controller weiter.

Pfad- und Abfrageparameter werden dann als Parameter in die Controller-Aktion eingefügt. Wir werden dies in den nächsten Abschnitten anhand eines Beispiels demonstrieren.

6. Erweitertes Routing mit Spiel

In diesem Abschnitt werden erweiterte Optionen für das Routing mithilfe dynamischer URI-Muster ausführlich erläutert.

6.1. Einfache Pfadparameter

Einfache Pfadparameter sind unbenannte Parameter in einer Anforderungs-URL, die nach dem Host und dem Port erscheinen und in der Reihenfolge ihres Auftretens analysiert werden.

Erstellen Sie inplay-routing/app/HomeController.java eine neue Aktion:

public Result greet(String name) {
    return ok("Hello " + name);
}

Wir möchten in der Lage sein, einen Pfadparameter aus der Anforderungs-URL auszuwählen und ihn dem Variablennamen zuzuordnen.

Der Router erhält diese Werte aus einer Routenkonfiguration.

Öffnen wir alsoplay-routing/conf/routes und erstellen eine Zuordnung für diese neue Aktion:

GET     /greet/:name     controllers.HomeController.greet(name: String)

Beachten Sie, wie wir einem Router mitteilen, dass der Name ein dynamisches Pfadsegment mit Doppelpunktsyntax ist, und ihn dann als Parameter an den Aufruf der Begrüßungsaktion übergeben.

Laden wir nunhttp://locahost:9000/greet/john in den Browser und wir werden mit Namen begrüßt:

Hello john

Es kommt also vor, dassif our action parameter is of string type, we may pass it during the action call without specifying the parameter type ist, obwohl dies für andere Typen nicht dasselbe ist.

Lassen Sie uns den Endpunkt von/greetmit Altersinformationen aufpeppen.

Zurück zur Begrüßungsaktion vonHomeControllerändern wir sie in:

public Result greet(String name, int age) {
    return ok("Hello " + name + ", you are " + age + " years old");
}

Und der Weg zu:

GET     /greet/:name/:age               controllers.HomeController.greet(name: String, age: Integer)

Beachten Sie auch die Scala-Syntax zum Deklarieren einer Variablen,age: Integer. In Java würden wir die Syntax vonInteger ageverwenden. Das Play Framework wurde in Scala erstellt. Folglich gibt es eine Menge Scala-Syntax.

Hello john, you are 26 years old

6.2. Platzhalter in Pfadparametern

In unserer Routenkonfigurationsdatei ist die letzte Zuordnung:

GET     /assets/*file  controllers.Assets.versioned(path="/public", file: Asset)

Im dynamischen Teil des Pfades wird ein Platzhalter verwendet. Was wir Play sagen, ist, dass jeder Wert, der*file in der tatsächlichen Anforderung ersetzt, als Ganzes analysiert und nicht wie in anderen Fällen von Pfadparametern dekodiert werden sollte.

In diesem Beispiel ist der Controller ein integrierter Controller,Assets, mit dem der Client Dateien aus dem Ordnerplay-routing/public herunterladen kann. Wenn wirhttp://localhost:9000/assets/images/favicon.png laden, sollte das Bild des Play-Favicons im Browser angezeigt werden, da es im Ordner/public/images vorhanden ist.

Erstellen wir unsere eigene Beispielaktion inHomeController.java:

public Result introduceMe(String data) {
    String[] clientData = data.split(",");
    return ok("Your name is " + clientData[0] + ", you are " + clientData[1] + " years old");
}

Beachten Sie, dass wir in dieser Aktion einen String-Parameter erhalten und unsere Logik anwenden, um ihn zu dekodieren. In diesem Fall besteht die Logik darin, ein durch Kommas getrenntesString in ein Array aufzuteilen. Bisher waren wir auf einen Router angewiesen, um diese Daten für uns zu dekodieren.

Mit Wildcards sind wir auf uns allein gestellt. Wir hoffen, dass der Client bei der Übergabe dieser Daten die richtige Syntax erhält. Idealerweisewe should validate the incoming String before using it.

Erstellen wir eine Route zu dieser Aktion:

GET   /*data   controllers.HomeController.introduceMe(data)

Laden Sie nun die URLhttp://localhost:9000/john,26. Dies wird drucken:

Your name is john, you are 26 years old

6.3. Regex in Pfadparametern

Genau wie bei Platzhaltern können wir für den dynamischen Teil reguläre Ausdrücke verwenden. Fügen wir eine Aktion hinzu, die eine Zahl erhält und ihr Quadrat zurückgibt:

public Result squareMe(Long num) {
    return ok(num + " Squared is " + (num * num));
}

Jetzt fügen wir die Route hinzu:

GET   /square/$num<[0-9]+>   controllers.HomeController.squareMe(num:Long)

Platzieren wir diese Route unter der Route vonintroduceMe, um ein neues Konzept einzuführen. Mit dieser Routing-Konfiguration können nur Routen verarbeitet werden, bei denen der Regex-Teil eine positive Ganzzahl ist.

Wenn wir nun die Route wie im vorherigen Absatz beschrieben platziert haben undhttp://localhost:9000/square/2 laden, sollten wir mitArrayIndexOutOfBoundsException begrüßt werden:

image

Wenn wir die Fehlerprotokolle in der Serverkonsole überprüfen, werden wir feststellen, dass der Aktionsaufruf tatsächlich für die Aktion vonintroduceMeund nicht für die Aktion vonsquareMeausgeführt wurde. Wie bereits zu Platzhaltern erwähnt, sind wir auf uns allein gestellt und haben eingehende Daten nicht überprüft.

Anstelle einer durch Kommas getrennten Zeichenfolge wurde die MethodeintroduceMe mit der Zeichenfolge „square/2“ aufgerufen. Folglich haben wir nach der Aufteilung ein Array der Größe eins erhalten. Der Versuch, den Indexzu erreichen, löste dann die Ausnahme aus.

Natürlich würden wir erwarten, dass der Aufruf an die MethodesquareMeweitergeleitet wird. Warum wurde es anintroduceMe weitergeleitet? Der Grund ist eine Wiedergabefunktion, die wir als nächstes mitRouting Priority. behandeln werden

7. Routing-Priorität

Wenn es einen Konflikt zwischen Routen gibt, da zwischensquareMe undintroduceMe liegt, dannPlay picks the first route in declaration order.

Warum gibt es einen Konflikt? Aufgrund des Platzhalterkontexts stimmt Pfad/data mit jeder Anforderungs-URL außer dem Basispfad/ überein. * Jede Route, deren URI-Muster Platzhalter verwendet, sollte in der letzten Reihenfolge angezeigt werden.

Ändern Sie nun die Deklarationsreihenfolge der Routen so, dass die Route vonintroduceMenachsquareMe kommt, und laden Sie sie neu:

2 Squared is 4

Um die Leistung regulärer Ausdrücke in einer Route zu testen, laden Siehttp://locahost:9000/square/-1. Ein Router stimmt nicht mit der RoutesquareMeüberein. Stattdessen stimmt es mitintroduceMe, überein und wir erhalten dieArrayIndexOutOfBoundsException erneut.

Dies liegt daran, dass-1 nicht mit dem angegebenen regulären Ausdruck übereinstimmt und auch kein alphabetisches Zeichen.

8. Parameter

Bis zu diesem Punkt haben wir die Syntax zum Deklarieren von Parametertypen in der Routendatei behandelt.

In diesem Abschnitt werden weitere Optionen vorgestellt, die uns beim Umgang mit Parametern in Routen zur Verfügung stehen.

8.1. Parameter mit festen Werten

Manchmal möchten wir einen festen Wert für einen Parameter verwenden. Auf diese Weise weisen wir Play an, den angegebenen Pfadparameter zu verwenden. Wenn der Anforderungskontext der Pfad/ ist, verwenden Sie einen bestimmten festen Wert.

Eine andere Betrachtungsweise besteht darin, zwei Endpunkte oder Kontextpfade zu haben, die zur gleichen Controller-Aktion führen - wobei für einen Endpunkt ein Parameter aus der Anforderungs-URL und für den Fall, dass der Parameter nicht vorhanden ist, der andere standardmäßig verwendet wird.

Um dies zu demonstrieren, fügen wir denHomeController eine Aktionwriter()hinzu:

public Result writer() {
    return ok("Routing in Play by example");
}

Angenommen, wir möchten nicht immer, dass unsere APIString zurückgibt:

Routing in Play by example

Wir möchten dies steuern, indem wir den Namen eines Autors des Artikels zusammen mit der Anforderung senden und standardmäßig den festen Wertexample verwenden, wenn die Anforderung nicht den Parameterauthor enthält.

Ändern wir also die Aktion vonwriterweiter, indem wir einen Parameter hinzufügen:

public Result writer(String author) {
    return ok("REST API with Play by " + author);
}

Sehen wir uns auch an, wie Sie der Route einen Festwertparameter hinzufügen:

GET     /writer           controllers.HomeController.writer(author = "example")
GET     /writer/:author   controllers.HomeController.writer(author: String)

Beachten Sie, dass wir jetzt zwei separate Routen haben, die alle zur AktionHomeController.indexanstelle einer führen.

Wenn wir jetzthttp://localhost:9000/writer aus dem Browser laden, erhalten wir:

Routing in Play by example

Und wenn wirhttp://localhost:9000/writer/john laden, erhalten wir:

Routing in Play by john

8.2. Parameter mit Standardwerten

Parameter können nicht nur feste Werte haben, sondern auch Standardwerte. Beide liefern Fallback-Werte für die Controller-Aktionsparameter, falls die Anforderung nicht die erforderlichen Werte liefert.

Der Unterschied zwischen den beiden ist, dassfixed values are used as a fallback for path parameters while default values are used as a fallback for query parameters.

Pfadparameter haben die Formhttp://localhost:9000/param1/param2 und Abfrageparameter haben die Formhttp://localhost:9000/?param1=value1¶m2=value2.

Der zweite Unterschied besteht in der Syntax der Deklaration der beiden in einer Route. Parameter mit festen Werten verwenden den Zuweisungsoperator wie in:

author = "example"

Während Standardwerte eine andere Art der Zuweisung verwenden:

author ?= "example"

Wir verwenden den Operator?=, derauthor unter bestimmten Bedingungenexample zuweist, falls festgestellt wird, dassauthor keinen Wert enthält.

Um eine vollständige Demonstration zu erhalten, erstellen wir die AktionHomeController.writer. Angenommen, neben dem Namen des Autors, der ein Pfadparameter ist, möchten wir auch authorid als Abfrageparameter übergeben, der standardmäßig1 sein sollte, wenn er nicht in der Anforderung übergeben wird.

Wir ändern die Aktion vonwriterin:

public Result writer(String author, int id) {
    return ok("Routing in Play by: " + author + " ID: " + id);
}

und die Routen vonwriterzu:

GET     /writer           controllers.HomeController.writer(author="example", id: Int ?= 1)
GET     /writer/:author   controllers.HomeController.writer(author: String, id: Int ?= 1)

Jetzt laden wirhttp://localhost:9000/writer und sehen:

Routing in Play by: example ID: 1

Wenn wirhttp://localhost:9000/writer?id=10 treffen, erhalten wir:

Routing in Play by: example ID: 10
Routing in Play by: john ID: 1

Und schließlich kehrthttp://localhost:9000/writer/john?id=5 zurück:

Routing in Play by: john ID: 5

9. Fazit

In diesem Artikel haben wir uns mit dem Thema Routing in Play-Anwendungen befasst. Wir haben auch einen Artikel überbuilding a RESTful API with Play Framework, in dem die Routing-Konzepte in diesem Tutorial in einem praktischen Beispiel angewendet werden.

Wie üblich ist der Quellcode für dieses Tutorialover on GitHub verfügbar.