REST API med Play Framework i Java

1. Oversikt

Hensikten med denne opplæringen er å utforske Play Framework og lære å bygge REST-tjenester med den ved hjelp av Java.

Vi setter sammen et REST API for å opprette, hente, oppdatere og slette studentposter.

I slike applikasjoner vil vi normalt ha en database for å lagre studentposter. Play Framework har en innebygd H2-database, sammen med støtte for JPA med Hibernate og andre utholdenhetsrammer.

For å holde ting enkelt og fokusere på de viktigste tingene, vil vi imidlertid bruke et enkelt kart for å lagre studentobjekter med unike ID-er.

2. Opprett et nytt program

Når vi har installert Play Framework som beskrevet i vår introduksjon til Play Framework, er vi klare til å lage vår applikasjon.

La oss bruke sbt kommando for å opprette et nytt program kalt student-api ved hjelp av play-java-seed:

sbt ny playframework / play-java-seed.g8

3. Modeller

Med applikasjonsstillaset vårt på plass, la oss navigere til student-api / app / modeller og lage en Java-bønne for håndtering av studentinformasjon:

offentlig klasse Student {privat streng fornavn; privat streng etternavn; privat alder; privat int id; // standardkonstruktører, getters og settere}

Vi oppretter nå en enkel datalager - støttet av en HashMap - for studentdata, med hjelpemetoder for å utføre CRUD-operasjoner:

offentlig klasse StudentStore {private Map students = new HashMap (); offentlig valgfritt addStudent (studentstudent) {int id = students.size (); student.setId (id); students.put (id, student); retur Valgfritt. av Nullable (student); } offentlig Valgfri getStudent (int id) {retur Optional.ofNullable (students.get (id)); } public Set getAllStudents () {return new HashSet (students.values ​​()); } offentlig Valgfri oppdateringStudent (studentstudent) {int id = student.getId (); hvis (students.containsKey (id)) {students.put (id, student); retur Valgfritt. av Nullable (student); } returner null; } offentlig boolsk deleteStudent (int id) {return students.remove (id)! = null; }}

4. Kontrollere

La oss gå over til student-api / app / kontrollere og opprett en ny kontroller kalt StudentController.java. Vi går trinnvis gjennom koden.

Først må vi konfigurere en HttpExecutionContext. Vi implementerer våre handlinger ved hjelp av asynkron, ikke-blokkerende kode. Dette betyr at våre handlingsmetoder kommer tilbake CompletionStage i stedet for bare Resultat. Dette har fordelen av å la oss skrive langvarige oppgaver uten å blokkere.

Det er bare en advarsel når vi arbeider med asynkron programmering i en Play Framework-kontroller: vi må gi en HttpExecutionContext. Hvis vi ikke leverer HTTP-kjøringskontekst, får vi den beryktede feilen "Det er ingen HTTP-kontekst tilgjengelig herfra" når vi ringer til handlingsmetoden.

La oss injisere det:

private HttpExecutionContext ec; privat StudentStore studentStore; @Inject public StudentController (HttpExecutionContext ec, StudentStore studentStore) {this.studentStore = studentStore; this.ec = ec; }

Legg merke til at vi også har lagt til StudentStore og injiserte begge feltene i konstruktøren til kontrolleren ved hjelp av @Injiser kommentar. Etter å ha gjort dette, kan vi nå fortsette med implementeringen av handlingsmetodene.

Noter det Spill skip med Jackson for å tillate databehandling - slik at vi kan importere alle Jackson-klasser vi trenger uten eksterne avhengigheter.

La oss definere en nytteklasse for å utføre repeterende operasjoner. I dette tilfellet bygger du HTTP-svar.

Så la oss lage student-api / app / verktøy pakke og legg til Util.java i det:

offentlig klasse Til {offentlig statisk ObjectNode createResponse (Objektrespons, boolsk ok) {ObjectNode-resultat = Json.newObject (); result.put ("erSuccessful", ok); if (response instanceof String) {result.put ("body", (String) response); } annet {result.putPOJO ("body", respons); } returnere resultat; }}

Med denne metoden lager vi standard JSON-svar med en boolsk er vellykket nøkkel og responsorganet.

Vi kan nå gå gjennom handlingene til kontrollerklassen.

4.1. De skape Handling

Kartlagt som en POST handling, håndterer denne metoden etableringen av Student gjenstand:

public CompletionStage create (Http.Request request) {JsonNode json = request.body (). asJson (); return supplyAsync (() -> {if (json == null) {return badRequest (Util.createResponse ("Expecting Json data", false));} Valgfri studentOptional = studentStore.addStudent (Json.fromJson (json, Student.class) )); returner studentOptional.map (student -> {JsonNode jsonObject = Json.toJson (student); retur opprettet (Util.createResponse (jsonObject, true));}). orElse (internalServerError (Util.createResponse ("Kunne ikke opprette data. ", false)));}, ec.current ()); }

