En guide til JavaLite - Opbygning af en RESTful CRUD-applikation

1. Introduktion

JavaLite er en samling af rammer til forenkling af almindelige opgaver som enhver udvikler skal håndtere, når han bygger applikationer.

I denne vejledning skal vi se på JavaLite-funktioner, der er fokuseret på at opbygge en simpel API.

2. Opsætning

I hele denne tutorial opretter vi en simpel RESTful CRUD-applikation. For at gøre det, vi bruger ActiveWeb og ActiveJDBC - to af de rammer, som JavaLite integrerer med.

Så lad os komme i gang og tilføje den første afhængighed, som vi har brug for:

 org.javalite activeweb 1.15 

ActiveWeb-artefakt inkluderer ActiveJDBC, så det er ikke nødvendigt at tilføje det separat. Bemærk, at den nyeste activeweb-version kan findes i Maven Central.

Den anden afhængighed, vi har brug for, er et databasestik. I dette eksempel skal vi bruge MySQL, så vi skal tilføje:

 mysql mysql-connector-java 5.1.45 

Igen kan den nyeste mysql-connector-java-afhængighed findes på Maven Central.

Den sidste afhængighed, vi skal tilføje, er noget specifikt for JavaLite:

 org.javalite activejdbc-instrumentering 1.4.13 procesklasser instrument 

Det seneste plugin til aktivjdbc-instrumentering kan også findes i Maven Central.

Når vi har alt dette på plads, og inden vi starter med enheder, tabeller og tilknytninger, sørger vi for det en af ​​de understøttede databaser er i gang. Som vi sagde før, bruger vi MySQL.

Nu er vi klar til at starte med objektrelationskortlægning.

3. Objektrelationel kortlægning

3.1. Kortlægning og instrumentering

Lad os komme i gang med oprettelse af en Produkt klasse, der vil være vores vigtigste enhed:

produkt i offentlig klasse {}

Og lad os også Opret den tilsvarende tabel til den:

OPRET TABELPRODUKTER (id int (11) STANDARD NULL auto_inkrement PRIMÆR NØGLE, navn VARCHAR (128));

Endelig kan vi ændre vores Produkt klasse for at udføre kortlægningen:

offentlig klasse Produkt udvider model {}

Vi behøver kun at udvide org.javalite.activejdbc.Model klasse. ActiveJDBC udleder DB-skemaparametre fra databasen. Takket være denne evne, der er ikke behov for at tilføje getters og settere eller nogen kommentar.

Desuden genkender ActiveJDBC det automatisk Produkt klasse skal kortlægges til PRODUKTER bord. Det gør brug af engelske bøjninger til at konvertere entalform af en model til en flertalsform af en tabel. Og ja, det fungerer også med undtagelser.

Der er en sidste ting, som vi bliver nødt til at få vores kortlægning til at fungere: instrumentering. Instrumentering er et ekstra trin, der kræves af ActiveJDBC det giver os mulighed for at lege med vores Produkt klasse som om det havde getters, settere og DAO-lignende metoder.

Efter at have kørt instrumentering kan vi gøre ting som:

Produkt p = nyt produkt (); p.set ("navn", "Brød"); p.saveIt ();

eller:

Liste over produkter = Product.findAll ();

Det er her aktivjdbc-instrumentering plugin kommer ind. Da vi allerede har afhængigheden i vores pom, bør vi se klasser blive instrumenteret under build:

... [INFO] --- aktivjdbc-instrumentering: 1.4.11: instrument (standard) @ javalite --- ************************ **** START INSTRUMENTATION **************************** Directory: ... \ tutorials \ java-lite \ target \ classes Instrumented klasse: ... / tutorials / java-lite / target / classes / app / models / Product.class *************************** * SLUTINSTRUMENTATION **************************** ...

Dernæst opretter vi en simpel test for at sikre, at dette fungerer.

3.2. Testning

Endelig følger vi tre enkle trin for at teste vores kortlægning: åbne en forbindelse til databasen, gemme et nyt produkt og hente det:

@Test offentlig ugyldighed givenSavedProduct_WhenFindFirst_ThenSavedProductIsReturned () {Base.open ("com.mysql.jdbc.Driver", "jdbc: mysql: // localhost / dbname", "bruger", "password"); Produkt toSaveProduct = nyt produkt (); toSaveProduct.set ("navn", "brød"); toSaveProduct.saveIt (); Produkt gemtProdukt = Produkt.findFirst ("navn =?", "Brød"); assertEquals (toSaveProduct.get ("navn"), gemtProduct.get ("navn")); }

Bemærk, at alt dette (og mere) er muligt ved kun at have en tom model og instrumentering.

4. Controllere

Nu hvor vores kortlægning er klar, kan vi begynde at tænke på vores applikation og dens CRUD-metoder.

Til det skal vi bruge controllere, der behandler HTTP-anmodninger.

Lad os skabe vores ProductsController:

