REST API med Play Framework i Java

1. Oversigt

Formålet med denne vejledning er at udforske Play Framework og lære at opbygge REST-tjenester med det ved hjælp af Java.

Vi sammensætter en REST API til at oprette, hente, opdatere og slette elevoptegnelser.

I sådanne applikationer ville vi normalt have en database til lagring af studereposter. Play Framework har en indbygget H2-database sammen med understøttelse af JPA med dvale og andre persistensrammer.

For at holde tingene enkle og fokusere på de vigtigste ting bruger vi dog et simpelt kort til at gemme studenterobjekter med unikke id'er.

2. Opret en ny applikation

Når vi har installeret Play Framework som beskrevet i vores introduktion til Play Framework, er vi klar til at oprette vores applikation.

Lad os bruge sbt kommando til at oprette et nyt program kaldet student-api ved brug af play-java-seed:

sbt nyt playframework / play-java-seed.g8

3. Modeller

Med vores applikationsstillads på plads, lad os navigere til student-api / app / modeller og oprette en Java-bønne til håndtering af studenteroplysninger:

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

Vi opretter nu en simpel datalager - bakket op af en HashMap - til studenterdata med hjælpemetoder til at udføre CRUD-operationer:

offentlig klasse StudentStore {private Map studerende = ny HashMap (); offentlig valgfri addStudent (studerende) {int id = students.size (); student.setId (id); students.put (id, student); tilbagevenden Optional.ofNullable (studerende); } offentlig Valgfri getStudent (int id) {return Optional.ofNullable (students.get (id)); } public Set getAllStudents () {returner nyt HashSet (students.values ​​()); } offentlig Valgfri opdateringStudent (studerende) {int id = student.getId (); hvis (students.containsKey (id)) {students.put (id, student); tilbagevenden Optional.ofNullable (studerende); } returnere null; } offentlig boolsk deleteStudent (int id) {return students.remove (id)! = null; }}

4. Controllere

Lad os gå over til student-api / app / controllere og opret en ny controller kaldet StudentController.java. Vi går trinvist igennem koden.

Først skal vi konfigurere en HttpExecutionContext. Vi implementerer vores handlinger ved hjælp af asynkron, ikke-blokerende kode. Dette betyder, at vores handlingsmetoder vender tilbage FuldførelseStage i stedet for bare Resultat. Dette har fordelen ved at lade os skrive langvarige opgaver uden at blokere.

Der er kun en advarsel, når vi beskæftiger os med asynkron programmering i en Play Framework-controller: vi skal give en HttpExecutionContext. Hvis vi ikke leverer HTTP-eksekveringskonteksten, får vi den berygtede fejl "Der er ingen HTTP-kontekst tilgængelig herfra", når vi kalder handlingsmetoden.

Lad os injicere det:

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

Bemærk, at vi også har tilføjet StudentStore og injicerede begge felter i controllerens konstruktør ved hjælp af @Indsprøjte kommentar. Når vi har gjort dette, kan vi nu fortsætte med implementeringen af ​​handlingsmetoderne.

Noter det Spil med Jackson for at give mulighed for databehandling - så vi kan importere alle Jackson-klasser, vi har brug for uden eksterne afhængigheder.

Lad os definere en hjælpeklasse til at udføre gentagne operationer. I dette tilfælde bygger HTTP-svar.

Så lad os skabe student-api / app / værktøjer pakke og tilføj Util.java i det:

offentlig klasse Til {public static ObjectNode createResponse (Object response, boolean ok) {ObjectNode result = Json.newObject (); result.put ("erSuccessful", ok); if (response instanceof String) {result.put ("body", (String) response); } andet {result.putPOJO ("body", svar); } returnere resultat }}

Med denne metode opretter vi standard JSON-svar med en boolsk er vellykket nøglen og responsorganet.

Vi kan nu gå igennem handlingerne i controller-klassen.

4.1. Det skab Handling

Kortlagt som en STOLPE handling, denne metode håndterer oprettelsen af Studerende objekt:

public CompletionStage create (Http.Request anmodning) {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 oprettet (Util.createResponse (jsonObject, sand));}). ellerElse (internalServerError (Util.createResponse ("Kunne ikke oprette data. ", false)));}, ec.current ()); }

Vi bruger et opkald fra den injicerede Http. Anmodning klasse for at få anmodningsorganet ind i Jacksons JsonNode klasse. Læg mærke til, hvordan vi bruger hjælpemetoden til at skabe et svar, hvis kroppen er nul.