Vi bruker en samtale fra den injiserte Http. Forespørsel klasse for å få anmodningsorganet inn i Jacksons JsonNode klasse. Legg merke til hvordan vi bruker verktøymetoden for å skape et svar hvis kroppen er null.

Vi returnerer også en CompletionStage, som gjør det mulig for oss å skrive ikke-blokkerende kode ved hjelp av CompletedFuture.supplyAsync metode.

Vi kan overføre det til noe String eller a JsonNode, sammen med en boolsk flagg for å indikere status.

Legg også merke til hvordan vi bruker Json.fromJson () for å konvertere det innkommende JSON-objektet til et Student motstand og tilbake til JSON for svaret.

Endelig, i stedet for ok () som vi er vant til, bruker vi opprettet hjelpermetode fra play.mvc.resultater pakke. Tanken er å bruke en metode som gir riktig HTTP-status for handlingen som utføres innenfor en bestemt kontekst. For eksempel, ok () for HTTP OK 200-status, og opprettet () når HTTP CREATED 201 er resultatstatusen som brukt ovenfor. Dette konseptet vil komme opp i resten av handlingene.

4.2. De Oppdater Handling

EN SETTE forespørsel til // lokal vert: 9000 / treffer StudentController.Oppdater metoden, som oppdaterer studentinformasjonen ved å ringe updateStudent metoden for StudentStore:

offentlig CompletionStage-oppdatering (Http.Request-forespørsel) {JsonNode json = request.body (). asJson (); return supplyAsync (() -> {if (json == null) {return badRequest (Util.createResponse ("Expecting Json data", false))}} Valgfri studentOptional = studentStore.updateStudent (Json.fromJson (json, Student.class) )); returner studentOptional.map (student -> {if (student == null) {return notFound (Util.createResponse ("Student ikke funnet", false));} JsonNode jsonObject = Json.toJson (student); returner ok (Util.createResponse (jsonObject, true));}). OrElse (internalServerError (Util.createResponse ("Kunne ikke opprette data.", False)));}, ec.current ()); }

4.3. De hente Handling

For å hente en student, passerer vi studentens id som en baneparameter i en forespørsel til // localhost: 9000 /: id. Dette vil treffe hente handling:

public CompletionStage retrieve (int id) {return supplyAsync (() -> {final Optional studentOptional = studentStore.getStudent (id); return studentOptional.map (student -> {JsonNode jsonObjects = Json.toJson (student); return ok (Util .createResponse (jsonObjects, true));}). orElse (notFound (Util.createResponse ("Student med id:" + id + "ikke funnet", false)));}, ec.current ()); }

4.4. De slett Handling

De slett handlingen er kartlagt til // localhost: 9000 /: id. Vi leverer id for å identifisere hvilken post du vil slette:

public CompletionStage delete (int id) {return supplyAsync (() -> {boolean status = studentStore.deleteStudent (id); if (! status) {return notFound (Util.createResponse ("Student med id:" + id + "ikke) funnet ", false));} return ok (Util.createResponse (" Student med id: "+ id +" slettet ", sant));}, ec.current ()); }

4.5. De listeStudenter Handling

Til slutt, listeStudenter handling returnerer en liste over alle studentene som har blitt lagret så langt. Det er kartlagt til // lokal vert: 9000 / som en be om:

public CompletionStage listStudents () {return supplyAsync (() -> {Set result = studentStore.getAllStudents (); ObjectMapper mapper = new ObjectMapper (); JsonNode jsonData = mapper.convertValue (result, JsonNode.class); return ok (Util. createResponse (jsonData, true));}, ec.current ()); }

5. Kartlegginger