@RESTful public class ProductsController udvider AppController {public void index () {// ...}}

Med denne implementering kortlægger ActiveWeb automatisk indeks() metode til følgende URI:

//:/Produkter

Controllere kommenteret med @Rolig, give et fast sæt metoder, der automatisk kortlægges til forskellige URI'er. Lad os se dem, der vil være nyttige til vores CRUD-eksempel:

Controller metodeHTTP-metodeURI
SKABskab()STOLPE// vært: port / produkter
LÆS ENat vise()// vært: port / produkter / {id}
LÆS ALLEindeks()// vært: port / produkter
OPDATERopdater ()SÆTTE// vært: port / produkter / {id}
SLETødelægge()SLET// vært: port / produkter / {id}

Og hvis vi tilføjer dette sæt metoder til vores ProductsController:

@RESTful public class ProductsController udvider AppController {public void index () {// code for at få alle produkter} public void create () {// code for at oprette et nyt produkt} public void update () {// code for at opdatere et eksisterende produkt} offentlig ugyldigt show () {// kode for at finde et produkt} offentligt tomrum ødelægge () {// kode for at fjerne et eksisterende produkt}}

Før vi går videre til vores logiske implementering, ser vi hurtigt på nogle få ting, som vi har brug for at konfigurere.

5. Konfiguration

ActiveWeb er hovedsageligt baseret på konventioner, projektstruktur er et eksempel på det. ActiveWeb-projekter skal følge et foruddefineret pakkelayout:

src | ---- main | ---- java.app | | ---- config | | ---- controllere | | ---- modeller | ---- ressourcer | ---- webapp | ---- WEB-INF | ---- visninger

Der er en bestemt pakke, som vi skal se på - app.konfig.

Inde i den pakke opretter vi tre klasser:

offentlig klasse DbConfig udvider AbstractDBConfig {@Override public void init (AppContext appContext) {this.configFile ("/ database.properties"); }}

Denne klasse konfigurerer databaseforbindelser ved hjælp af en egenskabsfil i projektets rodmappe, der indeholder de krævede parametre:

development.driver = com.mysql.jdbc.Driver development.username = brugerudvikling.password = password udvikling.url = jdbc: mysql: // localhost / dbname

Dette opretter forbindelsen, der automatisk erstatter det, vi gjorde i første linje i vores kortlægningstest.

Den anden klasse, som vi skal inkludere indeni app.config pakken er:

offentlig klasse AppControllerConfig udvider AbstractControllerConfig {@Override public void init (AppContext appContext) {add (new DBConnectionFilter ()). to (ProductsController.class); }}

Denne kodevil binde den forbindelse, som vi lige har konfigureret til vores controller.

Den tredje klasse viljekonfigurer vores apps kontekst:

offentlig klasse AppBootstrap udvider Bootstrap {public void init (AppContext context) {}}

Efter oprettelse af de tre klasser er den sidste ting vedrørende konfiguration skaber vores web.xml fil under webapp / WEB-INF vejviser:

