Routing in Play-applicaties in Java

1. Overzicht

Routing is een veelgebruikt concept dat voorkomt in de meeste webontwikkelingsframeworks, waaronder Spring MVC.

Een route is een URL-patroon dat is toegewezen aan een handler. De handler kan een fysiek bestand zijn, zoals een downloadbaar activum in de webtoepassing of een klasse die het verzoek verwerkt, zoals een controller in een MVC-toepassing.

In deze tutorial onderzoeken we het aspect van routing bij het ontwikkelen van webapplicaties met het Play Framework.

2. Installatie

Eerst moeten we een Java Play-applicatie maken. De details over het instellen van het Play Framework op een machine zijn beschikbaar in ons inleidende artikel.

Aan het einde van de installatie zouden we een werkende Play-applicatie moeten hebben die we via een browser kunnen openen.

3. HTTP-routering

Dus hoe weet Play welke controller moet worden geraadpleegd wanneer we een HTTP-verzoek verzenden? Het antwoord op deze vraag ligt in de app / conf / routes configuratiebestand.

De router van Play vertaalt HTTP-verzoeken in actieoproepen. HTTP-verzoeken worden beschouwd als gebeurtenissen in de MVC-architectuur en de router reageert erop door de routes bestand voor welke controller en welke actie in die controller moet worden uitgevoerd.

Elk van deze gebeurtenissen levert een router twee parameters: een verzoekpad met de bijbehorende queryreeks en de HTTP-methode van het verzoek.

4. Basisroutering met spelen

Om de router zijn werk te laten doen, moet de conf / routes bestand moet toewijzingen van HTTP-methoden en URI-patronen aan de juiste controlleracties definiëren:

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

Alle routes-bestanden moeten ook de statische bronnen in het play-routing / openbaar map beschikbaar voor de klant op het /middelen eindpunt.

Let op de syntaxis van het definiëren van HTTP-routes en de HTTP-methode ruimte URI-patroon ruimte controller actie.

5. URI-patronen

In deze sectie zullen we een beetje ingaan op URI-patronen.

5.1. Statische URI-patronen

De eerste drie URI-patronen hierboven zijn statisch. Dit betekent dat de toewijzing van de URL's aan bronnen plaatsvindt zonder enige verdere verwerking in de acties van de controller.

Zolang een controllermethode wordt aangeroepen, retourneert deze een statische bron waarvan de inhoud is bepaald vóór het verzoek.

5.2. Dynamische URI-patronen

Het laatste URI-patroon hierboven is dynamisch. Dit betekent dat de controlleractie die een verzoek op deze URI's uitvoert, enige informatie uit het verzoek nodig heeft om het antwoord te bepalen. In het bovenstaande geval verwacht het een bestandsnaam.

De normale volgorde van gebeurtenissen is dat de router een gebeurtenis ontvangt, het pad van de URL kiest, de segmenten decodeert en deze doorgeeft aan de controller.

Pad- en queryparameters worden vervolgens als parameters in de controlleractie geïnjecteerd. We zullen dit demonstreren met een voorbeeld in de volgende secties.

6. Geavanceerde routering met spelen

In deze sectie bespreken we geavanceerde opties in routering met behulp van dynamische URI-patronen in detail.

6.1. Eenvoudige padparameters

Eenvoudige padparameters zijn niet nader genoemde parameters in een verzoek-URL die verschijnen na de host en poort en worden geparseerd in volgorde van weergave.

Binnen play-routing / app / HomeController.java, laten we een nieuwe actie maken:

public Resultaat greet (String naam) {return ok ("Hallo" + naam); }

We willen een padparameter kunnen kiezen uit de verzoek-URL en deze toewijzen aan de variabelenaam.

De router haalt die waarden uit een routeconfiguratie.

Dus laten we openen play-routing / conf / routes en maak een mapping voor deze nieuwe actie:

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

Merk op hoe we een router informeren dat de naam een ​​dynamisch padsegment is met de dubbele punt-syntaxis en deze vervolgens als parameter doorgeven aan de begroetingsactie.

Laten we nu laden // locahost: 9000 / greet / john in de browser, en we worden bij naam begroet:

Hallo John

Het gebeurt zo dat als onze actieparameter van het stringtype is, kunnen we deze tijdens de actieoproep doorgeven zonder het parametertype op te geven, hoewel dit niet hetzelfde is voor andere typen.

Laten we ons wat pittiger maken /begroeten eindpunt met leeftijdsinformatie.