Etter å ha konfigurert kontrollerhandlingene våre, kan vi nå kartlegge dem ved å åpne filen student-api / conf / ruter og legge til disse rutene:

GET / controllers.StudentController.listStudents () GET /: id controllers.StudentController.retrieve (id: Int) POST / controllers.StudentController.create (forespørsel: Forespørsel) PUT / controllers.StudentController.update (forespørsel: Forespørsel) DELETE /: id-kontrollere.StudentController.delete (id: Int) GET / assets / * file controllers.Assets.versioned (path = "/ public", file: Asset)

De /eiendeler sluttpunktet må alltid være til stede for nedlasting av statiske ressurser.

Etter dette er vi ferdige med å bygge Student API.

For å lære mer om å definere rutekartlegginger, besøk vår veiledning om ruting i Play-applikasjoner.

6. Testing

Vi kan nå kjøre tester på API-en vår ved å sende forespørsler til // lokal vert: 9000 / og legge til riktig kontekst. Å kjøre basestien fra nettleseren skal sendes:

{"isSuccessful": true, "body": []}

Som vi kan se, er kroppen tom siden vi ikke har lagt til noen poster ennå. Ved hjelp av krølle, la oss kjøre noen tester (alternativt kan vi bruke en REST-klient som Postman).

La oss åpne et terminalvindu og utføre krøllkommandoen til legge til en student:

curl -X POST -H "Content-Type: application / json" \ -d '{"firstName": "John", "lastName": "Baeldung", "age": 18}' \ // localhost: 9000 /

Dette vil returnere den nyopprettede studenten:

{"isSuccessful": true, "body": {"firstName": "John", "lastName": "Baeldung", "age": 18, "id": 0}}

Etter å ha kjørt ovennevnte test, lasting // lokal vert: 9000 fra nettleseren skal nå gi oss:

{"isSuccessful": true, "body": [{"firstName": "John", "lastName": "Baeldung", "age": 18, "id": 0}]} 

De id attributt økes for hver nye plate vi legger til.

Til slette en post vi sender en SLETT be om:

krøll -X SLETT // localhost: 9000/0 {"isSuccessful": true, "body": "Student med id: 0 slettet"} 

I testen ovenfor sletter vi posten som ble opprettet i den første testen, la oss nå lage den igjen slik at vi kan teste Oppdater metode:

curl -X POST -H "Content-Type: application / json" \ -d '{"firstName": "John", "lastName": "Baeldung", "age": 18}' \ // localhost: 9000 / {"isSuccessful": true, "body": {"firstName": "John", "lastName": "Baeldung", "age": 18, "id": 0}}

La oss nå oppdater posten ved å sette fornavnet til “Andrew” og alderen til 30:

curl -X PUT -H "Content-Type: application / json" \ -d '{"firstName": "Andrew", "lastName": "Baeldung", "age": 30, "id": 0}' \ // localhost: 9000 / {"isSuccessful": true, "body": {"firstName": "Andrew", "lastName": "Baeldung", "age": 30, "id": 0}}

Ovennevnte test demonstrerer endringen i verdien på fornavn og alder felt etter oppdatering av posten.

La oss lage noen ekstra dummy-poster, vi legger til to: John Doe og Sam Baeldung:

curl -X POST -H "Content-Type: application / json" \ -d '{"firstName": "John", "lastName": "Doe", "age": 18}' \ // localhost: 9000 /
curl -X POST -H "Content-Type: application / json" \ -d '{"firstName": "Sam", "lastName": "Baeldung", "age": 25}' \ // localhost: 9000 /

La oss få alle postene:

curl -X GET // localhost: 9000 / {"isSuccessful": true, "body": [{"firstName": "Andrew", "lastName": "Baeldung", "age": 30, "id": 0 }, {"firstName": "John", "lastName": "Doe", "age": 18, "id": 1}, {"firstName": "Sam", "lastName": "Baeldung", " alder ": 25," id ": 2}]}

Med testen ovenfor undersøker vi at funksjonen fungerer listeStudenter kontrollerhandling.

7. Konklusjon

I denne artikkelen har vi vist hvordan du bygger et fullverdig REST API ved hjelp av Play Framework.

Som vanlig er kildekoden for denne opplæringen tilgjengelig på GitHub.


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