A gyakorlat célja, hogy a hallgatók megismerjék a JPA és a Spring Data használatát. A főbb témák: entitások fejlesztése, lekérdezések megfogalmazása különböző módokon, módosítások végrehajtása. A kódokat egy webalkalmazás projektbe integráljuk, amiben a projekt alapvető konfigurációja és egy teszteléshez használható egyszerű webes felületet már készen áll.
A labor elvégzéséhez szükséges eszközök:
- A kiinduló alkalmazás kódja: https://github.com/BMEVIAUBB04/gyakorlat-jpa
- Legalább 17-es JDK, pl. OpenJDK: https://adoptium.net/
- Tetszőleges Java alapú, Mavennel integrálódó IDE. A gyakorlatothoz kapcsolódó videón a Spring Tools 4 for Eclipse-et használjuk: https://spring.io/tools
- A gyakorlat otthoni megoldása során szabadon választható az adatbázis
- Az egyszerűbb megoldás a beágyazott hsqldb használata. Ennek lényege, hogy ha az alkalmazást a megfelelő Spring profile-lal futtatjuk (az application.properties fájlban töröljük a komment jelet a spring.profiles.active=hsql sor elején), akkor az alkalmazással egy processzben létrejön az adatbázis is, és egyből mintaadatokat is beleszúrunk. Az SQL Server telepítése teljesen kihagyható ebben az esetben.
- A másik lehetőség a Microsoft SQL Server Express használata (localdb nem alkalmas). Ebben az esetben a projekt application.properties fájljában lévő spring.profiles.active=hsql sort törölni kell, vagy kommentbe tenni (by default kommentben van)
- A telepítő innen tölthető le: https://www.microsoft.com/en-us/download/details.aspx?id=55994
- Szintén szükség lesz az SQL Server Management Studio-ra: https://aka.ms/ssmsfullsetup
- Telepítés után az SQL Server by default nem fog TCP porton figyelni. A JDBC driver viszont csak TCP porton keresztül tud csatlakozni hozzá, ezért ezt be kell állítanunk:
- Engedélyezni kell a TCP/IP kapcsolatot, a "mixed mode" authentikációt és az "sa" usert
- Képek a beállításokról: https://1drv.ms/w/s!ApHUeZ7ao_2ThuZgTdcGJeHjncRB7Q?e=YIb13k
- SQL Server Configuration Manager-ben:
- "Protocols for SQL Express" alatt TCP/IP
- Első tabon: enabled=yes
- Második tabon legalul: "IPAll" alatt "TCP Port" 1433
- SQL Server Management Studio-ban
- Server tulajdonságok alatt Security / "Sql Server and Windows Authentication mode"
- Security/Logins/sa user tulajdonságai alatt
- Jelszó: bármi, de jegyezd meg
- NE legyen bepipálva az "Enforce password policy"
- Status fül alatt: login: enabled
- Szükség lesz az adatbázis létrehozó scriptre: mssql.sql
- JPA előadás
- EJB, Spring előadás
A gyakorlat végig vezetett, a gyakorlatvezető utasításai szerint haladjunk. Bizonyos feladatoknál több megoldási lehetőséget is említ ez az útmutató, de a gyakorlatvezető nem mindegyiket mutatja be. Érdemes ezeket is kipróbálni önálló gyakorlásként. A taanszéki portálra töltsd fel a megoldás projektet zippelve. (A target mappát kivéve, azt töröld.)
Emlékeztetőként a megoldások is megtalálhatóak az útmutatóban is. Előbb azonban próbáljuk magunk megoldani a feladatot!
- Típus (osztály, interfész, enum) keresése: Ctrl+Shift+T (Nem érdemes a Project explorer-ben a mappákat nyitogatni)
- Fájl keresése: Ctrl+Shift+R
- Hiányzó importok megjavítása: Ctrl+Shift+O
- Kód formázása: Ctrl+Shift+F
- Ha a Java Resources alatt egy package-en jobb klikk / New Class/Interfaces, akkor abba a package-be rakja az új elemet by default
- Ha a nézeteket becsukjuk/átrendezzük, a default elrendezés visszaállítható: Window / Reset perspective
- Font megnövelése (a tanári gépen hasznos):
- Window menü / Preferences, ott elkezdjük gépelni, hogy font, így megtalálja azt a beállítást, hogy Fonts and Colors
- Azt kiválasztva, a Basic kategória alatt kell a Text Fontot kijelölni, és a méretét pl. 18-asra állítani
-
Csatlakozzunk Microsoft SQL Server Management Studio-val a a szerverhez. Ezúttal nem localdb-t használunk, a szerver címe:
localhost\sqlexpress
. A bejelentkezéshez SQL Server Authentication módot válasszuk. -
Hozzunk létre egy
hatteralk
nevű adatbázist (ügyeljünk a névre, különben a Java projektben módosítanunk kell). Az adatbázis létrehozásának mikéntjét lásd az első gyakorlat anyagában. Ha a gépen már létezik az adatbázis, akkor nem kell újat létrehozni. -
Futtassuk le az adatbázis inicializáló sql szkriptet az adatbázisban. Akkor is futtassuk le a szkriptet, ha már létezne az adatbázis (hogy a kezdeti állapotot visszakapjuk.)
- Indítsuk el az Eclipse-et innen:
C:\Tools\Hatteralkalmazasok\eclipse\SpringToolSuite4.exe
. (Fontos, hogy lehet egyD:\eclipse
mappa is, nekünk nem az kell.) Otthoni megoldás esetén természetesen a saját IDE-t indítsd el. - Indításkor megkérdezi, hova akarunk dolgozni (workspace), itt a laborbeli megoldás esetében válasszuk ezt:
C:\Tools\Hatteralkalmazasok\workspace
- Ha az indulás után a Project Explorer-ben ott van egy korábbi gyakorlatról a webshop nevű projekt, azt töröljük ki: a projekten jobb klikk / Delete, amikor rákérdez, pipáljuk be, hogy a fájlrendszerről is törlődjön.
-
Töltsük le a méréshez tartozó projekt vázat!
- Nyissunk egy command prompt-ot
- Navigáljunk el egy tetszőleges mappába, például
c:\work\NEPTUN
- Adjuk ki a következő parancsot:
git clone --depth 1 https://github.com/BMEVIAUBB04/gyakorlat-jpa.git
-
Importáljuk a letöltött forráskódot a workspace-be:
- Nyissuk meg a File / Import...-ot
- Kezdjük el gépelni a textboxba, hogy Existing projects into workspace, így rá fog szűrni és válasszuk ki ezt
- Keressük meg a kicsomagolt webshop projektet (a
webshop
mappát a saját könyvtárunk alatt), OK, utána a dialogban pipáljuk be a webshop-ot (lehet, hogy by default be lesz pipálva) - Finish
-
Tekintsük át röviden a projektet:
-
Ez egy maven alapú projekt. A maven parancssori build eszköz, ami IDE-khez is illeszthető. Fontos tulajdonsága, hogy képes a szükséges library függőségeket online repository-kból letölteni. Ha megnyitjuk a projekt gyökerében
pom.xml
-t, a maven konfig fájlját, dependency tagekben függőségeket látunk, amik (tranzitív módon) behúzzák a Hibernate-et mint JPA implementációt, a Spring Boot-ot, a Spring Data-t és a webréteghez szükséges Spring MVC-t és Thymeleaf-et. A laborban a maven offline működésre van konfigurálva, és előre le van töltve az összes függőség, így megelőzzük az esetleges hálózati problémákat. Otthon az import után eltarthat egy ideig, amíg minden függőség letöltődik. -
Az application.properties-ben van pár alapvető beállítás, itt a DB eléréshez ellenőrizzük az adatbázis URL-t, usernevet és jelszót, ha MSSQL-t szeretnénk használni. Szintén ebben az esetben kapcsoljuk ki a hsql profile-t aktiváló sort. Ha ezt ugyanis bent hagyjuk, az application-hsql.properties-ben lévő üres datasource property-k fognak érvényre jutni, amely esetben a Spring Boot by default egy beágyazott adatbázist fog használni. (Hsqldb helyett H2 vagy Derby is használható lenne.)
-
A
WebshopApplication
a Spring Boot alkalmazás belépési pontja és konfigja is. Egy hagyományos webalkalmazást egy külön processzben futó webkonténerre (pl. Tomcat, Jetty) kellene telepíteni. Spring Boot-os fejlesztés esetében viszont maga a Spring Boot fog elindítani egy beágyazott webkonténert (alapértelmezésben Tomcat-et). -
A webes felület egyetlen oldal, az
src\main\resources\templates\testPage.html
. Ebbe nem fogunk majd belenyúlni. Standard html + Thymeleaf-es attribútumok látahtóak benne. -
WebshopController: a webréteget megvalósító controller osztály, ennek metódusai kezelik az alkalmazáshoz érkező HTTP kéréseket. Jellemzően lekérdezések eredményét akarjuk megjeleníteni az oldalon, ezért a lekérdezés eredményét a modellbe tesszük valamilyen néven, amire hivatkozni tudunk a Thymeleaf segítségével. A
//TODO
részekre kell majd bekötni az egyes feladatokat megvalósító metódusok meghívását.
-
-
Az entitások már előre készen a
hu.bme.aut.hatteralk.webshop.model
package-ben találhatók. Ezeket általában vagy kézzel írjuk meg, vagy generáljuk a DB táblákból pl. az Eclipse-es JPA plugin segítségével. -
Az entitások közül nyissunk meg egyet, pl.
Afa
, látszik benne a@Entity
, a@Id
annotáció, illetve a kapcsolatok definiálására@OneToMany
vagy@ManyToOne
-
Az entitásokhoz a Criteria API használatakor hasznos metamodel osztályok is generálódnak, ezekből nézzünk meg egyet a
target\generated-sources\apt
alatt (Apom.xml
-ben látható maven-precessor-plugin generálja egyébként őket a build során.)
A leképzett adatmodellen fogalmazd meg az alábbi lekérdezéseket! A lekérdezéseket JPA és Spring Data használata esetén több módon is megvalósíthatjuk. Az alábbi feladatokban azt is megadjuk, milyen módon kell elkészíteni a lekérdezést, hogy mindegyikre lássunk példát. Fontos megjegyezni, hogy ezek a módszerre vonatkozó megkötések csak oktatási szempontok miatt szerepelnek, valójában bármelyik módszerrel bármelyik lekérdezés megvalósítható lenne.
Az egyes feladatokat megvalósító metódusokat mindig a WebshopController
osztály megfelelő //TODO
kommentjeinél kell meghívni, majd a webalkalmazást futtatni és böngészőből tesztelni a
http://localhost:9080 URL-en.
a) Listázd azon termékek nevét és raktárkészletét, melyből több mint 30 darab van raktáron! Módszer: Spring Data repository interfész, metódusnévből származtatott lekérdezés.
b) Írj olyan lekérdezést, mely kilistázza azon termékeket, melyből legalább kétszer rendeltek! Módszer: Spring Data repository custom implementációval, injektált EntityManagerrel készített JPQL query.
c) Listázd ki a legdrágább termék adatait! Módszer: Named query, amelyet Spring Data repository-ból hívunk meg, vagy custom implementációból, injektált EntityManagerrel hívunk meg, vagy a metódusnév és query név egyezése alapján.
Futás közben a Console nézetben látszódnak a Hibernate által generált SQL utasítások az application.properties-beli spring.jpa.show-sql=true
konfig miatt.
A projektben megtalálható (a legalsó fájl a Project Explorerben) a webshop run.launch nevű konfig fájl. Ezen jobb klikk / Debug As / webshop run. Ez debug módban indítja a Spring Boot maven plugin-t, aminek hatására a beágyazott webkonténer elindul, és böngészőből a http://localhost:9080 URL-en elérhető az alkalmazás. (Az application.properties definiálja ezt a portot a default 8080 helyett, mert a laborban előfordult port ütközés más szoftverrel.) Ha ezt egyszer jobb klikkel megcsináltuk, akkor később a toolbar Debug ikonját lenyitva is megtehetjük:
Ha a Debug ikon alatt már ott van a webshop run, akkor az egész fentebb leírt webshop run.launch-os módszer szükségtelen.
A futó alkalmazást a Console nézet piros Terminate ikonjával lehet leállítani. Ha leállítás nélkül próbáljuk újra futtatni, akkor a második processz ütközést jelent a 8080-as porton, és leáll. Ilyenkor a sikertelen második futtatás látszik a Console nézetben, a Terminate gomb pedig inaktív, mivel ez a futás már leállt. Nyomjuk meg a Terminate ikon melletti dupla szürke X ikont, ez el fogja távolítani a már leállított futtatásokat, és csak az aktív futtatás látszik, amin viszont már tudunk Terminate-et nyomni.
Ha a teljes Console nézetet bezárjuk véletlenül, elő lehet szedni Alt+Shift+Q, C gyorsbillenytűvel, vagy Window / Show View / Console menüvel.
A leállítás utáni újrafuttatáshoz az F11-et is használhatjuk.
A debug módban való futtatás jellegzetessége, hogy a HTML és bizonyos Java kód módosítások azonnal életbe lépnek. (A böngészőt persze frissíteni kell.) Újra kell viszont indítani az alkalmazást, ha a Java kódban:
- új típust adtunk hozzá
- annotációt adtunk hozzá/töröltünk/módosítottunk
- új osztály- vagy tagváltozót, metódust vettünk fel
- metódus szignatúrát módosítottunk
Röviden: a metódus törzsön belüli változásokon kívül mindig újraindítás lesz szükséges.
Megoldás
Nyissuk meg a dao
package-ben lévő TermekRepository
interfészt, amely a Spring Data-s JpaRepository
-ból származik (és az egyelőre üres TermekRepositoryCustom
-ból). Találunk benne későbbi feladathoz kapcsolódó metódusokat, azokat csak figyeljük meg. Valamelyik @Query
annotációval definiálja a futtatandó lekérdezést, valamelyiknél az is hiányzik. Nekünk sem lesz szükség @Query
annotációra, mert a metódus neve alapján a Spring Data képes kitalálni a query-t. Tegyük tehát bele ezt az új metódust:
package hu.bme.aut.hatteralk.webshop.dao;
import java.math.BigDecimal;
import java.util.List;
import hu.bme.aut.hatteralk.webshop.model.Termek;
import org.springframework.data.jpa.repository.JpaRepository;
public interface TermekRepository extends JpaRepository<Termek, Long>, TermekRepositoryCustom {
...
List<Termek> findByRaktarkeszletGreaterThan(BigDecimal limit);
}
A WebshopController
-ben már be van injektálva egy TermekRepository
típusú tagváltozó, hívjuk meg rajta a metódust az 4.a TODO-nál:
@Controller
public class WebshopController {
@Autowired
TermekRepository termekRepository;
//...
// 4.a feladat
private List<Termek> findTermekek30Folott() {
return termekRepository.findByRaktarkeszletGreaterThan(BigDecimal.valueOf(30));
}
}
A dao
package-ben lévő TermekRepositoryCustom
interfészbe vegyük fel egy findLegalabbKetszerRendeltTermekek
nevű metódust:
package hu.bme.aut.hatteralk.webshop.dao;
import hu.bme.aut.hatteralk.webshop.model.Termek;
import java.util.List;
public interface TermekRepositoryCustom {
List<Termek> findLegalabbKetszerRendeltTermekek();
}
A dao package-ben lévő TermekRepositoryImpl
osztály hibás lesz emiatt, mert nem implementálja a TermekRepositoryCustom
-ot. Nyissuk meg az osztályt, és az osztály elején, a sor elején megjelenő kis villanykörtére kattintva belegeneráltathatjuk a nem implementált metódus vázát:
Utána a törzsbe írhatjuk az implementációt, melynek lényege: injektált EntityManager-rel hozzuk létre és futtatjuk le a query-t. (Most látszik igazán, hogy az előző, Spring Data-s megoldás mennyi boilerplate kódot spórolt meg nekünk.)
package hu.bme.aut.hatteralk.webshop.dao;
import hu.bme.aut.hatteralk.webshop.model.Termek;
import java.util.List;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
public class TermekRepositoryImpl implements TermekRepositoryCustom {
@PersistenceContext
EntityManager em;
@Override
public List<Termek> findLegalabbKetszerRendeltTermekek(){
return em.createQuery("SELECT DISTINCT t FROM Termek t
LEFT JOIN FETCH t.megrendelestetels
WHERE size(t.megrendelestetels) >= :tetelMin", Termek.class)
.setParameter("tetelMin", 2)
.getResultList();
}
}
Megjegyzés a megoldáshoz: az első ötletünk ez lehetne: SELECT t FROM Termek t WHERE size(t.megrendelestetels) /= :tetelMin
. Írjuk be és próbáljuk ki előbb ezt, ilyenkor viszont org.hibernate.LazyInitializationException
dobódik teszteléskor, mert lecsatolt állapotban akarunk kapcsolódó entitást elérni (amikor a táblázatot generálja a webréteg, és a megrendelestetels listára hivatkozunk). Lehetséges megoldások:
- Az application.properties-ben
spring.jpa.open-in-view=true
(ez lenne amúgy a default Spring Boot esetében, de a példa projektben direkt false-ra van állítva): Ilyenkor az EntityManager már a webes kérés legelején létrejön, és csak a view renderelése után záródik be, vagyis a Spring bean-beli metódusok visszatérése után is menedzselt állapotban lenne a termek entitás, és el lehetne kérni a kapcsolódó megrendelestetels listát. - vagy
@OneToMany(fetch=EAGER)
a megrendelestetels változóra - vagy EntityGraph definiálása és annak alkalmazása a query létrehozásakor
- vagy
LEFT JOIN FETCH
, mi ezt választottuk a fenti megoldásban. E mellé aDISTINCT
is kell, különben minden kapcsolódó Megrendelestetel példányra külön Termek sor is lesz.
A meghívás a WebshopController
-ben triviális:
// 4.b feladat
private List<Termek> findLegalabbKetszerRendeltTermekek() {
// TODO
return termekRepository.findLegalabbKetszerRendeltTermekek();
}
A Termek
osztályt nyissuk meg, ott a gyorsabb haladás érdekében már fogunk találni kész named query-ket, a másodikat kell használnunk:
@NamedQueries({
@NamedQuery(name="Termek.findAll", query="SELECT t FROM Termek t"),
@NamedQuery(name="Termek.findLegdragabb", query="SELECT t FROM Termek t
WHERE t.nettoar IN (SELECT MAX(t2.nettoar) FROM Termek t2)")
})
A named query-t két módon is meghívhatjuk. Ha lassú a haladás, elég az első módszerrel megcsinálni. Az első módszer, hogy a named query-vel egyező nevű metódust teszünk a TermekRepository
-ba (leszámítva a Termek. előtagot.) Vagyis:
public List<Termek> findLegdragabb();
A másik lehetőség, hogy a TermekRepositoryImpl
-ben, EntityManager
-en keresztül hívjuk meg a named query-t:
@Override
public List<Termek> findLegdragabbTermek(){
return em.createNamedQuery("Termek.findLegdragabb", Termek.class).getResultList();
}
Ilyenkor ezt a metódust ki kell még tenni a TermekRepositoryCustom
interfészbe. Leggyorsabb így: Jobb klikk / Refactor / Pull up, és ott a metódus kiválasztható
Végül valamelyik verziót hívjuk meg a WebshopController
megfelelő pontján:
// 4.c feladat
private List<Termek> findLegdragabbTermekek() {
// TODO
// return termekRepository.findLegdragabbTermek();
return termekRepository.findLegdragabb();
}
A JPA nemcsak lekérdezéshez használható, hanem rajta keresztül módosítások is végrehajthatóak.
a) Írj olyan JPQL lekérdezést a TermekRepository
interfészbe, mely az "Építo elemek" árát megemeli 10 százalékkal!
b) Írj egy olyan metódust, amely létrehoz egy új kategóriát "Drága játékok" névvel, ha még nem létezik ilyen, és sorold át ide az összes olyan terméket, melynek ára, nagyobb, mint 8000 Ft!
c) Egyszerű önálló feladat: az 5.b feladat közös megoldásában egy EntityManager
-en keresztül lefuttatott lekérdezéssel ellenőrizzük, hogy létezik-e "Drága játékok" nevű kategória. Valósítsd meg ugyanezt a lekérdezést Spring Data repository interfészben, metódus névből származtatott lekérdezéssel, és hívd meg a megfelelő ponton.
Megoldás
A TermekRepository
interfészben egy UPDATE query-t definiálunk. Azt, hogy ez módosító query, közölni kell a Spring Data-val (@Modifying
), valamint tranzakcióba is kell tennünk @Transactional
, az org.springframework...
package-ből):
@Modifying
@Transactional
@Query("UPDATE Termek t SET t.nettoar=t.nettoar*1.1 WHERE t.id IN
(SELECT t2.id FROM Termek t2 WHERE t2.kategoria.nev=:kategoriaNev)")
void kategoriaDragit(@Param("kategoriaNev") String kategoriaNev);
Meghívása a WebshopController
-ből:
// 5.a feladat
@RequestMapping(value = "/epitoElemekDragit", method = {
RequestMethod.POST, RequestMethod.GET })
private String epitoElemekDragit() {
// TODO
termekRepository.kategoriaDragit("Építo elemek");
return "redirect:/";
}
Böngészőben a gomb megnyomása után a gomb alatti táblázatban látszódik az átárazás hatása.
A dao
package-be új osztály, KategoriaService
néven, @Service
annotációval, szintén @Transactional
metódussal:
@Service
public class KategoriaService {
@PersistenceContext
private EntityManager em;
@Autowired
TermekRepository termekRepository;
@Transactional
public void createDragaJatekokEsAtsorol(double arLimit){
String nev = "Drága játékok";
Kategoria dragaKategoria = null;
List<Kategoria> resultList =
em.createQuery("SELECT k from Kategoria k WHERE k.nev=:nev", Kategoria.class)
.setParameter("nev", nev)
.getResultList();
if(resultList.isEmpty()){
//0 vagy null id érték esetén fog a @GeneratedValue működésbe lépni. Most primitív long az id-nk, az csak 0 tud lenni, null nem.
dragaKategoria = new Kategoria(0, nev);
em.persist(dragaKategoria);
}else{
dragaKategoria = resultList.get(0);
}
List<Termek> dragaTermekek = termekRepository.findByNettoarGreaterThan(arLimit);
for (Termek termek : dragaTermekek) {
dragaKategoria.addTermek(termek);
}
}
}
Figyeljük meg, hogy a menedzselt entitás példányokat (amit tranzakción belül találunk meg query-vel, vagy most persist-áltunk frissen) nem kell explicit módon visszamenteni, tranzakció végén automatikusan DB-be íródnak a memóriabeli változások.
Meghívás a WebshopController
-ből:
@Autowired
KategoriaService kategoriaService;
...
// 5.b feladat
@RequestMapping(value = "/dragaTermekbeAtsorol", method = {
RequestMethod.POST, RequestMethod.GET })
private String dragaTermekbeAtsorol() {
// TODO
kategoriaService.createDragaJatekokEsAtsorol(8000.0);
return "redirect:/";
}
Böngészőben a gomb megnyomása után látszódik a Drága játékok kategória tartalma
A dao
package-be új interfész, KategoriaRepository
néven, a TermekRepository
mintájára (a Custom-os leszármazás nem kell, mert nem lesznek custom lekérdezéseink) egy metódussal:
public interface KategoriaRepository extends JpaRepository<Kategoria, Long>{
List<Kategoria> findByNev(String nev);
}
Ezután a KategoriaService
így egyszerűsödik le:
@Service
public class KategoriaService {
...
@Autowired
KategoriaRepository kategoriaRepository;
@Transactional
public void createDragaJatekokEsAtsorol(double arLimit){
...
List<Kategoria> resultList = kategoriaRepository.findByNev(nev);
...
}
}
Hívd meg a JPA-ból a FizetesModLetrehozasa nevű tárolt eljárást, mely új fizetési mód rögzítésére szolgál, és visszaadja az új rekord azonosítóját!
-
SQL Server használata esetén az SQL Server Management Studioban ellenőrizzük, hogy az adatbázis tartalmazza-e a FizetesModLetrehozasa nevű tárolt eljárást!
-
Ha nem, akkor nyisd meg a projekt gyökerében található CreateSP.sql nevű fájlt, és a tartalmát futtasd le a Management Studioban!
Megoldás
A FizetesMod
entitáson megtaláljuk az alábbi annotációt. Vessük össze a tárolt eljárást definiáló kóddal (CreateSP.sql) a változó neveket!
@NamedStoredProcedureQueries({
@NamedStoredProcedureQuery(name = "fizModSP",
procedureName = "FizetesModLetrehozasa",
parameters = {
@StoredProcedureParameter(mode = ParameterMode.IN, name = "fmod", type = String.class),
@StoredProcedureParameter(mode = ParameterMode.IN, name = "hatarido", type = BigDecimal.class)
})
})
public class Fizetesmod implements Serializable {
...
A named stored procedure query meghívható Spring Data repositoryból (dao
package-en New Interface ... / FizetesmodRepository):
public interface FizetesmodRepository extends JpaRepository<Fizetesmod, Long> {
@Procedure(name="fizModSP")
void ujFizetesmod(@Param("fmod") String nev, @Param("hatarido") BigDecimal hatarido);
}
Spring Data nélkül így menne, EntityManager
-en keresztül, erre valószínűleg már nem lesz idő:
@Service
public class FizetesmodService {
@PersistenceContext
private EntityManager em;
public void createUjFizetesMod(Fizetesmod fizetesMod){
StoredProcedureQuery sp = em.createNamedStoredProcedureQuery("fizModSP");
sp.setParameter("fmod", fizetesMod.getMod());
sp.setParameter("hatarido", fizetesMod.getHatarido());
sp.execute();
}
}
A webrétegbeli meghívás:
- Injektáljuk a
WebshopController
-be aFizetesmodRepository
interfészt:
@Autowired
FizetesmodRepository fizetesmodRepository;
- A WebshopController utolsó TODO-jánál hívjuk meg
fizetesmodRepository.ujFizetesmod(fizetesmod.getMod(), fizetesmod.getHatarido());
- A
Fizetesmod
entitáshatarido
ésmod
tagváltozóin validációs constraint-eket találunk. Ezek az annotációk a Bean Validation API részei, amivel a webes rétegben használt Spring MVC, de a JPA és integrálódik, így a webrétegbeli és adatrétegbeli validáció konzisztens módon, redundanciamentesen definiálható.
@NotNull
private BigDecimal hatarido;
@Column(name="MOD")
@NotEmpty
private String mod;