   dispatcher org.javalite.activeweb.RequestDispatcher ekskluderinger css, billeder, js, ico kodning UTF-8 dispatcher / * 

Nu hvor konfigurationen er færdig, kan vi gå videre og tilføje vores logik.

6. Implementering af CRUD-logik

Med de DAO-lignende muligheder leveret af vores Produkt klasse, det er super simpelt at tilføj grundlæggende CRUD-funktionalitet:

@RESTful offentlig klasse ProductsController udvider AppController {private ObjectMapper mapper = ny ObjectMapper (); offentligt ugyldigt indeks () {Liste over produkter = Product.findAll (); // ...} public void create () {Map payload = mapper.readValue (getRequestString (), Map.class); Produkt p = nyt produkt (); p.fromMap (nyttelast); p.saveIt (); // ...} offentlig ugyldig opdatering () {Map payload = mapper.readValue (getRequestString (), Map.class); Streng-id = getId (); Produkt p = Product.findById (id); p.fromMap (nyttelast); p.saveIt (); // ...} offentligt ugyldigt show () {String id = getId (); Produkt p = Product.findById (id); // ...} offentlig tomrum ødelægge () {String id = getId (); Produkt p = Product.findById (id); p.delete (); // ...}}

Let, ikke? Dette returnerer dog ikke noget endnu. For at gøre det er vi nødt til at skabe nogle visninger.

7. Visninger

ActiveWeb bruger FreeMarker som en skabelonmotor, og alle dens skabeloner skal være placeret under src / main / webapp / WEB-INF / visninger.

Inde i denne mappe placerer vi vores synspunkter i en mappe, der hedder Produkter (samme som vores controller). Lad os oprette vores første skabelon kaldet _produkt.ftl:

{"id": $ {product.id}, "name": "$ {product.name}"}

Det er ret klart på dette tidspunkt, at dette er et JSON-svar. Selvfølgelig fungerer dette kun for et produkt, så lad os gå videre og oprette en anden skabelon kaldet index.ftl:

[]

Dette vil dybest set gengive en samling navngivet Produkter, med hver formateret af _produkt.ftl.

Langt om længe, vi er nødt til at binde resultatet fra vores controller til den tilsvarende visning:

@RESTful offentlig klasse ProductsController udvider AppController {public void index () {List products = Product.findAll (); visning ("produkter", produkter); gengive (); } offentligt ugyldigt show () {String id = getId (); Produkt p = Product.findById (id); visning ("produkt", p); gengive ("_ produkt"); }}

I det første tilfælde tildeler vi Produkter liste til vores skabelonsamling, der også hedder Produkter.

Da vi ikke angiver nogen visning, index.ftl vil blive brugt.

I den anden metode tildeler vi produkt s til element produkt i udsigten, og vi siger udtrykkeligt, hvilken visning der skal gengives.

Vi kunne også oprette en visning message.ftl:

{"message": "$ {message}", "code": $ {code}}

Og så kald det fra enhver af vores ProductsController'S metode:

visning ("meddelelse", "Der opstod en fejl.", "kode", 200); gengive ("besked");

Lad os nu se vores finale ProductsController:

@RESTful offentlig klasse ProductsController udvider AppController {private ObjectMapper mapper = ny ObjectMapper (); public void index () {view ("products", Product.findAll ()); gengive (). contentType ("applikation / json"); } public void create () {Map payload = mapper.readValue (getRequestString (), Map.class); Produkt p = nyt produkt (); p.fromMap (nyttelast); p.saveIt (); visning ("besked", "Succes gemt produkt-id" + s.get ("id"), "kode", 200); gengive ("besked"); } offentlig ugyldig opdatering () {Map payload = mapper.readValue (getRequestString (), Map.class); Streng-id = getId (); Produkt p = Product.findById (id); hvis (p == null) {view ("meddelelse", "Produkt-id" + id + "ikke fundet.", "kode", 200); gengive ("besked"); Vend tilbage; } p.fromMap (nyttelast); p.saveIt (); visning ("besked", "Opdateret produkt-id" + id, "kode", 200); gengive ("besked"); } offentligt ugyldigt show () {String id = getId (); Produkt p = Product.findById (id); hvis (p == null) {view ("meddelelse", "Produkt-id" + id + "ikke fundet.", "kode", 200); gengive ("besked"); Vend tilbage; } visning ("produkt", p); gengive ("_ produkt"); } offentlig tomrum ødelægge () {String id = getId (); Produkt p = Product.findById (id); hvis (p == null) {view ("meddelelse", "Produkt-id" + id + "ikke fundet.", "kode", 200); gengive ("besked"); Vend tilbage; } p.delete (); visning ("besked", "Produkt-id slettet" + id, "kode", 200); gengive ("besked"); } @ Override beskyttet String getContentType () {returner "applikation / json"; } @ Override beskyttet String getLayout () {return null; }}

På dette tidspunkt er vores ansøgning færdig, og vi er klar til at køre den.

8. Kørsel af applikationen

Vi bruger Jetty-plugin:

 org.eclipse.jetty jetty-maven-plugin 9.4.8.v20171121 

Find det nyeste jetty-maven-plugin i Maven Central.

Og vi er klar, vi kan køre vores ansøgning:

mvn anløbsbro: kør

Lad os oprette et par produkter:

$ curl -X POST // localhost: 8080 / products -H 'content-type: application / json' -d '{"name": "Water"}' {"meddelelse": "Produkt-id 1 er gemt", " kode ": 200}
$ curl -X POST // localhost: 8080 / products -H 'content-type: application / json' -d '{"name": "Bread"}' {"message": "Produkt-id 2 er gemt", " kode ": 200}

.. læs dem:

$ curl -X GET // localhost: 8080 / products [{"id": 1, "name": "Water"}, {"id": 2, "name": "Bread"}]

.. opdater en af ​​dem:

$ curl -X PUT // localhost: 8080 / products / 1 -H 'content-type: application / json' -d '{"name": "Juice"}' {"message": "Opdateret produkt-id 1" , "kode": 200}

... læs den, vi lige har opdateret:

$ curl -X GET // localhost: 8080 / products / 1 {"id": 1, "name": "Juice"}

Endelig kan vi slette en:

$ curl -X SLET // // host: 8080 / products / 2 {"meddelelse": "Produkt-id 2 er slettet," "kode": 200}

9. Konklusion

JavaLite har mange værktøjer til at hjælpe udviklere få en applikation i gang på få minutter. Mens basering af ting på konventioner resulterer i en renere og enklere kode, tager det dog et stykke tid at forstå navngivning og placering af klasser, pakker og filer.

Dette var kun en introduktion til ActiveWeb og ActiveJDBC, find mere dokumentation på deres hjemmeside og se efter vores produktapplikation i Github-projektet.


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