Vi vender også tilbage en FuldførelseStage, som gør det muligt for os at skrive ikke-blokerende kode ved hjælp af CompletedFuture.supplyAsync metode.

Vi kan videregive det til enhver Snor eller a JsonNodesammen med en boolsk flag for at angive status.

Bemærk også, hvordan vi bruger Json.fromJson () at konvertere det indgående JSON-objekt til en Studerende mod og tilbage til JSON for svaret.

Endelig i stedet for Okay() som vi er vant til, bruger vi oprettet hjælper metode fra play.mvc.resultater pakke. Ideen er at bruge en metode, der giver den korrekte HTTP-status for den handling, der udføres inden for en bestemt sammenhæng. For eksempel, Okay() for HTTP OK 200-status, og oprettet () når HTTP CREATED 201 er resultatstatus som brugt ovenfor. Dette koncept kommer op i resten af ​​handlingerne.

4.2. Det opdatering Handling

EN SÆTTE anmodning til // lokal vært: 9000 / rammer StudentController.opdatering metode, der opdaterer studerendes information ved at ringe til updateStudent metode til StudentStore:

offentlig opdatering af CompletionStage (Http.Request anmodning) {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 fundet", false));} JsonNode jsonObject = Json.toJson (student); returner ok (Util.createResponse (jsonObject, true));}). OrElse (internalServerError (Util.createResponse ("Kunne ikke oprette data.", False)));}, ec.current ()); }

4.3. Det hente Handling

For at hente en studerende videregiver vi studentens id som en sti-parameter i en anmodning til // localhost: 9000 /: id. Dette vil ramme hente handling:

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

4.4. Det slet Handling

Det slet handling kortlægges til // localhost: 9000 /: id. Vi leverer id for at identificere, hvilken post der skal slettes:

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

4.5. Det listeStudenter Handling

Endelig blev listeStudenter handling returnerer en liste over alle de studerende, der hidtil er gemt. Det er kortlagt til // lokal vært: 9000 / som en anmodning:

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. Kortlægninger

Efter at have oprettet vores controllerhandlinger kan vi nu kortlægge dem ved at åbne filen student-api / conf / ruter og tilføje disse ruter:

GET / controllers.StudentController.listStudents () GET /: id controllers.StudentController.retrieve (id: Int) POST / controllers.StudentController.create (anmodning: Request) PUT / controllers.StudentController.update (anmodning: Request) DELETE /: id-controllere.StudentController.delete (id: Int) GET / assets / * file controllers.Assets.versioned (path = "/ public", file: Asset)

Det / aktiver slutpunkt skal altid være til stede for at downloade statiske ressourcer.

Efter dette er vi færdige med at opbygge Studerende API.

Hvis du vil lære mere om definition af rutekortlægninger, kan du besøge vores vejledning i Routing i Play Applications.

6. Testning

Vi kan nu køre tests på vores API ved at sende anmodninger til // lokal vært: 9000 / og tilføje den relevante kontekst. At køre basisstien fra browseren skal output:

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

Som vi kan se, er kroppen tom, da vi endnu ikke har tilføjet nogen poster. Ved brug af krølle, lad os køre nogle tests (alternativt kan vi bruge en REST-klient som Postman).

Lad os åbne et terminalvindue og udføre curl-kommandoen til tilføj en studerende:

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

Dette returnerer den nyoprettede studerende:

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

Efter indlæsning af ovenstående test // localhost: 9000 fra browseren skal nu give os:

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

Det id attribut forøges for hver nye post, vi tilføjer.

Til slette en post vi sender en SLET anmodning:

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

I ovenstående test sletter vi den post, der blev oprettet i den første test, lad os nu Opret det igen, så vi kan teste opdatering 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}}

Lad os nu opdater posten ved at indstille fornavnet til "Andrew" og alder 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}}

Ovenstående test viser ændringen i værdien af fornavn og alder felter efter opdatering af posten.

Lad os oprette nogle ekstra dummy-poster, vi tilføjer 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 /

Lad os nu få alle optegnelserne:

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 ovenstående test undersøger vi, at den fungerer korrekt listeStudenter controller handling.

7. Konklusion

I denne artikel har vi vist, hvordan man bygger en fuldgyldig REST API ved hjælp af Play Framework.

Som normalt er kildekoden til denne vejledning tilgængelig på GitHub.


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