En guide til JavaLite - Bygg en RESTful CRUD-applikasjon
1. Introduksjon
JavaLite er en samling rammer for å forenkle vanlige oppgaver som hver utvikler må forholde seg til når han bygger applikasjoner.
I denne opplæringen skal vi ta en titt på JavaLite-funksjoner som er fokusert på å bygge en enkel API.
2. Oppsett
Gjennom denne opplæringen oppretter vi en enkel RESTful CRUD-applikasjon. For å gjøre det, vi bruker ActiveWeb og ActiveJDBC - to av rammene som JavaLite integrerer med.
Så la oss komme i gang og legge til den første avhengigheten vi trenger:
org.javalite activeweb 1.15
ActiveWeb-gjenstand inkluderer ActiveJDBC, så det er ikke nødvendig å legge den til separat. Vær oppmerksom på at den nyeste activeweb-versjonen finnes i Maven Central.
Den andre avhengigheten vi trenger er en databasekontakt. For dette eksemplet skal vi bruke MySQL, så vi må legge til:
mysql mysql-connector-java 5.1.45
Igjen, siste mysql-connector-java avhengighet kan bli funnet på Maven Central.
Den siste avhengigheten vi må legge til er noe spesifikt for JavaLite:
org.javalite activejdbc-instrumentering 1.4.13 prosessklasser instrument
Den siste plugin-en for aktivjdbc-instrumentering finnes også i Maven Central.
Når vi har alt dette på plass, og før du begynner med enheter, tabeller og kartlegginger, sørger vi for at det en av de støttede databasene er i gang. Som vi sa tidligere, bruker vi MySQL.
Nå er vi klare til å starte med objektrelasjonell kartlegging.
3. Objektrelasjonell kartlegging
3.1. Kartlegging og instrumentering
La oss komme i gang med skape en Produkt klasse som vil være vår hovedenhet:
produkt i offentlig klasse {}
Og la oss også lag den tilsvarende tabellen for den:
OPPRETT TABELLPRODUKTER (id int (11) STANDARD NULL auto_increment PRIMÆR NØKKEL, navn VARCHAR (128));
Endelig kan vi endre vår Produkt klasse for å gjøre kartleggingen:
offentlig klasse Produkt utvider modell {}
Vi trenger bare å utvide org.javalite.activejdbc.Modell klasse. ActiveJDBC utleder DB-skjemaparametere fra databasen. Takket være denne muligheten, det er ikke nødvendig å legge til getters og settere eller noen kommentar.
Videre gjenkjenner ActiveJDBC det automatisk Produkt klassen må kartlegges til PRODUKTER bord. Den bruker engelske bøyninger for å konvertere entallform av en modell til flertall av en tabell. Og ja, det fungerer også med unntak.
Det er en siste ting som vi trenger for å få kartleggingen til å fungere: instrumentering. Instrumentering er et ekstra trinn som kreves av ActiveJDBC som vil tillate oss å leke med vår Produkt klasse som om det hadde getters, settere og DAO-lignende metoder.
Etter å ha kjørt instrumentering, kan vi gjøre ting som:
Produkt p = nytt produkt (); p.set ("navn", "Brød"); p.saveIt ();
eller:
Liste produkter = Product.findAll ();
Dette er hvor aktivjdbc-instrumentering plugin kommer inn. Ettersom vi allerede har avhengighet i vår pom, bør vi se at klasser blir instrumentert under byggingen:
... [INFO] --- activejdbc-instrumentering: 1.4.11: instrument (standard) @ javalite --- *********************** **** STARTINSTRUMENTASJON **************************** Katalog: ... \ tutorials \ java-lite \ target \ classes Instrumented klasse: ... / tutorials / java-lite / target / classes / app / models / Product.class *************************** * SLUTTINSTRUMENTASJON **************************** ...
Deretter lager vi en enkel test for å sikre at dette fungerer.
3.2. Testing
Til slutt, for å teste kartleggingen vår, følger vi tre enkle trinn: Åpne en forbindelse til databasen, lagre et nytt produkt og hente det:
@Test offentlig ugyldig givenSavedProduct_WhenFindFirst_ThenSavedProductIsReturned () {Base.open ("com.mysql.jdbc.Driver", "jdbc: mysql: // localhost / dbname", "bruker", "passord"); Produkt toSaveProduct = nytt produkt (); toSaveProduct.set ("navn", "brød"); toSaveProduct.saveIt (); Produkt sparet Produkt = Produkt.findFirst ("navn =?", "Brød"); assertEquals (toSaveProduct.get ("name"), savedProduct.get ("name")); }
Merk at alt dette (og mer) er mulig ved bare å ha en tom modell og instrumentering.
4. Kontrollere
Nå som kartleggingen vår er klar, kan vi begynne å tenke på applikasjonen vår og dens CRUD-metoder.
For det skal vi bruke kontrollere som behandler HTTP-forespørsler.
La oss lage våre ProductsController:
@RESTful offentlig klasse ProductsController utvider AppController {public void index () {// ...}}
Med denne implementeringen vil ActiveWeb automatisk kartlegge indeks () metode til følgende URI:
//:/Produkter
Kontrollere kommentert med @Avslappende, gi et fast sett med metoder som automatisk tilordnes forskjellige URI-er. La oss se de som vil være nyttige for vårt CRUD-eksempel:
Kontrollmetode | HTTP-metoden | URI | |
---|---|---|---|
SKAPE | skape() | POST | // vert: port / produkter |
LES EN | vise fram() | FÅ | // vert: port / produkter / {id} |
LES ALLE | indeks () | FÅ | // vert: port / produkter |
OPPDATER | Oppdater() | SETTE | // vert: port / produkter / {id} |
SLETT | ødelegge() | SLETT | // vert: port / produkter / {id} |
Og hvis vi legger til dette settet med metoder til vårt ProductsController:
@RESTful offentlig klasse ProductsController utvider AppController {public void index () {// code for å få alle produkter} public void create () {// code for create a new product} public void update () {// code for update a eksisterende produkt} offentlig ugyldig visning () {// kode for å finne ett produkt} offentlig tomrom ødelegge () {// kode for å fjerne et eksisterende produkt}}
Før vi går videre til logikkimplementeringen, ser vi raskt på noen få ting som vi trenger å konfigurere.
5. Konfigurasjon
ActiveWeb er hovedsakelig basert på konvensjoner, prosjektstruktur er et eksempel på det. ActiveWeb-prosjekter må følge en forhåndsdefinert pakkeoppsett:
src | ---- main | ---- java.app | | ---- config | | ---- kontrollere | | ---- modeller | ---- ressurser | ---- webapp | ---- WEB-INF | ---- visninger
Det er en spesifikk pakke som vi må ta en titt på - app.konfig.
Inne i den pakken skal vi lage tre klasser:
offentlig klasse DbConfig utvider AbstractDBConfig {@Override public void init (AppContext appContext) {this.configFile ("/ database.properties"); }}
Denne klassen konfigurerer databaseforbindelser ved hjelp av en egenskapsfil i prosjektets rotkatalog som inneholder de nødvendige parametrene:
development.driver = com.mysql.jdbc.Driver development.username = brukerutvikling.passord = passordutvikling.url = jdbc: mysql: // localhost / dbname
Dette vil opprette forbindelsen som automatisk erstatter det vi gjorde i første linje i kartleggingsprøven.
Den andre klassen som vi må inkludere inne app.config pakken er:
offentlig klasse AppControllerConfig utvider AbstractControllerConfig {@Override public void init (AppContext appContext) {add (new DBConnectionFilter ()). to (ProductsController.class); }}
Denne kodenvil binde forbindelsen som vi nettopp konfigurerte til kontrolleren vår.
Tredje klasse vilkonfigurer appens kontekst:
offentlig klasse AppBootstrap utvider Bootstrap {public void init (AppContext context) {}}
Etter å ha opprettet de tre klassene, er det siste angående konfigurasjon skape vår web.xml fil under webapp / WEB-INF katalog:
dispatcher org.javalite.activeweb.RequestDispatcher eksklusjoner css, bilder, js, ico koding UTF-8 dispatcher / *
Nå som konfigurasjonen er ferdig, kan vi fortsette og legge til logikken vår.
6. Implementering av CRUD Logic
Med de DAO-lignende funksjonene som tilbys av vår Produkt klasse, det er superenkelt å legge til grunnleggende CRUD-funksjonalitet:
@RESTful offentlig klasse ProductsController utvider AppController {private ObjectMapper mapper = ny ObjectMapper (); public void index () {List products = Product.findAll (); // ...} public void create () {Map payload = mapper.readValue (getRequestString (), Map.class); Produkt p = nytt produkt (); p.fromMap (nyttelast); p.saveIt (); // ...} offentlig ugyldig oppdatering () {Map payload = mapper.readValue (getRequestString (), Map.class); Streng-id = getId (); Produkt p = Product.findById (id); p.fromMap (nyttelast); p.saveIt (); // ...} offentlig ugyldig show () {String id = getId (); Produkt p = Product.findById (id); // ...} offentlig tomrom ødelegge () {String id = getId (); Produkt p = Product.findById (id); p.delete (); // ...}}
Enkelt, ikke sant? Dette gir imidlertid ikke noe ennå. For å gjøre det, må vi lage noen visninger.
7. Visninger
ActiveWeb bruker FreeMarker som en malmotor, og alle malene skal være under src / main / webapp / WEB-INF / visninger.
Inne i katalogen vil vi plassere våre synspunkter i en mappe som heter Produkter (samme som kontrolleren vår). La oss lage vår første mal som heter _product.ftl:
{"id": $ {product.id}, "name": "$ {product.name}"}
Det er ganske klart på dette punktet at dette er et JSON-svar. Selvfølgelig vil dette bare fungere for ett produkt, så la oss fortsette og lage en ny mal som heter index.ftl:
[]
Dette vil i utgangspunktet gi en samling navngitt Produkter, med hver og en formatert av _product.ftl.
Endelig, vi må binde resultatet fra kontrolleren vår til tilsvarende visning:
@RESTful offentlig klasse ProductsController utvider AppController {public void index () {List products = Product.findAll (); visning ("produkter", produkter); gjengi (); } offentlig ugyldig show () {String id = getId (); Produkt p = Product.findById (id); visning ("produkt", p); gjengi ("_ produkt"); }}
I det første tilfellet tildeler vi Produkter liste til malsamlingen vår også Produkter.
Da vi ikke spesifiserer noe syn, index.ftl vil bli brukt.
I den andre metoden tildeler vi produktet s til element produkt i visningen, og vi sier eksplisitt hvilken visning som skal gjengis.
Vi kan også lage et syn melding.ftl:
{"message": "$ {message}", "code": $ {code}}
Og så kaller det fra noen av våre ProductsController‘S metode:
visning ("melding", "Det oppstod en feil.", "kode", 200); gjengi ("melding");
La oss nå se finalen vår ProductsController:
@RESTful offentlig klasse ProductsController utvider AppController {private ObjectMapper mapper = ny ObjectMapper (); public void index () {view ("products", Product.findAll ()); gjengi (). contentType ("applikasjon / json"); } public void create () {Map payload = mapper.readValue (getRequestString (), Map.class); Produkt p = nytt produkt (); p.fromMap (nyttelast); p.saveIt (); visning ("melding", "Vellykket lagret produkt-id" + s.get ("id"), "kode", 200); gjengi ("melding"); } offentlig ugyldig oppdatering () {Map payload = mapper.readValue (getRequestString (), Map.class); Streng-id = getId (); Produkt p = Product.findById (id); hvis (p == null) {view ("melding", "Produkt-id" + id + "ikke funnet.", "kode", 200); gjengi ("melding"); komme tilbake; } p.fromMap (nyttelast); p.saveIt (); view ("melding", "Oppdatert produkt-id" + id, "kode", 200); gjengi ("melding"); } offentlig ugyldig show () {String id = getId (); Produkt p = Product.findById (id); hvis (p == null) {view ("melding", "Produkt-id" + id + "ikke funnet.", "kode", 200); gjengi ("melding"); komme tilbake; } visning ("produkt", p); gjengi ("_ produkt"); } offentlig tomrom ødelegge () {String id = getId (); Produkt p = Product.findById (id); hvis (p == null) {visning ("melding", "Produkt-id" + id + "ikke funnet.", "kode", 200); gjengi ("melding"); komme tilbake; } p.delete (); visning ("melding", "Vellykket slettet produkt-id" + id, "kode", 200); gjengi ("melding"); } @ Override-beskyttet streng getContentType () {return "application / json"; } @ Override-beskyttet streng getLayout () {return null; }}
På dette tidspunktet er søknaden vår ferdig, og vi er klare til å kjøre den.
8. Kjøre applikasjonen
Vi bruker Jetty-plugin:
org.eclipse.jetty jetty-maven-plugin 9.4.8.v20171121
Finn siste jetty-maven-plugin i Maven Central.
Og vi er klare, vi kan kjøre applikasjonen vår:
mvn brygge: løp
La oss lage et par produkter:
$ curl -X POST // localhost: 8080 / products -H 'content-type: application / json' -d '{"name": "Water"}' {"message": "Vellykket lagret produkt-ID 1", " kode ": 200}
$ curl -X POST // localhost: 8080 / products -H 'content-type: application / json' -d '{"name": "Bread"}' {"message": "Vellykket lagret produkt-ID 2", " kode ": 200}
.. Les dem:
$ curl -X GET // localhost: 8080 / products [{"id": 1, "name": "Water"}, {"id": 2, "name": "Bread"}]
.. oppdater en av dem:
$ curl -X PUT // localhost: 8080 / products / 1 -H 'content-type: application / json' -d '{"name": "Juice"}' {"message": "Oppdatert produkt-ID 1" , "kode": 200}
... les den vi nettopp oppdaterte:
$ curl -X GET // localhost: 8080 / products / 1 {"id": 1, "name": "Juice"}
Til slutt kan vi slette en:
$ curl -X SLETT // localhost: 8080 / products / 2 {"melding": "Produkt-ID 2 er slettet," kode ": 200}
9. Konklusjon
JavaLite har mange verktøy for å hjelpe utviklere få en applikasjon i gang på få minutter. Mens det å basere ting på konvensjoner resulterer i en renere og enklere kode, tar det imidlertid en stund å forstå navn og plassering av klasser, pakker og filer.
Dette var bare en introduksjon til ActiveWeb og ActiveJDBC, finn mer dokumentasjon på deres nettsider og se etter produktsøknaden vår i Github-prosjektet.