1. gyakorlat¶
Építsünk valamit¶
A legtöbb esetben a Spring-et backend-ként szokás használni, de a Spring MVC is egy népszerű megoldás. Központi elem a controller vagy controllerek, melyek kapnak egy kérést és azt valamilyen módon kiszolgálják. A válasz lehet legenerált vagy statikus HTML, vagy adat (ha éppen REST API-t) készítünk. A Spring MVC-t alaposan meg fogjuk ismerni a következőkben, melynek szintén része, hogy controller-ekkel dolgozzunk.
Készítsük el a "Contacts" webes alkalmazást, mely egy elektronikus telefonkönyvhöz lesz hasonló! A félév során ezt az alkalmazást fogjuk felépíteni a nulláról, minden alkalommal kicsit továbbfejlesztve azt.
Függőségek¶
Spring MVC-s alkalmazásokkal fogunk dolgozni, így szükségünk lesz még egy-két dependency-re. Ezeket a legegyszerűbb, akkor hozzáadni amikor a Spring Initializr-t használjuk, de utólagos hozzáadásuk sem túl nagy feladat. Ezen a ponton készíthető egy új alkalmazás az initializr-el vagy kövessük a következő lépéseket:
- Mivel webes a projekt, ezért adjuk hozzá a
spring-boot-starter-web
dependency-t! - Mivel szeretnénk HTML válaszokat generálni, így adjuk hozzá a
spring-boot-starter-thymeleaf
HTML templating engine-t a dependency-k közé.
Tehát a pom.xml
-be a következő bejegyzéseknek kell belekerülnie:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Tehát az alkalmazásunkat a Spring MVC (Model, View, Controller) mentén fogjuk fejleszteni. Fontos, hogy egy jól definiált felosztást, csoportosítást (packaging) alkalmazzunk a projekt felépítése során, mivel így sokkal könnyebb lesz karbantartani az alkalmazásunkat!
Thymeleaf
A Thymeleaf egy modern szerver oldali Java-s template engine (view rétegben dinamikusan renderelhetünk tartalmat) mind webes, mind standalone környezetben.
A Thymeleaf fő célja, hogy elegáns módon úgynevezett "natural template"-eket írhassunk. Ennek lényege, hogy például a HTML tartalmat a böngésző helyesen meg tudja jeleníteni még fejlesztés közben is, így prototypinghoz ideálisan alkalmazható, mely növelheti a kollaboráció sikeressegét a csapaton belül.
Különböző modulokkal (dialektusokkal) rendelkezik, melyek között ott van például a Spring dialektus, de ezen felül további dialektusokkal is rendelkezik, illetve saját magunk is írhatunk konkrét megvalósításokat, mely rendkívül rugalmassá teszi ezt a template engine-t.
A Thymeleaf-et alkalmazhatjuk JSP, JSF helyett.
A HomeController¶
Készítsünk egy egyszerű Controller-t, mely a /
-re (root-ra) érkező kéréseket szolgálja ki!
Tipp: Az összes Controller osztályt érdemes egy controller
package-be elhelyezni!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Az osztályunkat a @Controller
annotációval látjuk el, mely jelzi a Spring számára, hogy ez az osztály egy komponens, melyet az automatikus Component Scanning alkalmával meg is tud így találni a rendszer és be tudja regisztrálni, azaz a Spring készíteni fog egy Bean-t ebből az osztályból, mely belekerül az Application Context-be (nekünk magunknak nem kell példányosítani ezt a controller-t).
Figyelem
Amíg másképp nem rendelkezünk, addig a Controller-eknek az Application
osztály package-ében, vagy annak valamely sub-package-ében kell lenniük, különben az Component Scanning nem fogja megtalálni őket.
A @Controller
annotáció helyett használhattunk volna @Service, @Component, @Repository
annotációkat is, ugyanaz lenne az eredmény azonban fontos a szerepüknek megfelelően annotálni az osztályainkat, így a Controller a legmegfelelőbb választás (később látni fogjuk a többieket is akció közben).
A következő fontos elem a home()
metódusra elhelyezett @GetMapping
annotáció, mely jelzi hogy HTTP GET kérések kiszolgálását fogja végezni ez a metódus, méghozzá a root útvonalon.
Maga a metódus csak a "home" szöveget adja vissza, ami elsőre kicsit gagyinak tűnik, de ezt fogja felhasználni a Thymeleaf (pontosabban ez a string lesz a template logikai neve a rendszerben, tehát majd egy "home" nevű template-et kell készítenünk).
Anélkül, hogy a Thymeleaf-el még bármit is csinálnánk, indítsuk el az alkalmazásunkat! Láthatjuk, hogy így az alkalmazásunk már nem terminál rögtön, mivel van egy controller benne, ami várja a HTTP kéréseket. Nyissuk meg a Postman-t, mellyel HTTP kéréseket küldhetünk megadott útvonalakra! Mivel a Spring Boot alkalmazásunk alapból behúz egy TomCat embedded szervert, így nincs is más dolgunk mint megnézni, hogy amikor elindítottuk az alkalmazásunkat, akkor a webes app (TomCat által), melyik porton van hostolva.
1 |
|
Tipp
Az application.properties
állományban megadhatunk más portot is, melyen a szervert indítani szeretnénk.
Ehhez használjuk a következő sort!
1 |
|
Eredményképpen a szerver a 8000-es porton indul el a 8080 helyett.
Ezután a Postman-be állítsuk be hogy GET kérést küldünk a http://localhost:8080/
címre.
A válasz most egy hiba:
1 2 3 4 5 6 7 |
|
Viszont ez jól demonstrálja a spring-boot-starter
depenency-k hatalmát.
Anélkül, hogy bármi különösebbet kellett volna konfigurálnunk, a keretrendszer már tudja, hogy nem egyszerűen egy string-et szeretnénk visszaküldeni, hanem egy template-re adunk hivatkozást.
A kezdőoldal¶
Ha utólag adtuk hozzá a projekthez a Thymeleaf-et, akkor hozzunk létre egy templates
mappát a resources
alatt és azon belül hozzunk létre egy home.html
oldalt, amibe valami tetszőleges szöveget írjunk bele!
Postman-el is tesztelhetjük ezután a működést, vagy böngészőben is megjeleníthetjük az eredményt ha a localhost:8080
-ra navigálunk (Az URL elérése egy GET kérést fog küldeni ilyen esetben. Később azonban a postman még nagyon jól fog jönni, így szokjuk ennek használatát is).
A template-ek elnevezési konvenciója:
/templates/<view template neve>.html
Tipp
Az üres HTML állományba írd be, hogy `html, majd Ctrl + Space és válaszd ki a megfelelő html verziót (esetünkben 5-ös html). Ekkor legenerál az IntelliJ egy alap HTML törzset.
Ahhoz, hogy Thymeleaf-es elemeket is használhassunk be kell húznunk a html-be a Thymeleaf-es xml namespace-t.
Használjuk is, úgy hogy egy stock photo-t rakunk bele a html-be!
A statikus erőforrásokat, mint például a képeket a Thymeleaf szintén egy előre definiált szerkezetben keresi.
A resources alá (a templates-el egy szinten) hozzunk létre egy static
mappát, melyben egy images
mappát is létrehozunk a képeknek!
Keressünk a neten egy szimpatikus contacts témájú logót, amit helyezzük el az előbbi mappába contacts_logo.png
néven!
Ekkor a home.html
a következőképpen alakul:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
A képnek a th:src
-vel adjuk meg a forrását, melyben így használhatjuk a @{...}
alakú kifejezéseket, melyek az application root-hoz képesti relatív útvonal megadását teszi lehetővé.
Próbáljuk ki most az alkalmazásunkat!
Spring dev tools¶
Amikor fejlesztünk, akkor az alkalmazásunkat mindig újra kell indítani, amikor valamilyen kódot megváltoztatunk. A Spring Dev Tools ebben nyújthat segítséget. Előnyei a következőek:
- Alkalmazás újratöltése, amikor a kód változik
- Automatikus böngésző frissítés, amikor frissült valamilyen browser-related erőforrás
- Template cache automatikus letiltása
- Beépített H2 konzol, ha H2-t használunk DB-nek
- Nem IDE függő plugin
Először hozzá kell adnunk a dev toolset-et a projekt függőségeihez.
1 2 3 4 5 |
|
A scope
megadásával a production code-ba nem kerül bele a devtools.
Ha IntelliJ-t használunk a fejlesztéshez, akkor ennyi sajnos nem elég az automatikus újratöltéshez. IntelliJ-ben kicsit trükkös összelőni a dolgokat. Ehhez kövessük a következőket:
File –> Settings... –> Build, Execution, Deployment –> Compiler –> Build project automatically
(kipipálni)File –> Settings... –> Advanced Settings –> Allow auto-make to start even if developed application is currently running
(kipipálni)
Tipp
Előfordulhat, hogy régebbi IntelliJ verzió esetén az utóbbi beállítási lehetőség nem létezik.
Ekkor nyomd meg a Shift+Control+A billentyűkombinációt -> Írd be, hogy Registry
, majd keresd meg és engedélyezd a compiler.automake.allow.when.app.running
bejegyzést!
Ekkor ha futtatjuk az alkalmazásunkat, akkor automatikusan újrafordítja a projektet, amikor valami változik. Azonban a böngésző nem frissül automatikusan, F5-öt kell nyomni, hogy ez megtörténjen. Abban az esetben, ha ezt is szeretnénk belőni, akkor tegyük a következőket:
- Töltsük le a LiveReload plugin-t Chrome alá
- Miután futtatjuk az alkalmazásunkat a böngészőben engedélyeznünk kell a LiveReload plugin-t a jobb felső sarokban
- Ezután, amikor változtatunk a kódon, akkor az automatikusan újrafordul, illetve a böngésző is frissül.
Van még egy fontos dolog, amit még tisztázni kell. A Java kódok frissítését úgy végzi a rendszer, hogy két class loadert használ, egyet a mi saját java osztályainkhoz (mivel valószínűleg ezek változnak gyakran) és egyet a library-k kódjához. Ezt azért csinálja, hogy időt nyerjen vele, mivel változáskor csak az első loader által érintett elemek töltődnek újra. Ez sajnos azt is jelenti, hogy amikor például egy dependency módosul, akkor nem tudja az automatikus frissítést megtenni a rendszer, ilyenkor egy hard restart kell.
Teszt írása az alkalmazáshoz¶
Ha működik az alkalmazásunk, nézzük hogy hogyan írhatunk hozzá tesztet. Webes alkalmazások tesztelése trükkös lehet, de szerencsére a Spring ehhez is ad támogatást.
Először is adjuk hozzá a következő dependency-t:
1 2 3 4 5 |
|
A teszt végrehajt egy HTTP GET hívást a /
-ra, és figyeli, hogy az a home-ot adja-e vissza illetve azt, hogy a template milyen tartalmat generál.
Lássuk magát a tesztet:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Tipp
A spring-boot-starter-test
további függőségeket húz be, többek között a JUnit-ot is.
A fenti példa a JUnit 5-ös verziójával készült.
Ha JUnit-ból valamely 4-es verzió áll rendelkezésünkre, vagy kifejezetten ezt a verziót szeretnénk használni az 5-össel szemben, akkor az @ExtendWith(SpringExtension.class)
helyett használjuk a @RunWith(SpringRunner.class)
annotációt, valamint az org.junit.jupiter.api.Test
helyett az org.junit.Test
-et importáljuk.
Az osztályt @WebMvcTest
annotációval látjuk el.
Ez a speciális, Spring által biztosított annotáció azt a célt szolgálja, hogy ezt a tesztet Spring MVC alkalmazás kontextben futtassa a rendszer.
Egész pontosan a HomeController regisztrálásra kerül a kontextben, így tudunk számára request-eket küldeni a tesztek közben.
A MockMvc
injektálásával irányíthatjuk a tesztünket, hozzáférhetünk a mokkolt objektumhoz.
Az egyetlen teszt metódus (@Test
-el ellátva) ezt a mokkolt objektumot használja, melyen keresztül küldhetünk egy GET kérést a homePage-nek ("/"
, azaz a rootnak küldjük).
Ezután leteszteljük, hogy az elvárt eredményeket kaptuk-e (200-al tér vissza, logikai neve a "home"
, és kirenderelődött a "Hello"
szöveg).
Amennyiben valamelyik feltétel sérül, akkor a teszt el fog hasalni.
Kontaktok kezelése¶
Az alkalmazásunk biztosítson felületet kapcsolatok felvételére!
A Spring-ben is a controller feladata az adat elérése és annak megfelelő feldolgozása. A View feladata, hogy ezen adatot megjelenítse a felhasználó számára, jelen esetben HTML tartalmat adjon.
Amiket el kell készítenünk:
- Domain model, mely egy kapcsolat leírására szolgál
- Egy controller, amin keresztül hozzáadhatunk és lekérhetünk kontaktokat
- Maga a view template, ami rendereli a kontakt formot és a kontaktok listáját (külön-külön view) a böngészőben.
Domain model¶
Egy kapcsolat a következőkkel rendelkezzen!
- egyedi azonosító
- név
- telefonszám
- lakcím
- születésnap
- létrehozás dátuma
Ennek tükrében a model osztályunk:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
De mi a nyavaja az a lombok és miért jó ha ezt használjuk?
A lombok nem a Spring része, de igen hasznos kis library, mivel segítségével sokkal tömörebb model osztályokat írhatunk, illetve változtatások alkalmával nem kell mindent átnevezni (pl getter, setter).
Ha megfigyeljük, akkor nincs se konstruktor, se getter/setter megadva.
Ezeket mind a lombok generálja futásidőben, amihez nem kell mást csinálnunk mint a @Data
annotációt rárakni az osztályunkra.
Ez ellátja az osztályunk adattagjait getter/setter párosokkal (nyilván ha final a field akkor setter-t nem fog hozzáadni), továbbá készít toString
, hashCode
, equals
metódusokat és egy paraméteres konstruktort is (az összes paraméter szerepel benne).
Látható, hogy a @Data
annotáció összetett és sok dolgot legenerál magától.
Ha ezek közül valamelyiket nem szeretnénk, akkor szükség lehet arra, hogy egyenként tudjuk ezeket befolyásolni.
A @Data
megegyezik a következő lombok-os annotációk összességével:
@Getter
@Setter
@RequiredArgsConstructor
@ToString
@EqualsAndHashCode
A lombok használatához az alábbi dependency-re lesz szükségünk:
1 2 3 4 |
|
Előfordulhat, hogy az IDE hibát jelezni amint használnánk valamelyik generált metódust, hiszen ezeket csak futásidőben generálja le a rendszer. Amennyiben IntelliJ-t használunk, akkor a lombok honlapján leírt lépéseket kell követnünk. Más IDE-hez is megtalálhatjuk itt a szükséges beállításokat.
Controller elkészítése¶
A controllerek az alkalmazásunk lelkét alkotják, elsődleges feladatuk a HTTP kérések kezelése, majd a kérés továbbpasszolása a megfelelő view-nak, ami kirendereli a HTML-t (MVC esetében), vagy közvetlenül ők írják a választ nem pedig a view (ilyenkor beszélünk RESTful controller-ről). Utóbbival később fogunk foglalkozni, egyelőre mindig átpasszoljuk a view-nak a kérést és ő intézi a megjelenítést. Nézzük miket is kell tudnia a controllerünknek, ahhoz hogy összerakhassunk egy kontaktot:
- HTTP GET kérés kezelése a
/contact/create
URL-en - Meg kell adni a megfelelő adatokat
- Át kell passzolni a kérést a megfelelő view-nak, ami majd a renderelést végzi
Nézzük is, hogy hogyan nézhet ez ki:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
A controller-re itt is rárakjuk a @Controller
stereotype annotációt, így automatikusan regisztrálja a Spring a bean-ek között.
Jelen esetben az osztályra helyezünk el egy @RequestMapping("/contact")
annotációt, mellyel az osztály handler metódusai egységesen a /contact
URL alá kerülnek regisztrálásra.
Ettől függetlenül a showContactCreateForm
metódus @GetMapping
annotációjában megadhatunk további URL részeket, pl: @GetMapping("/create")
, mely esetben a a metódus a /contact/create
URL-re fut le.
Jelen esetben ez a kérés csupán továbbhajít minket a contact-create.html
oldalra.
View template¶
Írjuk meg a view template-et!
Ahogy korábban is tettük a /resources/templates
alá hozzunk létre egy contact-create.html
oldalt!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
|
Mielőtt megnéznénk, hogy pontosan milyen Thymeleaf-es elemeket használunk a fenti példában, érdemes egy kicsit általánosságában beszélni a Thymeleaf-ről.
Spring MVC-ben két interface szolgálja ki a template engine-eket:
- org.springframework.web.servlet.View
- org.springframework.web.servlet.ViewResolver
A View
felelős a megadott HTML tartalom rendereléséért, melyet általában a template engine (pl.: Thymeleaf) végez.
A ViewResolver
egy olyan objektum, mely megadott kérésre (műveletre) és locale-ra visszaadja a megfelelő View
-t.
Tipikusan a controller-ek megkérik a ViewResolver
-t, hogy továbbítsa őket a megadott nevű view-hoz (elérhető String visszatéréssel, ahogyan azt mi is csináltuk).
Fontos, hogy ViewResolver-ből egy egész láncolatunk is lehet (hasonlóan, mint a FilterChain), de a láncolat végén el kell, hogy dőljön, hogy melyik View végzi a renderelést.
Ha a fenti kódot megvizsgáljuk, akkor látunk többféle kifejezést is a HTML-be ágyazva (pl.: ${contact}
).
Nézzük meg, hogy milyen típusú kifejezéseket adhatunk meg.
${...}
: Variable expression*{...}
: Selection expresison#{...}
: Message (i18n) expression@{...}
: Link (URL) expression~{...}
: Fragment expression
Röviden nézzük át azokat melyeket a fenti példában használunk (a többit később vesszük majd elő).
Variable expression¶
Spring-el való integráció esetében az ilyen expression a Spring EL (Spring Expression Language) része.
A kifejezéssel a context
változókra (a Spring model attribute
is szokta hívni) adhatunk kifejezéseket.
Egy példa lehet:
1 |
|
Használatuk általában attributumokban történik:
1 |
|
1 |
|
Variable expression-ök előfordulhatnak olyan helyen is ahol közvetlenül nem állítunk elő output-ot (nem rendereli egyből), pl: iterációkban:
1 |
|
contact
változóhoz.
Selection expression¶
Hasonló a variable expression-höz, de annyi különbséggel, hogy ezek az előzőleg kiválaszott objektumon értékelődnek ki, nem pedig az összes context változón. Pl:
1 |
|
Egy ilyen kiválasztást tesz meg például a form-on megadott th:object
.
Így a form fieldekre megadott selection expression-ök ezen a contact
objektumon értékelődnek ki.
Pl: *{name}
nem mást jelent mint ${contact.name}
, ami megegyezik a
1 |
|
A fenti példában a th:field
használata miatt egy kötés jön létre a form field-jei és a contact
objektum adattagjai között.
Link (URL) expression¶
Ezt már láttuk korábban is, amikor a home.html
oldalon megadtuk a képünk elérését:
1 |
|
Alapvetően arről van szó, hogy URL-eket rakunk össze ezekkel a kifejezésekkel, úgy hogy context és session infokat adhatunk hozzá. Pl. a következő kifejezés:
1 |
|
1 |
|
viszont nem kell nyilvántartani, lekéregetni a context-et (myapp), majd összefűzni a megadott url-el.
Amennyiben a rendszerben engedélyezve van a session követés akkor akár a következőt is kaphatjuk:
1 |
|
, azaz a rendszer automatikusan beilleszti a session id-t az URL-be.
Ami később fontos lehet, amikor majd egy-egy kontaktot kiválasztva egy details oldalra szeretnénk átvinni a felhasználót, az az, hogy az URL is kaphat paramétereket. Pl:
1 |
|
1 |
|
A Link Expression-ök lehetnek relatív megadások is. Ilyen esetben az application context nem kerül bele az url-be prefixként. Pl:
1 |
|
Most, hogy helyére tettünk néhány Thymeleaf-es dolgot vesézzük ki alaposabban a megírt kódot!
Az első fontos rész, hogy a form method attribútuma POST
, viszont nincs beállítva action
, ahol megmondanánk hogy a kérést hova küldjük (pontosabban megadtuk, de a #
ezt jóformán semmire állítja).
Ilyen esetben ugyanarra az url-re fogja küldeni, ahol vagyunk, vagyis a /contact/create
URL-re (itt fogjuk majd megírni azt a metódust, ami kezeli a POST
-ot a ContactController
-ben).
Ugyanakkor megadjuk a th:action
-t melyben most megadjuk, hogy hova is menjen a kérés (link expression használatával).
A következő fontos elem a th:object
attribútum.
Ebben az atribútumban adhatjuk meg az ún. command object-et, mely alatt a Spring a form-backing bean-eket (azaz a form-hoz rendelt bean-eket) érti.
A th:object
-et máshol is használhatjuk (nem csak form-on), de ebben a kontextusban fontos, hogy a következő megkötések vannak:
- a
th:object
atribútum értékének csak variable expression-t adhatunk meg, melyben csak a model attribútum nevét adjuk meg (magáról a model attribútumokról hamarosan hallunk még sokkal többet, de lényeg, hogy ez az, amit a controller átad a view számára). Fontos, hogy nem lehet benne property kiválasztás (tehát a${contact}
helyes, de a${contact.name}
már nem az). - A
<form>
-on belül már nem használhatunk másikth:object
-et (HTML form-ok amúgy sem ágyazhatóak egymásba, különben következetlenség lépne fel).
Tipp: A HTML oldal header-jébe behúztuk a Bootstrap CSS és JS elemeket, így használhatjuk a Bootstrap nyújtotta előnyöket.
Amennyiben az alkalmazásnkat jelen állapotában futtatjuk, akkor látnunk kell egy form-ot, amely bekéri a megfelelő kontakt tulajdonságokat (név, email, stb.), valamint van egy gombunk, amit ha megnyomunk, akkor azt fogja írni, hogy a POST kérés típus nem támogatott (Request method 'POST' not supported
).
A következőkben nézzük meg, hogy hogyan lehet ezt kezelni, azaz a POST-ban elküldött adatokat feldolgozni.
POST kezelése¶
Az egyszerűség kedvéért csak annyit csinálunk a POST kezelésekor, hogy logoljuk az elküldött adatokat, majd újra a /contact/create
oldalt mutatjuk.
1 2 3 4 5 |
|
A GetMapping
-hez hasonlóan létezik @PostMapping
is (továbbá az összes alap kéréstípushoz van megfelelő: @DeleteMapping, @PutMapping
, stb).
Mivel a form-ban azt mondtuk, hogy a POST a /contact/create
-re érkezzen, így itt is a /create
-et adtuk meg, ugyanúgy, ahogy a GET esetében is.
A kód jelen pillanatban még hibás, mivel nincs log objektumunk.
Aki használt már logolást a rendszerében az tudja, hogy a logger példányosítása mindig kopizással, de legalábbis unalmas gépeléssel történik.
Valami ilyesmi lenne ha mondjuk az Slf4J loggert használnánk:
1 |
|
ezen felül a logolás config property-jeit is meg kellene adnunk.
A lombok ebben is támogatást nyújt.
A fenti adattag létrehozás helyett használhatjuk egyszerűen a Slf4J
annotációt az osztályon és máris ismerni fogja a log
objektumot a rendszer.
Az Slf4J használatáról további infok itt találhatóak.
Az egyik érdekes dolog, hogy a metódus paramétere egy Contact
.
Mivel a view-ban megmondtuk, hogy a name
és azemail
, stb form-data állítódjék be a felületi elemeknek megfelelően (th:object
és th:field
használata), így ezeket át fogja passzolni ennek a contact objektumnak, amit automatikusan létre is hoz a rendszer.
Ezután simán logoljuk, a contact-ot, amit látnunk is kell majd a konzolon.
Továbbá érdemes lehet megnéznünk a böngésző devTools-a alatt, hogy a hálózati küldések során milyen adatokat küldött el a POST kérés.
Egy rész még kimaradt a kódból, mely igen fontos. A dátumok változatos megadásuk miatt nem biztos, hogy automatikusan parse-olhatóak, így erről nekünk kell gondoskodnunk. Amennyiben csak az adott controller-ben szeretnénk használni a konvertert, akkor megadhatjuk a következőképpen:
1 2 3 4 |
|
String
-ből képződik, illetve engedélyezünk üres field-et is (ilyen esetben a birthDate null
értéket fog felvenni).
Ezzel meg is volnánk, szóval futtassuk le az alkalmazásunkat.
Ha létrehozunk egy contact-ot a /contact/create
oldalon, akkor az IDE-ben valami hasonló log sornak kell megjelennie a konzolon (ez az alapértelmezett beállítása az Slf4J-nek):
1 |
|
Feladatok¶
Feladat
Készítsünk tesztet a /contact/create
-hez