Terug naar HomeController‘Begroetingsactie, we veranderen dit in:

public Resultaat greet (String naam, int leeftijd) {return ok ("Hallo" + naam + ", je bent" + leeftijd + "jaar oud"); }

En de route naar:

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

Let ook op de Scala-syntaxis voor het declareren van een variabele, leeftijd: geheel getal. In Java zouden we de Integer leeftijd syntaxis. Het Play Framework is gebouwd in Scala. Daarom is er veel scala-syntaxis.

Laten we laden // localhost: 9000 / greet / john / 26:

Hallo John, je bent 26 jaar oud

6.2. Jokertekens in padparameters

In ons routes-configuratiebestand is de laatste mapping:

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

We gebruiken een jokerteken in het dynamische deel van het pad. Wat we Play vertellen, is dat elke waarde in de plaats komt *het dossier in het daadwerkelijke verzoek moet als geheel worden geparseerd en niet worden gedecodeerd zoals in andere gevallen van padparameters.

In dit voorbeeld is de controller een ingebouwde controller, Middelen, waarmee de client bestanden kan downloaden van het play-routing / openbaar map. Als we laden //localhost:9000/assets/images/favicon.png, zouden we de afbeelding van de Play-favicon in de browser moeten zien, aangezien deze aanwezig is in het / public / images map.

Laten we onze eigen voorbeeldactie maken in HomeController.java:

openbaar resultaat introduMe (String data) {String [] clientData = data.split (","); return ok ("Je naam is" + clientData [0] + ", je bent" + clientData [1] + "jaar oud"); }

Merk op dat we bij deze actie één String-parameter ontvangen en onze logica toepassen om deze te decoderen. In dit geval is de logica om een ​​kommagescheiden te splitsen Draad in een array. Voorheen waren we afhankelijk van een router om deze gegevens voor ons te decoderen.

Met wildcards staan ​​we er alleen voor. We hopen dat de client onze syntaxis correct krijgt tijdens het doorgeven van deze gegevens. Idealiter we moeten de inkomende string valideren voordat we deze gebruiken.

Laten we een route naar deze actie maken:

GET / * gegevenscontrollers.HomeController.introduceMe (gegevens)

Laad nu de URL // localhost: 9000 / john, 26. Dit zal afdrukken:

Je naam is John, je bent 26 jaar oud

6.3. Regex in padparameters

Net als jokertekens kunnen we reguliere expressies gebruiken voor het dynamische gedeelte. Laten we een actie toevoegen die een getal ontvangt en zijn kwadraat retourneert:

openbaar resultaat squareMe (Long num) {return ok (num + "Squared is" + (num * num)); }

Nu zullen we de route toevoegen:

GET / square / $ num controllers.HomeController.squareMe (num: lang)

Laten we deze route onder het stel me voor route om een ​​nieuw concept te introduceren. We kunnen alleen routes afhandelen waarbij het regex-gedeelte een positief geheel getal is met deze routeringsconfiguratie.

Als we nu de route hebben geplaatst zoals aangegeven in de vorige paragraaf, en we laden // localhost: 9000 / square / 2, zouden we begroet moeten worden met een ArrayIndexOutOfBoundsException:

Als we de foutenlogboeken in de serverconsole controleren, zullen we ons realiseren dat de actieoproep daadwerkelijk is uitgevoerd op stel me voor actie in plaats van squareMe actie. Zoals eerder gezegd over jokertekens, staan ​​we er alleen voor en hebben we inkomende gegevens niet gevalideerd.

In plaats van een door komma's gescheiden tekenreeks, de stel me voor methode werd aangeroepen met de string “vierkant / 2“. Daarom kregen we na het splitsen een reeks van maat één. Probeert de index te bereiken 1 gooide toen de uitzondering.

We verwachten natuurlijk dat de oproep wordt doorgestuurd naar het squareMe methode. Waarom is het omgeleid naar stel me voor? De reden is een Play-functie die we hierna behandelen Routeprioriteit.

7. Routeprioriteit

Als er een conflict is tussen routes zoals er tussen is squareMe en stel me voor, dan Het spel kiest de eerste route in de aangiftevolgorde.

Waarom is er een conflict? Vanwege het contextpad van het jokerteken /*gegevens komt overeen met elke verzoek-URL behalve het basispad /. Zo elke route waarvan het URI-patroon gebruikmaakt van jokertekens, moet als laatste worden weergegeven.

Laten we nu de aangiftevolgorde van de routes wijzigen zodat de stel me voor route komt erna squareMe en herlaad:

2 Kwadraat is 4

Probeer te laden om de kracht van reguliere expressies in een route te testen // locahost: 9000 / vierkant / -1, zal een router niet overeenkomen met de squareMe route. In plaats daarvan komt het overeen stel me voor, en we krijgen de ArrayIndexOutOfBoundsException opnieuw.

Dit is zo omdat -1 komt niet overeen met de opgegeven reguliere expressie, evenmin als een alfabetisch teken.

8. Parameters

Tot nu toe hebben we de syntaxis behandeld voor het declareren van parametertypes in het routes-bestand.

In deze sectie zullen we meer opties bekijken die voor ons beschikbaar zijn bij het omgaan met parameters in routes.

8.1. Parameters met vaste waarden

Soms willen we een vaste waarde voor een parameter gebruiken. Dit is onze manier om Play te vertellen dat het de opgegeven padparameter moet gebruiken of dat de verzoekcontext het pad is /, gebruik dan een bepaalde vaste waarde.

Een andere manier om ernaar te kijken is het hebben van twee eindpunten of contextpaden die naar dezelfde controlleractie leiden - waarbij het ene eindpunt een parameter van de verzoek-URL vereist en standaard naar het andere als de genoemde parameter afwezig is.

Om dit te demonstreren, voegen we een auteur() actie naar de HomeController:

public Result writer () {return ok ("Routing in Play door Baeldung"); }

Ervan uitgaande dat we niet altijd willen dat onze API een Draad:

Routing in Play door Baeldung

We willen het controleren door de naam van een auteur van het artikel samen met het verzoek te sturen, standaard ingesteld op de vaste waarde Baeldung alleen als het verzoek niet de schrijver parameter.

Dus laten we de auteur actie door een parameter toe te voegen:

public Resultaat schrijver (String auteur) {return ok ("REST API met spelen door" + auteur); }

Laten we ook kijken hoe we een parameter met een vaste waarde aan de route kunnen toevoegen:

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

Merk op hoe we nu twee aparte routes hebben die allemaal naar de HomeController.index actie in plaats van één.

Als we nu laden // localhost: 9000 / writer van de browser krijgen we:

Routing in Play door Baeldung

En als we laden // localhost: 9000 / writer / john, we krijgen:

Routing in Play door John

8.2. Parameters met standaardwaarden

Naast vaste waarden kunnen parameters ook standaardwaarden hebben. Beide bieden fallback-waarden voor de actieparameters van de controller voor het geval het verzoek niet de vereiste waarden bevat.

Het verschil tussen de twee is dat vaste waarden worden gebruikt als een fallback voor padparameters, terwijl standaardwaarden worden gebruikt als een fallback voor queryparameters.

Padparameters hebben de vorm // localhost: 9000 / param1 / param2 en queryparameters hebben de vorm // localhost: 9000 /? param1 = waarde1¶m2 = waarde2.

Het tweede verschil zit in de syntaxis van het declareren van de twee in een route. Parameters voor vaste waarden gebruiken de toewijzingsoperator zoals in:

author = "Baeldung"

Hoewel standaardwaarden een ander type toewijzing gebruiken:

author? = "Baeldung"

Wij gebruiken de ?= operator die voorwaardelijk toewijst Baeldung naar schrijver in geval van schrijver blijkt geen waarde te bevatten.

Laten we voor een volledige demonstratie het HomeController.writer actie. Laten we zeggen dat we naast de naam van de auteur, die een padparameter is, ook de auteur willen doorgeven ID kaart als een queryparameter die standaard zou moeten zijn 1 indien niet doorgegeven in het verzoek.

We zullen veranderen auteur actie om:

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

en de auteur routes naar:

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

Nu aan het laden // localhost: 9000 / writer wij zien:

Routing in spel door: Baeldung ID: 1

Slaan // localhost: 9000 / writer? id = 10 geeft ons:

Routing in Play door: Baeldung ID: 10

Hoe zit het met // localhost: 9000 / writer / john?

Routing in Play door: john ID: 1

En tenslotte, // localhost: 9000 / writer / john? id = 5 geeft terug:

Routing in Play door: john ID: 5

9. Conclusie

In dit artikel hebben we het concept van routering in Play-applicaties onderzocht. We hebben ook een artikel over het bouwen van een RESTful API met Play Framework waarin de routeringsconcepten in deze tutorial worden toegepast in een praktisch voorbeeld.

Zoals gewoonlijk is de broncode voor deze tutorial beschikbaar op GitHub.