szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet elméleti háttér 2.1. a...

42
Szakdolgozat Miskolci Egyetem „MEAN” fejlesztési technológia alkalmazása kémiai adatbázisokban Készítette: Musatics Gilbert programtervező informatikus szak Témavezető: Dr. Nehéz Károly Miskolc, 2018

Upload: others

Post on 03-Jun-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

Szakdolgozat

Miskolci Egyetem

„MEAN” fejlesztési technológia alkalmazásakémiai adatbázisokban

Készítette:

Musatics Gilbert

programtervező informatikus szak

Témavezető:

Dr. Nehéz Károly

Miskolc, 2018

Page 2: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

Miskolci EgyetemGépészmérnöki és Informatikai KarAlkalmazott Matematikai Tanszék Szám:

Szakdolgozat Feladat

Musatics Gilbert (JW28VF) programtervező informatikus jelölt részére.

A szakdolgozat tárgyköre: Alkalmazásfejlesztés - Szoftvertechnológia

A szakdolgozat címe: „MEAN” fejlesztési technológia alkalmazása kémiai adatbázi-sokban

A feladat részletezése:(1) A szakirodalom alapján ismerje meg az úgynevezett MEAN (Mongodb, ExpressJS,Angular, NodeJS) technológiát és mutassa be előnyeit.(2) Készítsen egy keretrendszert, amely alkalmas az alábbi informatikai rendszerekbenmegismert alapfunkciók támogatására: felhasználó menedzsment, REST API, JWT,authorizáció.(3) Készítsen kémiai folyóiratok tárolásának támogatására alkalmas megoldást.(4) Dokumentálja munkáját a Szakdolgozatban.

Témavezető: Dr. Nehéz Károly egyetemi docens

Konzulens: Dr. Nehéz Károly egyetemi docens

A feladat kiadásának ideje:

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .szakfelelős

2

Page 3: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

Eredetiségi Nyilatkozat

Alulírott Musatics Gilbert; Neptun-kód: JW28VF a Miskolci Egyetem Gépészmér-nöki és Informatikai Karának végzős programtervező informatikus szakos hallgatójaezennel büntetőjogi és fegyelmi felelősségem tudatában nyilatkozom és aláírásommaligazolom, hogy „MEAN” fejlesztési technológia alkalmazása kémiai adatbázisokban cí-mű szakdolgozatom saját, önálló munkám; az abban hivatkozott szakirodalom felhasz-nálása a forráskezelés szabályai szerint történt.

Tudomásul veszem, hogy szakdolgozat esetén plágiumnak számít:

• szószerinti idézet közlése idézőjel és hivatkozás megjelölése nélkül;

• tartalmi idézet hivatkozás megjelölése nélkül;

• más publikált gondolatainak saját gondolatként való feltüntetése.

Alulírott kijelentem, hogy a plágium fogalmát megismertem, és tudomásul veszem,hogy plágium esetén szakdolgozatom visszautasításra kerül.

Miskolc, . . . . . . . . . . . .év . . . . . . . . . . . .hó . . . . . . . . . . . .nap

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Hallgató

3

Page 4: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

1.szükséges (módosítás külön lapon)

A szakdolgozat feladat módosításanem szükséges

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .dátum témavezető(k)

2. A feladat kidolgozását ellenőriztem:

témavezető (dátum, aláírás): konzulens (dátum, aláírás):. . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . .

3. A szakdolgozat beadható:

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .dátum témavezető(k)

4. A szakdolgozat . . . . . . . . . . . . . . . . . . . szövegoldalt. . . . . . . . . . . . . . . . . . . program protokollt (listát, felhasználói leírást). . . . . . . . . . . . . . . . . . . elektronikus adathordozót (részletezve). . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . egyéb mellékletet (részletezve). . . . . . . . . . . . . . . . . . .

tartalmaz.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

dátum témavezető(k)5.

bocsáthatóA szakdolgozat bírálatra

nem bocsátható

A bíráló neve: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .dátum szakfelelős

6. A szakdolgozat osztályzataa témavezető javaslata: . . . . . . . . . . . . . . . .a bíráló javaslata: . . . . . . . . . . . . . . . .a szakdolgozat végleges eredménye: . . . . . . . . . . . . . . . .

Miskolc, . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .a Záróvizsga Bizottság Elnöke

4

Page 5: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

Tartalomjegyzék

1. Bevezetés 6

2. Elméleti háttér 72.1. A fejlesztés menete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72.2. A használt technológiák . . . . . . . . . . . . . . . . . . . . . . . . . . 72.3. A projekt struktúrája . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82.4. Angular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2.4.1. Komponensek . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92.4.2. Routing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102.4.3. Modulok . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112.4.4. Függőség injektálás . . . . . . . . . . . . . . . . . . . . . . . . . 112.4.5. Beépített direktívák, adatkötés . . . . . . . . . . . . . . . . . . 12

2.5. Az üzleti logika implementációja . . . . . . . . . . . . . . . . . . . . . . 132.5.1. Absztrakció . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132.5.2. Felhasználók regisztrálása és a szerepkörök . . . . . . . . . . . . 142.5.3. Bejelentkezés és token alapú azonosítás . . . . . . . . . . . . . . 162.5.4. A szerveroldal . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172.5.5. MongoDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192.5.6. Az algaForm struktúra . . . . . . . . . . . . . . . . . . . . . . . 212.5.7. A struktúra frissítése . . . . . . . . . . . . . . . . . . . . . . . . 222.5.8. A typeahead implementálása . . . . . . . . . . . . . . . . . . . . 242.5.9. Formmanipulálás . . . . . . . . . . . . . . . . . . . . . . . . . . 252.5.10. Dokumentumok mentése, keresése, szerkesztése és törlése . . . . 272.5.11. Dokumentumok betöltése fájlból . . . . . . . . . . . . . . . . . 29

2.6. A webalkalmazás kinézete és használata . . . . . . . . . . . . . . . . . . 31

3. Összefoglalás 40

Irodalomjegyzék 41

Adathordozó használati útmutató 42

5

Page 6: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

1. fejezet

Bevezetés

Az informatika folyamatosan és gyorsan fejlődő tudomány. Minden évben jelentős elő-relépés történik hardveres és szoftveres téren egyaránt. Míg a hardver területen főkénta processzorok, a videókártyák és a mobileszközök teljesítményének növekedése látszik,addig szoftveres területen a szoftvertechnológiák és a programnyelvek próbálnak lépésttartani a modern kor elvárásaival.

A változások miatt a kezdő programozónak érdemes az új és fejlődő programozásinyelvekkel és az új technológiákkal is megismerkednie az alapismeretek megszerzéseután. A szakdolgozat célja, hogy egy algák adatait tároló és kezelő webalkalmazásfejlesztésén keresztül bemutassam a MEAN stackkel való munkát (stack itt: szoftver-fejlesztési komponensek együttese, amikkel egy szoftver elkészíthető, nem igényel tá-mogató alkalmazásokat), azon belül is hangsúlyt fektetve a feltörekvő és folyamatosanfejlődő JavaScript keretrendszerre, az Angularra.

A webalkalmazás a Miskolci Egyetem Kémiai Intézete számára készült el a „Straté-giai K+F műhelyek kiválósága” tárgyú, GINOP-2.3.2-15-2016-00058 azonosító számúprojekt keretein belül. Az oldalon lehetőség lesz olyan tudományos cikkek feldolgozá-sára és rendszerezésére, amelyek algák tenyésztési körülményeivel és az általuk termeltanyagokkal, valamint algák elfogyasztásának állatokra gyakorolt hatásával foglalkoz-nak. A fejlesztés során folyamatosan alkalmazkodni kellett az új elvárásokhoz, az ebbőlfakadó nehézségek és a megoldás szemléltetése miatt röviden a fejlesztés menetéről isszó lesz, a szoftverfejlesztésnél használt prototípusos életciklus-modell leírását előtérbehelyezve.

A szakdolgozat szerkezetileg a következőképpen épül fel: egy rövidebb fejezetbenaz imént említett fejlesztési modell kifejtése található, ezt követi a MEAN és az infor-matikai rendszer bemutatása párhuzamosan, az alapoktól leírva a fejlesztés lépéseit. Atartalmi részt a weboldal által nyújtott szolgáltatások rövid felsorolása zárja, mindentképpel illusztrálva.

6

Page 7: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2. fejezet

Elméleti háttér

2.1. A fejlesztés meneteAhogy az a bevezetésben olvasható, a szakdolgozathoz készített webalkalmazást erede-tileg a Kémiai Intézet igényelte. Az ott végzett kutatások körülményeit, az algák adataités a vizsgálatok eredményeit ezelőtt egy megosztott Excel táblázatban tárolták, viszontennek a módszernek vannak hátrányai. A táblázat a rengeteg tárolt információ miattnehezen átlátható. A dokumentumok felvitele a komplex adatstruktúra miatt körülmé-nyes. Az adatok visszakeresése is nehéz, lassú. Az Excel alapú adattárolás problémáia növekvő adatmennyiséggel egyre gyakrabban előkerültek, ezért a kutatók egy olyanrendszert kértek az Informatikai Intézet munkatársaitól, amiben könnyen tudnak ada-tokat felvinni és lekérdezni. A rendszer az Alga Database nevet kapta.

A fejlesztés menete a prototípusos életciklus-modellre illeszkedik leginkább. Egyrendszer fejlesztésének életciklusa alatt a projekt egészét értjük, kezdve a követelmé-nyek feltárásától, a dizájnon és programozáson keresztül a tesztelésig és karbantartásig.[1] A prototípusos fejlesztés során nagy hangsúlyt kellett fektetni a kutatók folyamato-san változó igényeire, mivel a kezdeti kérések túl homályosak, nagy területet lefedőekvoltak az informatikai tapasztalatuk hiánya miatt. Minden rövid implementációs fá-zis végén a rendszert néhány új működő funkcióval tesztelték, majd visszajelzéseketküldtek aszerint, hogy dizájn és használhatóság szempontjából mennyire elégedettek,milyen hibákat tapasztaltak és milyen irányba folytatódjon a fejlesztés. [2]

A kérésekből mindig ki kellett szűrni a megvalósítható elemeket, például az adatfel-vitelnél egy algákról szóló tudományos cikk és a korábbi Excel táblázat alapján kelletteldönteni, hogy az egyes mezők milyen formában kerüljenek be a webalkalmazás formkitöltő felületére. Miután elkészült a prototípus és végbementek a tesztek, a megbeszé-lésen kiderült, hogy az implementálás néhány apró rész kivételével jól sikerült, majd atovábbi funkcionális kérésekre is gyorsan lehetett reagálni.

2.2. A használt technológiákA továbbiakban arról lesz szó, miként lehet egy webalkalmazást fejleszteni a MEANstack-kel, de először mindenképp meg kell említeni, milyen technológiák segítségévelkészült el az Alga Database.

Az első és legfontosabb maga a MEAN stack. A MEAN egy mozaikszó, négy Ja-vaScript alapú technológiát foglal magában: a MongoDB-t, az ExpressJS-t, az Angulartés a NodeJS-t. A MongoDB egy NoSQL adatbázis szoftver, ami JSON fájlokkal kreált

7

Page 8: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.3. A projekt struktúrája

gyűjtemények segítségével valósítja meg a gyors olvasást és írást, saját lekérdező nyelvethasznál, ami eltér az SQL-féle lekérdezésektől és erősen hagyatkozik a mezőindexelésre.Az Angular (amiből a weboldalhoz a 4-es verziót használtam) egy JavaScript keret-rendszer, ami magas szintű eszközöket biztosít dinamikus webalkalmazások fejlesztés-hez. A NodeJS webszerverek létrehozásához használható aszinkron, eseményvezéreltkeretrendszer. Az ExpressJS pedig egy NodeJS feletti keretrendszer, ami főként arouting (szerver felé közvetített kérések irányítása) egyszerűsítését teszi lehetővé.

A fejlesztés során felmerült az igény csomagok használatára (pl. a kereső kompo-nens az ngx-datatable csomagból származik), ezeket a NodeJS csomagtelepítőjével,az npm-mel lehetett egyszerűen telepíteni és kezelni. Végül az utolsó említésre méltóhasznált eszköz a Gulp, amivel a fejlesztés során előkerülő rutinmunkák(szerver elindí-tás, fordítási munkák, stb.) automatizálhatók.

2.3. A projekt struktúrájaA webalkalmazás komplex könyvtárstruktúrával rendelkezik. Ebben a fejezetben rövidleírás következik arról, melyik fájl mire szolgál a programban.

- .vscode: Mivel a programot Visual Studio Code szerkesztővel írtam, az ahhoztartozó konfigurációs fájlok itt tárolódnak. Külön megemlítendő a launch.jsonfájl, amiben a debugoláshoz található plusz információ a VSCode számára.

- dump: Ebben a mappában találhatók az adatbázis visszaállítására szolgáló fájlokarra az esetre, ha valamilyen okból nem sikerült betölteni azokat a szerverről.

- e2e: Itt end-to-end tesztekhez (teljes rendszertesztek backend tekintetben) talál-hatók konfigurációs fájlok.

- src: Itt található maga a program, ami a szakdolgozathoz készült. A későbbifejezetekben részletesen szó lesz a tartalmáról.

- .angular-cli.json: Az Angular parancssoros interfészéhez tartozó konfigurációsfájlja. Itt vannak megadva az alkalmazás indításához szükséges információk: a be-lépési pont (main.ts), a főoldal (index.html), a külső stíluslapok és JavaScriptfájlok, valamint a tesztekhez szükséges fájlok elérési útjai és egyéb információk.

- .env : Környezeti változók gyűjteménye.

- .gitignore: Itt találhatók azok a könyvtárak/fájlok, amiket a Git commitolás ese-tén figyelmen kívül hagy, akár a mérete, akár egyéb tényezők miatt. Ezeket különlokálisan kell importálni/generálni.

- README.md : Itt egyrészt a szerver és kliens elindításához szükséges parancsok,másrészt a programozás során újrahasználható technikák vannak felsorolva.

- gulpfile.js : Az előző fejezetben említett Gulp taszklistája található itt.

- karma.conf.js.: Egy másik tesztrendszer, a Karma konfigurációs fájlja.

- package-lock.json: Ez a fájl tárolja az összes csomagot, amit npm-mel letöltöttünkés hozzácsatoltunk a projekthez. Ez a fájl commitolódik a node_modules helyett,adatforgalom megtakarítás miatt.

8

Page 9: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.4. Angular

- package.json: Ebben a fájlban találhatók a ténylegesen használt csomagok neveés verziószáma.

- protractor.conf.js : Szintén az e2e tesztekhez szükséges fájl.

- proxy.conf.json: Itt definiálhatjuk, hogy a szerverhívások milyen portokra kerül-jenek alapértelmezetten.

- tsconfig.json és tslint.js : Mindkét fájl a TypeScript (szintaktikai kiegészítése aJavaScriptnek) számára szolgál konfigurációs fájlként.

Ezután bele is nézhetünk az src mappába és elkezdhetjük felépíteni a programot.

2.4. Angular

2.4.1. Komponensek

Mint egy átlagos weboldalnál, az Alga Database-nél is az index.html a kezdőoldal, amiinduláskor betöltődik. A felépítése azonban jelentősen eltér. Miután a head szekcióbanmegadtuk a megfelelő metaadatokat (karakterkészlet, oldalcím, nézetbeállítás, helyicache kikapcsolása), a body részben csak egy ismeretlen tag és azon belül egy töltéstszolgáló tag található. A töltési mechanizmus az src/assets/sass/_app-base.scssfájlban található: amíg be nem töltődik az eredeti tag tartalma, addig egy forgó körtanimál folyamatosan.

Az eredeti tag az Angular újítása, a komponens segítségével lett definiálva. Egykomponens tipikusan 3 elemből áll (habár majd láthatjuk, hogy ez gyakran változik):a html kódból, ami a definiáló tagek közé töltődik, egy css stíluslaphoz, ami kompo-nensenként egyedi, valamint egy TypeScript fájlból, ahol az üzleti logika található.Ahhoz, hogy egy komponenst létrehozzunk, szükséges, hogy az utóbbi állománybandefiniáljunk egy Component dekorátort. Egy dekorátor a következőképpen néz ki:

1 import { Component } from ’@angular/core’;23 @Component ({4 selector: ’app -root’,5 templateUrl: ’./app.component.html’,6 styleUrls: [’./app.component.css’]7 })8 export class AppComponent {9 }

Komponens példa

Az első sorban beimportáljuk a Component-et, hogy azzal utána létrehozzuk a de-korátort. Itt a következő metaadatokat adjuk meg:

- selector: a tagnév, amivel hivatkozhatunk a komponensre a html-en belül.

- templateUrl: a komponenshez tartozó html fájl elérési útja.

- styleUrls: a komponenshez tartozó stíluslap(ok) elérési útja(i). (Megjegyzés:az Alga Database nem használja ezt a megoldást, ehelyett scss preprocesszo-ros stíluslapokat használ, amik az src/assets könyvtárban találhatóak és az.angular-cli.json fájlon keresztül tölti be őket az Angular.)

9

Page 10: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.4. Angular

Ezeken kívül más metaadatokat is megadhatunk, például a stílust (styles) és ahtml sablont (template) helyben is leírhatjuk. [3]

2.4.2. Routing

Az app.component.html fájlt megnyitva egy szimpla router-outlet taget találunk.Routing során a weboldalon látogatni kívánt url-ekhez hozzárendeljük a hozzá tar-tozó oldalakat, egyfajta ösvényrendszert kialakítva. Az Angular a routing segítségéveltámogatja az egyoldalas applikációk (SPA-Single Page Application) fejlesztését, a kü-lönböző komponensek így aszinkron módon töltődhetnek be a router-outlet tagekáltal meghatározott területre.

Ahhoz, hogy a routingot használhassuk és konfigurálhassuk, először be kell im-portálnunk a RouterModule-t (ez az app.module.ts-ben található, amiről a követ-kező fejezetben szó lesz), valamint létrehozunk egy route fájlt is: app.routes.ts.Ez utóbbiban az Angular routerén kívül be kell importálni a használni kívánt kül-ső route fájlokat, amennyiben bővebb elágaztatásra van szükség (itt: LoginRoutes ésDashboardRoutes), valamint azokat a komponenseket, amiket közvetlenül el szeretnénkérni (itt: LoginComponent). Ezután pedig megadhatjuk a route-okat:

1 export const routes: Routes = [2 ... LoginRoutes ,3 ... DashboardRoutes ,4 { path: ’**’, component: LoginComponent }5 ];

Routing

Itt a következők figyelhetők meg:

- a route konstans tömböt exportáljuk, ez ugyancsak az app.module.ts-ből leszelérhető.

- a továbbvezető Login és Dashboard route-ok előtt három pont található. Ez egyúgynevezett spread operátor, ami megengedi, hogy több elemet illesszünk beegy helyre. Ahogy pl. az src/app/dashboard/document/document.routes.ts-ben látható, ott két route van megadva. A spread operátornak köszönhetőendinamikusan változtatható, mennyi route-ot használunk egy helyen.

- itt már látható egy közvetlen route leírása: abban esetben, ha olyan url-t írunkbe, amire a router nem talál illeszkedő mintát, akkor a loginképernyőre kerülünk.

A közvetlen route leírásnál az illesztési mintán és a betöltendő komponensen kívülmás paramétereket is megadhatunk, az Alga Database szempontjából a hitelesítésrőlszóló fejezetben szó lesz a canActivate-ről és a data-ról, amik hitelesítéshez szüksé-gesek.

A document.routes.ts első path mintájában látszik, hogy bővebb elérési út ismegadható, valamint paraméter is átadható, jelen esetben egy dokumentum azonosí-tója, amivel ugyancsak betölthető a Document komponens (az üzleti logikáról későbbbővebb leírás található).

Nem összetévesztendő az Angular routere az ExpressJS routerével, ami a szerver-oldalon irányítja a kéréseket (erről a szerverrel foglalkozó fejezetben található többinformáció).

10

Page 11: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.4. Angular

2.4.3. Modulok

Amikor az applikáció elindul, a belépési ponton keresztül (main.ts) betöltődik (boo-tol) az AppModule. Az Angularban a modulok felelősek a komponensek betöltéséért ésmás komponensekkel való összekapcsolásáért, éppen ezért minden komponensnek tar-toznia kell egy modulhoz. A modulok felépítése hasonló a komponensek megadásához,ahogy az AppModule-ban is látszik: importálhatunk (a deklarálni kívánt komponense-ket és a betöltendő modulokat), írhatunk metódusokat, valamint itt is megjelenik egydekorátor: az @NgModule.

1 @NgModule ({2 declarations: [3 AppComponent ,4 UserAdminComponent5 ],6 imports: [7 BrowserModule ,8 FormsModule ,9 ReactiveFormsModule ,

10 HttpModule ,11 RouterModule.forRoot(routes),12 LoginModule ,13 DashboardModule ,14 ],15 providers: [ {16 provide: AuthHttp ,17 useFactory: authHttpServiceFactory ,18 deps: [Http , RequestOptions]19 }],20 bootstrap: [AppComponent]21 })

Modul példa

Ez a dekorátor a következő információkat tartalmazza:

- declarations: azok a komponensek kerülnek ide, amik a modulhoz tartoznak.

- imports: azoknak a moduloknak a gyűjteménye, amiknek az exportált kompo-nenseit elérhetővé akarjuk tenni ezen modul komponensei számára.

- providers: itt azokat az objektumokat és változókat adjuk meg, amiket más mo-dulokból, valamint a saját komponens service részéből szeretnénk használni. Erreaz Angular „függőség injektálás” (DI-Dependency Injection) néven hivatkozik.

- bootstrap: Azok a komponensek, amiket a modul bootol, amikor a modul be-töltődik.

Természetesen itt is megadhatók más adatok is, amik közül fontos az Alga Databaseszámára az exports, itt azok a komponensek adhatók meg, amiket külső modulokszámára is elérhetővé szeretnénk tenni. [4]

2.4.4. Függőség injektálás

A megosztani kívánt metódusokat, változókat úgynevezett szolgáltatásként (service)adjuk át a moduloknak. Ezeket jórészt külön fájlba gyűjtjük ki és egyben küldjük

11

Page 12: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.4. Angular

az @NgModule providers részére (kivétel például az authHttpServiceFactory azapp.module.ts-ben). Amikor az ilyen módon előkészített szolgáltatásokat használjuk,úgymond beinjektáljuk őket függőségként. Ez azt jelenti, hogy nem példányosítunkhasználat előtt, felelősséget vállalva arra, hogy a használt osztályban történt változá-sokkal a használó osztályt is változtatni kell, hanem mi csak felhasználjuk a szolgáltatásáltal nyújtott lehetőségeket.

Jó példa erre a UserRoles szolgáltatás, amit az dashboard.module.ts-ben igény-lünk, majd a kívánt komponensekben átadunk konstruktor paraméterként (pl. ilyen adocument.component.ts konstruktora: vegyük észre, hogy nem történik példányosí-tás). Ez egy metódust biztosít, ami megvizsgálja, hogy a jelenlegi felhasználó szerepköremegtalálható-e a paraméterként megadott szerepkörök tömbjében. A visszakapott lo-gikai értéket aztán a komponensek felhasználják: amennyiben a felhasználó rendelkezika szükséges jogokkal, akkor megjelenik a bizonyos szerepkörhöz tartozó funkció (egyéb-ként elrejti egy *ngIf direktíva, lásd következő fejezet). Az injektálható osztályokatmeg kell jelölni az osztálydefiníció elé írt @Injectable() jelzővel.

2.4.5. Beépített direktívák, adatkötés

Az Angular támogatja a dinamikus html generálását és ezt a beépített direktíváin ke-resztül biztosítja. Direktívák segítségével megváltoztatható a html kód és a tagekfelépítése is. Direktívának számít a már bemutatott komponens is. Ezen felül léteznekattribútum direktívák, amik a tagek, komponensek, vagy akár más direktívák működé-sét is befolyásolhatják, valamint strukturális direktívák, amik a html tagjeinek számátés tartalmát változtatják meg. Az Angular beépített direktívái egy * prefixszel vannakellátva, ami egy komplexebb, sablonnal megoldott struktúrát egyszerűsít.

1 <small *ngIf="!algaForm.get(’title ’).valid" class="text -danger">Document title is required (minimum 5 characters).</small >

*ngIf

Az *ngIf direktíva azt befolyásolja, hogy egy elem megjelenjen-e, vagy sem. Ab-ban az esetben, ha az idézőjelek közt megadott kifejezés hamis, az elem (és egyben agyerekelemek) be sem kerülnek az Angular által fordított dinamikus struktúrába, ígynem jelennek meg (másik megoldás lehet, amikor az ellenőrzés után csak az elem stílu-sát változtatjuk meg láthatatlanra, ez memóriaigényesebb összetett struktúrák esetén,viszont nem kell a komponenst újratölteni, ha a feltételbeli kifejezés értéke igazra vál-tozik). A példában a hibaüzenet csak akkor jelenik meg, ha a hozzá tartozó formelemnem megy át a validáción.

Az *ngFor direktíva segítségével egy elemet dinamikusan többszörözhetünk. A mű-ködése hasonló egy for ciklushoz: megadunk egy tömböt/listát, valamint egy indexvál-tozót, majd az *ngFor végigiterál rajta és annyiszor generálja le az elemet, amekkoraa tömb/lista elemszáma. Az alsó példában látszik, hogy az ngFor többre is képes. Azindexváltozó ugyanis megkapja a lista soron következő elemét és azt ki is írja a dup-la kapcsos zárójelekkel megadott helyekre. Ezt a módszert adatkötésnek nevezzük. Amódszer dinamikus, így ha a listában változás történik, akkor automatikusan változika html-ben is a megfelelő bejegyzés.

12

Page 13: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

1 <tr class="even -odd" *ngFor="let item of generateArray(doc)" style="width :50%">

2 <td>3 <div class="td_head">{{item.key}}</div>4 </td>5 <td>6 <div>{{item.value}}</div>7 </td>8 </tr>

*ngFor

A webalkalmazás szempontjából legfontosabb direktíva az ngForm. Ez az előző di-rektívákkal ellentétben nem beépített, a használatához importálni kell a FormsModulemodult az @angular/forms-ból. Ezután viszont nem kell külön jelölni a HTML-ben,mivel minden form típusú elemet felülír. A direktíva készít egy FormGroup példányt,amivel képesek vagyunk egy JavaScript metódusokkal könnyen és dinamikusan kezelhe-tő struktúrát létrehozni. A FormsModule és a hozzá tartozó FormBuilder működésérőlés használatáról az üzleti logika algaForm-mal foglalkozó fejezetében lesz szó.

1 <form #f="ngForm" (ngSubmit)="f.form.valid && addUser(f)" novalidate >2 <div class="form -content">3 <div class="form -group">4 <label >E-mail</label>5 <input type="text" class="form -control input -underline input -lg"

placeholder="Email" name="email" #email="ngModel" ngModelrequired >

6 <small *ngIf="f.submitted && !email.valid" class="text -danger">Email is required </small>

7 </div>8 .9 .

10 .

*ngForm

A form-ra hivatkozást hozhatunk létre #name="ngForm" alakban. A form beküldéseaz (ngSubmit) segítségével működik, ezzel megadhatunk egyéb eseményeket is, amik-nek teljesülnie kell a beküldés előtt. A novalidate kulcsszó megadása után a form nemkerül validálásra. Az ngModel required jelentése az, hogy az adott mező kötelezőenkitöltendő.

Bár az Alga Database nem használja, megemlítendő még az *ngSwitch, amivela feltételben megadott kifejezés értéke szerint döntjük el, melyik *ngSwitchCase-zelellátott elem jelenjen meg (természetesen az *ngSwitch elem belső gyerekelemének kelllennie).

2.5. Az üzleti logika implementációja

2.5.1. Absztrakció

Most már tisztában vagyunk a program alapjának, az Angularnak a működésével (akésőbbiekben még előfordulhatnak új elemek, amik ott helyben lesznek kifejtve), ígybelekezdhetünk az üzleti logikának és implementációjának kielemzésébe.

13

Page 14: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

A Kémiai Intézet egy olyan programot kért, amiben lehetséges algák és a velükvégzett kutatások adatainak felvitele, valamint már felvitt adatok szabad visszakereséseés módosítása. Mivel vannak előre elkészített XML fájljaik, amikben dokumentumokadatait tárolják, így a fájlokon keresztüli automatikus adatfeltöltést is meg kell oldani.Ezen felül két felhasználótípussal akarnak dolgozni, a szerkesztővel és az elemzővel. Aszerkesztő képes az adatmanipulációra (felvitel, törlés, módosítás), míg az elemző csakvisszakeresheti az adatokat. A dokumentumok szerkezete a következőképpen néz ki:

- Az adatokat tudományos cikkekből gyűjtötték ki, ezeknek le kell tárolni a cí-mét, kiadási évét, a DOI (Digital Object Identifier) és url azonosítóját, azt afolyóiratot, amiben megjelent a cikk, a cikk íróit és egyéb információkat.

- A vizsgált algá(k)nak tárolni kell a faját, alfaját, a tesztelés fizikai körülményeit,stb.

- Egy külön szekcióban tárolni kell a vizsgálat biológiai körülményeit és adminiszt-rációs információit.

- Végül le kell tárolni azt is, hogy milyen más algákkal lett keresztezve a vizsgá-lat(ok) során a vizsgált algafaj, ezeknek is külön-külön le kell jegyezni az adatait.

Ez informatikai megközelítésből egy komplex adatstruktúrát fed le, amiben vannaktöbbszörös beágyazások és olyan elemek is, amik többször szerepelhetnek (például akeresztezendő algák számát nem tudjuk előre). Ezért egy dinamikusan bővíthető struk-túrát kell létrehozni. A későbbiekben újabb kérések érkezhetnek a struktúra bővítésére,ezt rugalmas adatszerkezettel kell megvalósítani. Az adatmodell implementációjáról aMongoDB-vel foglalkozó fejezetben lesz szó.

Az XML dokumentumok feltöltésére és feldolgozására, valamint a keresés megoldá-sára egy-egy könyvtárat használunk, az X2JS-t és az ngx-datatable komponenst. Afelhasználótípusok kezelését hitelesítéssel végezzük, emellett létrehozunk egy harmadiktípust is, az adminisztrátort, aki a rendszer egészét képes kezelni, emellett pedig új fel-használókat is képes felvenni. Végül a bejelentkezést is meg kell oldani, ami token-alapúazonosítással történik.

2.5.2. Felhasználók regisztrálása és a szerepkörök

Egy weboldalon nagy lehet az elérhető funkciók száma. Nem mindig jó viszont az, habármelyik felhasználó hozzáférhet az összes funkcióhoz. Például a projekt esetében nemcélravezető az, ha olyan ember próbál dokumentumokat feltölteni, aki nem tartozik akutatók azon csoportjába, akik a kísérleteket leíró cikkeket olvassák és elemzik, mivelnehezebb lehet számára mind a cikk, mind a dokumentum feltöltő felület értelmezése.Ezért csoportokra kell bontani azon felhasználókat, akik egy kísérlet során hozzáférneka webes felülethez.

A Kémiai Intézet azt kérte, hogy két szerepkör legyen: a dokumentumokat feltöl-tő és szerkesztő editor, valamint egy szűkebb felhasználói réteg, a viewer, akik csakvisszakeresni tudják a felvitt adatokat, azon módosítani nem tudnak. Természetesenaz editor képes arra is, amire a viewer, hiszen ha egy már feltöltött dokumentumot kellmódosítania, akkor először ki kell azt keresnie.

Ahhoz, hogy ezt megvalósítsuk, először minden felhasználóhoz el kell tárolni, milyenszerepkörbe tartozik. Ezt az információt egy új felhasználó felvételénél adhatjuk meg.

14

Page 15: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

A regisztrációs felület a user-admin komponensben található. A html fájlban látható,hogy egy táblázatban vannak felsorolva a jelenlegi felhasználók és adataik az *ngFordirektívával végigiterálva a ts fájlból elért JSON állományon, valamint mindegyikükmellett szerepel egy törlés gomb, amivel az adataik eltávolíthatóak az adatbázisból.Ez alatt egy ngForm direktívával ellátott form található. Itt vannak: elérhetőségeket(email, telefonszám) tároló mezők; egy mező a jelszóhoz, amivel majd be tud lépni afelhasználó; egy department mező, ahol megadható, hogy melyik tanszék dolgozója afelhasználó; valamint a szerepkörök.

Amint az észrevehető, a két szerepkörön kívül a már említett admin is szerepelaz opciók között. A rendszerben kialakult hibák hatékony kiküszöbölése érdekében azadminok minden funkciót elérnek, amit az editor, ráadásul csak az admin képes elérnia user-admin komponenst, azaz ő tudja felvenni és törölni a felhasználókat.

Két módunk van arra, hogy a szerepek hatókörét érvényesíteni tudjuk: az egyikkomponens, míg a másik funkció szintű. Komponens szintű érvényesítésre példa auser-admin.routes.ts fájl. Látható, hogy egy route van megadva, ami a user-adminkomponensre vezet, valamint a Route paraméterek között szerepel egy canActivate ésegy data is. Az utóbbi szerepe egyértelmű: itt meg van adva egy roles változóban, hogymely szerepkörrel rendelkező felhasználók érhetik el a komponenst. A canActivate azAngular routerének egy beépített paramétere, ez megkapja az AuthGuard osztályt (azazonos nevű TypeScript fájlból), ami a hitelesítést végzi.

1 canActivate(route: ActivatedRouteSnapshot) {2 if (localStorage.getItem(’currentUser ’)) {3 let roles = route.data[’roles ’] as Array <string >;4 if (roles === undefined) {5 return true;6 }7 const jwtToken = JSON.parse(localStorage.getItem(’currentUser ’));8 const tokenPayload = decode(jwtToken.token);9 if (tokenPayload.user.role.includes(’admin’)) {

10 return true;11 }12 for (let role of roles) {13 if (tokenPayload.user.role.includes(role)) {14 return true;15 }16 }17 console.log(’Authorization required:’ + roles);18 this.router.navigate ([’/dashboard/invalidauth ’]);19 return false;20 }21 this.router.navigate ([’/’]);22 return false;23 }

Részlet az authguard.ts fájlból

Az osztályban levő canActivate metódusnak egy paramétere van, a route, amiaz ActivatedRouteSnapshot interfészen keresztül szerez magának értéket. Ez az ak-tuálisan elérni kívánt ösvényről tárol információt, nekünk tehát nem kell explicitenmegadni. A metódus egy vizsgálattal kezdődik: a weboldal minden használatakor lét-rejön helyileg egy localStorage tár, ami az aktuális használatról tárol információt.Jelen esetben ebben vizsgáljuk, hogy be van-e jelentkezve felhasználó (amennyibennincs bejelentkezve és manuálisan írja be az elérni kívánt ösvény url-jét, akkor a local-

15

Page 16: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

Storageben nem lesz eltárolva felhasználó, a feltételes blokk nem fut le, hanem helyettea router átnavigál a loginképernyőre). Ha bejutunk a feltételes blokkon belülre, akkorelőször a roles változóba lementődik (a komponens routejának data tagjából), melyszerepkörrel rendelkező felhasználók érhetik el a komponenst. Ha ez a lista üres, bárkielérheti. Ha nem üres, akkor token alapú hitelesítés következik (a token generálásról ésa szükségességéről szól a következő fejezet). Az előzőleg vizsgált aktuális felhasználóiadatok itt dekódolódnak a jwt-decode csomag metódusa segítségével, hogy vizsgál-ható formába kerüljön a kódolt információ. A felhasználó szerepkörei közt először aztnézzük, hogy megtalálható-e az admin, azt mindenképp továbbengedjük. Ha nem, ak-kor az átengedhető szerepkörökön végigiterálva megnézzük, a felhasználó rendelkezik-elegalább eggyel. Ha igen, továbbengedjük, ellenkező esetben a sikertelen hitelesítésikomponensre irányítjuk.

2.5.3. Bejelentkezés és token alapú azonosítás

Tokenek

A felhasználó számára nem kényelmes az, ha egy session (weboldal használati alkalom)során minden alkalommal azonosítania kell magát, ha egy szolgáltatást használni akar.Ezért érdemes valamilyen formában megjegyezni, hogyha egy felhasználó belépett -legalábbis egy session idejére. A felhasználónév-jelszó páros letárolása a felhasználóhelyi tárolójába (localStorage) nem jó megoldás biztonság szempontjából, mivel ezt azinformációt nem védi semmi, azaz adatlopással megszerezhetőek a belépési adatok. Amegoldást a tokenek nyújtják.

A token egy olyan kódolt adat, ami egy megfelelő metódus segítségével olyan infor-mációkra bontható szét, amik az azonosításhoz szükségesek. A token generálása és ke-zelése a jsonwebtoken csomag segítségével egyszerűen megoldható: mikor a felhasználóaz adataival bejelentkezett, az adatait tároló struktúrát átadjuk a jsonwebtoken signmetódusának egy mellékelt titkosító kulccsal együtt, ami aztán generál egy tokent. Eza token aztán letárolódik a localStorage-be és azonosítások alkalmával ezt a tokentbontja le a decode metódus (az authguard.ts-ben látható).

1 login = (req , res) => {2 this.model.findOne ({ email: req.body.email }, (err , user) => {3 if (!user) { return res.sendStatus (403); }4 user.comparePassword(req.body.password , (error , isMatch) => {5 if (! isMatch) { return res.sendStatus (403); }6 const token = jwt.sign({ user: user }, process.env.SECRET_TOKEN);7 res.status (200).json({ token: token });8 });9 });

10 }

Login a token segítségével

Maga a bejelentkezés csak abból áll, hogy a szervernek küldött információkból kike-ressük az emailt (email és jelszó párossal lehet belépni), azt pedig a felhasználói adat-bázisból próbáljuk kikeresni. Amennyiben találunk illeszkedő email címet, meghívjuka comparePassword metódust (lásd lentebb). Sikeres azonosítás után legenerálódik atoken és az visszakerül a frontendre. A fenti metódus a backenden fut, bővebben aNodeJS-sel és MongoDB-vel foglalkozó fejezetben lesz róla szó.

16

Page 17: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

Jelszótitkosítás

Hasonló megfontolásból (védeni kell a személyi adatokat a fejlesztőktől is) a jelszót nemszabad az adatbázisba sem eltárolni. Ugyan a szakdolgozat írásakor készült programesetében az admin veszi fel az új felhasználókat és ezáltal a jelszóhoz is hozzáférése van,de egy éles rendszerben biztosítani kell vagy azt, hogy szabadon lehessen regisztrálni,aztán az admin dönti el, hogy ad-e felhasználói jogot a regisztráló személynek, vagytovábbra is az admin regisztrál új felhasználókat egy default jelszóval, amit aztán a fel-használó megváltoztathat. Ettől az említett biztonsági réstől eltekintve biztosítva vana felhasználók jelszavainak biztonsága. Már magába az adatbázisba sem a regisztrálás-kor megadott jelszó kerül, hanem egy titkosított változata, amit a bcryptjs csomagbiztosít.

1 userSchema.pre(’save’, function(next) {2 const user = this;3 if (!user.isModified(’password ’)) { return next(); }4 bcrypt.genSalt (10, function(err , salt) {5 if (err) { return next(err); }6 bcrypt.hash(user.password , salt , function(error , hash) {7 if (error) { return next(error); }8 user.password = hash;9 next();

10 });11 });12 });

Titkosítás

A metódus a felhasználó adatbázisba lementése előtt hívódik meg (akkor is, hamódosítottuk az adatokat és nem új felhasználót hoztunk létre). Egy feltételben meg-vizsgájuk, hogy módosult-e a jelszó, amennyiben nem, további dolgunk nincs. Egyéb-ként generálunk egy véletlenszámot (salt), amit aztán a jelszó hashelésére használunk.Miután előállt a hash kód, ezt az adatot írjuk a felhasználó jelszavának helyére. A ké-sőbbiekben, mikor bejelentkezik a felhasználó, a bycriptjs összehasonlító metódusátalkalmazzuk (ez fut a comparePassword-ben is).

2.5.4. A szerveroldal

Kapcsolattartás a szerverrel

A korábban említett szolgáltatásoknak az injektálhatóságon kívül van egy másik hasz-nuk is: innen küldhetünk kéréseket(request) a szerver felé, amiket majd az feldolgoz.Ezt az úgynevezett Promise segítségével valósítjuk meg. A Promise aszinkron módonoldja meg a requestek teljesítését, tehát nem áll meg az oldal működése, amíg nemérkezik meg az információ a szerverről. A működése a következő kódrészletben látható.

Itt a newDocument a metódus, amelyik egy dokumentum szerverre feltöltését vég-zi (ez a dokumentum a data változóban van eltárolva). Ennek a visszatérési értéke aPromise függvény, ami "megígéri", hogy teljesíti a kérést, amit átadunk neki. A kérésjelen esetben egy POST HTTP metódus, amit az /api/doc route-ra (ez nem egyenlőaz Angular routing rendszerével) irányítunk, a dokumentumot elküldve. Ezután a Pro-mise megpróbálja felvenni a szerverrel a kapcsolatot, teljesíteni a kérést és esetlegesenvisszatérni a kért adatokkal (például egy GET metódus esetén mindenképpen). Ha si-kerül végrehajtani a kérést, akkor a res változóba kerülnek a visszatérési adatok, amit

17

Page 18: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

aztán feldolgozhatunk, ellenkező esetben az err változóban tárolódik el a sikertelenségoka (például a megfelelő hibakód).

1 newDocument(data) {2 return new Promise ((resolve , reject) => {3 this.authHttp.post(’/api/doc’, data)4 .map(res => res.json())5 .subscribe(res => {6 resolve(res);7 }, (err) => {8 reject(err);9 });

10 });11 }

Promise példa

NodeJS, mint szerver

A MEAN stacken belül összetartozó keretrendszerek a NodeJS és az ExpressJS. ANodeJS biztosítja az aszinkron, eseményvezérelt, alacsony szintű eszközöket a szerverfunkcióinak felépítéséhez, az ExpressJS pedig magas szintű szolgáltatásokat nyújt azMVC (Model-View-Controller minta), Request routing és egyéb szerverkészítési elemekegyszerű megvalósításához.

Az ExpressJS felállítása az src/api/app.ts fájlban található. Az Express applétrehozása egyszerű: az app változóban példányosítjuk az express()-t, ezután márhasználhatóak a metódusai. A use metódussal megadhatók azok a funkciók és szol-gáltatások, amiket használni fog: jelen esetben a bodyParser-t használjuk a fogadottJSON fájlok feldolgozására, a beépített static funkciót a statikus fájlok kezelésére, amorgan nevű csomagot programozás közben log fájlok készítésére, a jwt pedig az előzőfejezetben bemutatott jsonwebtoken-re utal, annak az inicializálása is itt megy vég-be. Ezt követően kezdődik a szerver indítása: rákapcsolódunk a MongoDB adatbázisra(erről részletesebben a MongoDB alfejezetben lesz szó) és amint sikerült a kapcsolódás(db.once), felállítjuk a route-okat, ami azt jelenti, hogy a routes.ts fájlt hozzákap-csoljuk az Expresshez. Végül a listen metódussal elindítjuk a szervert, innentől aport-on (a set metódussal megadotton) figyeli és szolgálja ki a szerver a beérkezőkéréseket.

Tehát már fut a szerver, így képes válaszolni a Promise-ok által benyújtott kéré-sekre. Viszont amíg a különböző kérések nincsenek a megfelelő kontrollerhez (MVCcontroller része) irányítva, addig csak sikertelenül tér vissza. Ahhoz, hogy ezt az irá-nyítást elvégezzük, szükség van a kérések routeolására. Az Express routing moduljánakmegvalósítása a routes.ts fájlban található.

Először felállítjuk a Routert, majd hozzákapcsoljuk a használni kívánt kontrollere-ket. Ezután pedig felsoroljuk az összes kéréstípust, amit le akarunk kezelni. Idézőjelekközt adjuk meg azt az útvonalat, amit a Promise keres, utána a HTTP metódus tí-pusát, majd azt a kontroller-metódus párost, ami a kérést kiszolgálja. Végül az egészleírást átadjuk az Expressnek a use metódussal.

18

Page 19: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

1 export default function setRoutes(app) {23 const router = express.Router ();45 const userCtrl = new UserCtrl ();6 const docCtrl = new DocumentCtrl ();7 const sensorDataCtrl = new SensorDataCtrl ();89 router.route(’/login’).post(userCtrl.login);

1011 router.route(’/users’).get(userCtrl.getAll);12 ...13 app.use(’/api’, router);14 }

Részlet a routes.ts fájlból

2.5.5. MongoDB

A Kémiai Intézet kutatóival való megbeszélések során kiderült, hogy szeretnék a rend-szert könnyen bővíthetővé tenni a bevihető adatokat illetően. Azt a rugalmasságot,hogy új adatmezőket, vagy esetlegesen akár új adatszekciókat is lehessen hozzáadni azadatstruktúrához és azt könnyen lehessen kezelni, a MongoDB biztosította, elsősorbanemiatt is a MEAN stackkel történt a fejlesztés.

A MongoDB egy dokumentum alapú, NoSQL adatbázis program. Dokumentumalapú alatt azt kell érteni, hogy JSON formátumú dokumentumokat tárol el (ez meg-feleltethető az SQL row-val) és nem várja el, hogy a mezők minden dokumentumbanmegegyezzenek. Lehet, hogy egy régebben eltárolt dokumentum még nem rendelkezikegy bizonyos mezővel, ez nem okoz problémát, hogyha a fejlesztők felelősséget vállalnaka hiányok kezelésére. Ez pedig egyszerűen megoldható verziókontrollal vagy szkriptekalkalmazásával (erről egy későbbi fejezetben bővebben lesz szó). [5]

Modellek

Az Alga Database két adatstruktúrát különít el: a felhasználók és az algákkal vég-zett kutatások adatait. Ezek modelljei az src/api/models mappában találhatók. Amodellek alapján hozzuk létre a gyűjteményeket (ami az SQL table megfelelője). [6]

A lenti ábrán látható egy tipikus mongoose schema szerkezete. A mongoose csomaghasználatával definiáljuk a szerkezetet, majd belül felsoroljuk a használt adatmezőknevét és típusait. Az alga dokumentumok esetében ez az adatszekcióból áll (amit teljesobjektumként adunk át, nem külön mezőkre bontva), a létrehozó felhasználó nevéből, alétrehozás dátumából (aminek default értékül van megadva a létrehozáskor aktuális dá-tum), valamint a módosítások adatai: ki és mikor módosította a dokumentumot. Amintaz látható, ez egy tömb, azaz minden egyes módosítás látszik benne. Végül megadjuk,milyen néven érhető majd el az adatszerkezet. Ezen felül az adatok előkészítését végzőmetódusok is szerepelhetnek ebben a leírásban, mint ahogy azt a jelszótitkosításnálláthattuk.

19

Page 20: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

1 import * as mongoose from ’mongoose ’;23 const formSchema = new mongoose.Schema(4 {5 data: Object ,6 user: Object ,7 creationDate: { type: Date , default: Date.now },8 modifications: [9 {

10 user: String ,11 date: Date ,12 _id: false ,13 },14 ],15 },16 );1718 const Document = mongoose.model(’Document ’, formSchema);1920 export default Document;

Az alga dokumentum modellje

Lekérdezések

Ahhoz, hogy használhassuk a MongoDB funkcióit, először el kell indítani a szerverét.Ennek a leírása megtalálható a Readme.MD fájlban: parancssorból indítani kell a mon-god programot az elérési útjáról. Ez azért is fontos, mert ahogy az Express felállításánállátszik, a szerver csak akkor fog elindulni, ha a MongoDB szervere is fut és figyeli ahozzá irányuló kéréseket.

Az összes használt lekérdezés csoportosítva megtalálható az src/api/controllersmappában. Míg a base.ts alapvető, addig a document.ts és a user.ts a saját speci-fikus lekérdezéseit tartalmazza. A következőkben csak az alapvető lekérdezések kapnakmagyarázatot és azok közül is csak a base.ts-ben levők, mivel a user.ts login metó-dusa már korábban ki lett fejtve, a document.ts összetettebb lekérdezései külön feje-zetben lesznek tárgyalva, a MongoDB összes funkciójának részletes bemutatása pedignem célja a szakdolgozatnak.

A BaseCtrl osztály absztrakt, azaz típusa attól függ, milyen modell kezelésé-re lett meghívva (például a routes.ts fájlban látható az insert metódus, ami aBaseCtrl-hoz tartozik, viszont a DocumentCtrl a leszármazottja, amelyik típust adneki a document modell által).

Az SQL SELECT-jét felváltja a find() metódus. Alapértelmezett alakja a követ-kező: this.model.find({}). Ez kigyűjti az összes adatot az adott (itt: a megfelelőmodell) gyűjteményből. A kapcsos zárójelek között megadhatók JSON-höz hasonlóformátumú szűrő feltételek, például this.model.find({_id: 1}) visszaadja az 1-esid-jű dokumentumokat. A gyűjteménybe új dokumentumot az insert() metódussaltehetünk. Az aggregációs függvények is külön metódust kapnak, például a count()metódussal lehet egy gyűjtemény bizonyos tulajdonsággal rendelkező elemeit összeszá-molni. Frissíteni egy már adatbázisban levő elemet a findOneAndUpdate() metódussallehet, aminek az első paramétere a frissítendő dokumentum kulcseleme, a második pe-dig maga a frissítés, amit ugyancsak a JSON-szerű formátumban, kulcs-érték párokkal

20

Page 21: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

kell megadni. Az adatbázisból egy dokumentum törlése is hasonló módon történik: afindOneAndRemove() paraméterének megadott azonosítójú dokumentum törlődik.

2.5.6. Az algaForm struktúra

A továbbiakban az Alga Database legösszetettebb részéről, a Document komponensrőllesz szó. Ennek a komponensnek a funkciója a dokumentumkitöltő felület megjelení-tésének, működésének és dinamikusságának biztosítása, valamint a komplex algaFormmodell kezelése. A komponens működése több kis szakaszra bontható, ezért ezek különfejezetekben lesznek kifejtve.

A dokumentumok struktúrája, amit a szerveroldalon már csak data-ként tárolunkel, ebben a komponensben van definiálva. Maga a struktúra az Angular FormBuildermoduljával lett létrehozva, ami az áttekinthetőséget, a kezelést és az adatok validációjátis elősegíti. Megjegyzendő, hogy ez a modul valójában egy szintaktikai rövidítése aFormGroup, FormControl és FormArray moduloknak. [7]

1 this.algaForm = this._fb.group({2 title: [’’, [Validators.required , Validators.minLength (5)]],3 year: [’’, [Validators.required , Validators.pattern(’[0 -9]{4}’)]],4 journal: [’’],5 additionalInfo: [’’],6 doi: [’’],7 url: [’’],8 docType: [’article ’, Validators.required],9 inVivo: [false],

10 algae: this._fb.array([this.oneAlga ()]),11 bioInformations: this._fb.array([this.oneBioInformation ()]),12 authors: this._fb.array ([this._fb.group({13 name: [’’, Validators.required],14 department: [’’]15 })]),16 tables: this._fb.array ([this.oneTable ()]),17 });

Részlet az algaForm struktúrából

A fenti kódrészlet a 2.5.1. fejezetben látható lista első pontjának az implementálása.Szintaktikailag a következő módon áll össze egy mező: megadjuk a nevét, amivel hi-vatkozunk rá (például title), majd egy kettőspont után a típust (itt mindegyik adattömb szerkezetű, tehát szögletes zárójelekkel megadott). Itt default értéket is adha-tunk a megfelelő adatoknak a félidézőjelek közé írt szöveggel sztringek esetén (példáula docType default „article” értéke), vagy a típusnak megfelelő szintaktikával (példáulaz inVivo logikai default értéke). Ugyanitt a validátorok is beállíthatók a Validatorosztály használatával: a required feltétel megadása kötelezi a felhasználót, hogy ki-töltse a megfelelő mezőt, a minLength az adat hosszára vonatkozó megkötés, a patternsegítségével reguláris kifejezéseket lehet megadni validációs feltételnek.

A vizsgált folyóirat alapadatai után a különböző alszekciók mezői vannak definiálva,mindegyik külön formBuilder metódus segítségével létrehozva, majd hozzáillesztve astruktúra főágához. Ezeknél az alszekcióknál a this._fb.array metódus vehető ész-re: ez azt jelenti, hogy az adott szekciók több példányból is állhatnak. Ez kifejezettenhasznos lesz a későbbiekben a dinamikusan hozzáadható és törölhető elemek implemen-tálásánál, mivel a fastruktúra egyes részeit csak egy-egy metódussal megadott változójelképezi.

21

Page 22: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

Ezek után példaként nézhetjük az egyszerű author alszekció HTML-beli előkészí-tését.

1 <div formArrayName="authors">2 <div class="card -header card -info">Authors </div>3 <div class="divider"></div>4 <div *ngFor="let author of authors.controls; let i=index" class="

card row" style="margin -left: 0.3em;margin -right: 0.3em;">5 <div class="form -group" [formGroupName ]="i">6 <div class="col -md -1 glyphicon glyphicon -remove btn pull -right"

style="text -align: right; height: 10px;" (click)="removeAuthor(i,modalTemplate)">x</div>

7 <div class="col -md -3">8 <small >Name</small>9 <input type="text " class="form -control" formControlName="name

" [typeahead ]="user_names" typeaheadMinLength="0">10 <small [hidden ]="author.get(’name ’).valid" class="text -danger

">Name is required </small>11 </div>12 <div class="col -md -4">13 <small >Department </small >14 <input type="text " class="form -control" formControlName="

department">15 </div>16 </div>17 </div>18 </div>

Az authors alszekció

A formArrayName változónak megadott értékkel kötjük az általa definiált teljesszekciót (a divet és gyerekelemeit) a formBuilder struktúra megfelelő részéhez. A 4.sorban indított *ngFor direktíva segítségével iterálunk végig az authors tömb jelenlegfastruktúrában levő elemein és mindegyikhez létrehozunk egy-egy form-group csopor-tot a hozzá tartozó mezők definícióival együtt. A csoport létrehozásánál észrevehetőpár újdonság. Meg van adva egy kattintásra aktiválódó esemény, ami a removeAuthormetódust hívja. Ez a tömb kiválasztott csoportját törli a struktúrából (a metódus ki-fejtése egy későbbi fejezetben található). Látható továbbá a form-control input mezőis, ami a formControlName paraméterével van hozzákötve a struktúrához. (Ugyanitttalálható a typeahead funkció megadása is, amihez szintén tartozik bővebb leírás akövetkező fejezetben.) Végül a validációhoz is tartozik külön elem. Amíg a name mezőnem felel meg a validációs követelményeknek, addig egy figyelmeztetés jelenik meg.

2.5.7. A struktúra frissítése

A MongoDB engedélyezi, hogy olyan dokumentumokat töltsünk fel, amik nem konzisz-tensek az alapstruktúrával (pl. új mezőket tartalmaznak), mivel nem is törődik a struk-túra felépítésével. Viszont lekérdezéseknél hibát okozhat, ha valamelyik dokumentumnem rendelkezik egy keresett mezővel. Ezért célszerű új struktúraelem hozzáadásakorfrissíteni az összes dokumentumot egy default üres mezővel, vagy más, specifikusabbtartalommal. Az is megtörténhet, hogy a teljes struktúrát szeretnénk átrendezni, ekkormuszáj szkriptet írnunk, ami átalakítja a régi dokumentumokat is.

Az egyik legfontosabb átalakítás a tableRow header-jeihez fűződik. A szkript al-kalmazása előtt egy tableRow elem egy header-ből és a hozzá tartozó dinamikusan

22

Page 23: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

bővíthető parameters gyerekelemekből állt. Meg kellett valósítani, hogy a header-ekis szabadon bővíthetőek legyenek. Ahogy az látható, a header adatai mind bele voltakégetve a tableRow-ba a parameters elemmel ellentétben.

1 oneTableRow () {return this._fb.group ({2 species: [’’],3 subSpecies: [’’],4 description: [’’],5 ...6 parameters: this._fb.array([this.oneParameter ()]),7 });8 }

A régi tableRow

A documentComponent-ben elég volt külön kigyűjteni egy metódusba ezeket az ada-tokat a parameters-hez hasonlóan és refaktorálni/megírni a hozzá fűződő struktúramó-dosító metódusokat. Így viszont csak az új feltöltött dokumentumok rendelkeznének azúj struktúrával, sőt, ezután, ha egy régi dokumentumot akarnánk betölteni szerkesztés-re, az mindenképp hibát okozna. Ezért a MongoDB-ben egy szkripttel át kell rendeznia régi dokumentumokat is.

1 db.documents.find ({}).forEach(function(doc) {2 if(doc.data.tables [0]. tableRows [0]. headers === undefined){3 for(var i = 0; i < doc.data.tables.length; i++){4 doc.data.tables[i]. inVivo = false;5 for(var j = 0; j < doc.data.tables[i]. tableRows.length; j

++){6 var tableRowCtrl = doc.data.tables[i]. tableRows[j];7 if(tableRowCtrl.parameter === undefined){8 tableRowCtrl.parameter= "";9 }

10 tableRowCtrl.headers = [{11 notes: tableRowCtrl.notes ,12 unit: tableRowCtrl.unit ,13 value: tableRowCtrl.value ,14 parameter: tableRowCtrl.parameter ,15 description: tableRowCtrl.description ,16 subSpecies: tableRowCtrl.subSpecies ,17 species: tableRowCtrl.species18 }19 ];20 delete tableRowCtrl.species;21 delete tableRowCtrl.subSpecies;22 delete tableRowCtrl.description;23 delete tableRowCtrl.parameter;24 delete tableRowCtrl.value;25 delete tableRowCtrl.unit;26 delete tableRowCtrl.notes;27 }28 }29 }30 db.documents.save(doc);31 });

Struktúraátalakítás

Ahhoz, hogy a szkriptet alkalmazni tudjuk, parancssorból el kell indítani a mongod

23

Page 24: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

daemon programot (a kapcsolat felállításához) és mongo parancsértelmezőt, majd ause alga paranccsal kiválasztani a dokumentumokat tároló gyűjteményt.

A szkript egy metódusból áll, ami az összes dokumentumon végigmegy. Mivel márvoltak frissített struktúrájúak az adatbázisban, ezért először ezeket kiszűrjük, nem mó-dosítjuk. A többi dokumentumban végigiterálunk az összes table-ön egy for ciklussal.Ebben a frissítésben került a struktúrához az inVivo adat is, úgyhogy itt ez is frissül.Ezután a table-ek tableRow-jain is végigmegyünk. A tableRowControl változóba ki ismentjük az aktuális tableRow-ot, hogy változtatni tudjuk. Megvizsgáljuk, hogy létezik-e a parameter eleme, ha nem, inicializáljuk egy üres értékkel. Ezután létrehozzuk aheader-t is, amibe egyesével átválogatjuk a megfelelő értékeket. Így az elemen belülmegkapjuk a másolatokat, amihez azonban még mindig léteznek az eredeti elemek,ezeket kitöröljük a struktúrából. Végül elmentjük a változtatásokat.

2.5.8. A typeahead implementálása

A typeahead kényelmi funkció a felhasználók számára: amikor egy mezőbe szövegetír a felhasználó, egy lista jelenik meg, amiben az eddig beírt szöveg alapján ajánlottértékek szerepelnek, amik közül választhat, ha megtalálja köztük a beírni kívánt szöve-get. A listán megjelenő lehetőségek megjelenhetnek valamilyen rendezési szempont(ok)szerint, jelen esetben az egyszerűség és a rendezési számítások megspórolása érdekébennincs rendezés. A modul csak egy direktívát szolgáltat néhány opcióval, ezért az adatokelérésének megoldása a programozó feladata.

Az adatokat szolgáltató metódus paraméterként egy hatókört vár, amelyen belülkeresi az elemeket, azt a listát, amelyikbe bekerülnek (néhány előre megadott elemmellé), valamint opcionálisan egy feltételt arra, hogy működjön-e az adott mezőben atypeahead. Belül hívódik a DocumentService szolgáltatása, ami a szerverről lekérdezia scope segítségével szűrt elemeket. Ennek leírása a szerveroldal document kontrol-lerében található és egy új MongoDB-beli metódust használ: a distinct segítségévelkiszűrhetőek az egyező elemek. A szerverről érkező adatokon ezután végigiterálunk ésa helyi listán levő elemekkel is összevetjük, az egyezéseket elvetve. Ugyancsak megvizs-gáljuk, hogy a vizsgált elem nem üres-e véletlenül, csak ezután adjuk hozzá a typeaheadadatlistájához a document.consts.ts fájlban.

1 getTypeaheadData(scope , currentList , condition = {}) {2 this.docsService.getTypeaheadData(scope , condition).then((res) => {3 let data = res as Array <string >;4 for (let g of data) {5 if (currentList.includes(g)) { continue };6 if (g !== ’’) {7 currentList.push(g);8 }9 }

10 }, (err) => {11 console.log(err);12 });13 }

A typeaheadhez tartozó adatok biztosítása

Ezután a typeahead direktíva használható az előző HTML példában látott módon:megadjuk a tömböt, amit a kiíratáshoz használ, valamint, hogy mennyi karakter beírásaután jelenjenek meg a lehetőségek.

24

Page 25: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

2.5.9. Formmanipulálás

Új elemek hozzáadása

Ahogy arról már volt szó az üzleti logika bevezetőjében, a dokumentumkitöltő űrlapnakdinamikusnak kell lennie. Előfordulhat például, hogy egy folyóiratot több, előre nemdefiniált számú szerző írta, nem tudjuk előre a cikkben vizsgált algafajok és tulajdon-ságaik számát sem, stb. Ezek felvitele egy rugalmatlan, nem változtatható rendszerbeközel lehetetlen. A fejlesztés során fokozatosan derültek ki, mely részeket érdemes dina-mikussá tenni és melyek állandó méretű adatok, ezért az új funkciók programozása ésbeültetése a rendszerbe fokozott figyelmet igényelt. Ennek a pontosabb okát a következőpélda szemlélteti:

A lenti metódus egy tableRow elemet illeszt be az algaForm n. table szekciójánaka végére. Ennek a kiválasztása történik az első két sorban, a változókba kiíratássalegyszerre navigálunk a fában és mentünk el fontosabb csomópontokat. Ezután iniciali-záljuk az új tableRow-ot, amit be akarunk illeszteni: előkészítünk egy üres elemet, majda fastruktúra utolsó tableRow-jából átmásoljuk (patchValue metódus) a species éssubSpecies attribútumokat (a Kémiai Intézet kérése volt ez a kényelmi funkció, arraalapozva, hogy a legtöbb helyen ez a két adat megegyezik). Végül a push metódussalbeillesztjük az új tableRow-ot a struktúra végére.

1 addTableRow(n: number) {2 const tableControl = this.algaForm.get(’tables ’) as FormArray;3 const tableRowControl = tableControl.controls[n].get(’tableRows ’) as

FormArray;4 const tableRowCtrl = this.oneTableRow ();5 const oldTableRowData = tableRowControl.getRawValue ()[

tableRowControl.length - 1];6 const newTableRowData = {7 species: oldTableRowData[’species ’],8 subSpecies: oldTableRowData[’subSpecies ’],9 }

10 tableRowCtrl.patchValue(newTableRowData);11 tableRowControl.push(tableRowCtrl);12 }

Egy üres tableRow hozzáadása a struktúrához

A probléma abból fakadhat, hogy ha egy idő után a Kémiai Intézetből új kérésérkezik például egy új struktúra, vagy funkció hozzáadására, az a kapcsolódó összesmetódus refaktorálását, átszervezését is jelenti és ha valamelyik metódust kifelejtjük,az hibás működéshez vezethet.

Törlés a struktúrából

A törlés hasonlóan működik, mind a hozzáadás, viszont itt új kérdések merülnek fel:mi történik akkor, ha az utolsó elemet is kitöröltük? Szabad-e egyáltalán engedni afelhasználónak, hogy minden elemet kitöröljön? Hogyan értesítsük ezekről? A következőpélda egy lehetséges megoldást mutat be.

25

Page 26: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

1 removeRowHeader(n: number , i: number , k: number , template: TemplateRef<any >) {

2 const tableControl = this.algaForm.get(’tables ’) as FormArray;3 const tableRowControl = tableControl.controls[n].get(’tableRows ’) as

FormArray;4 const rowHeadersCtrl = tableRowControl.controls[i].get(’headers ’) as

FormArray;5 if (rowHeadersCtrl.length > 1) {6 rowHeadersCtrl.removeAt(k);7 } else {8 this.modalTitle = ’Delete permitted ’;9 this.modalMessage = ’You must have at least one row header ’;

10 this.modalRef = this.modalService.show(template);11 }12 }

Egy header elem törlése a struktúrából

Itt egy tableRow-on belüli header elem törlése történik. Mivel itt már konkrétanegy bizonyos elemet törlünk, ráadásul ez egy nagyobb szekció része, konkrétabb hivat-kozásra van szükség, ami több paraméter átadását jelenti. Az n az n. table-t jelöliki, az i az i. tableRow-ot, végül a k legbelül a törlendő header-t. Miután lenavigál-tunk a megfelelő elemhez, megvizsgáljuk, hogy 1-nél több header létezik-e és csakekkor töröljük az elemet. Ennek a hátterében az áll, hogy a form beküldhető lenneszinte üresen is, akár 0 table-lel, Alga leírással, stb. Ez pedig hibákat okozhatna aMongoDB-s lekérdezések során, valamint az adatok visszakeresésénél. Mivel ilyen ese-tek egyébként is csak véletlenül, felhasználói figyelmetlenségből történhetnek (egy-egykülönálló elemnek legalább mindenképp kell szerepelnie a struktúrában), ezért abbanaz esetben, ha az utolsó elemet is törölné, egy figyelmeztetést kap. Ezt modal segítsé-gével jelenítjük meg. A használatához szükséges egy sablon, ami megjelenik (a használtsablonok a document.component.html fájl alján fel vannak sorolva), valamint a meg-felelő metódusokban hivatkozni is kell rá. A példakód 8. sorától kezdődik a modalinicializálása: megadjuk a modal nevét és a kiírandó üzenetet, majd egy csomagbólkért modalService show metódusával megjelenítjük a modalt.

Elemek másolása

Az elemek másolása újabb kényelmi funkcióként került be a webalkalmazásba. Vol-tak ugyanis olyan elemek, amiknek tartalma részben, vagy egészben megegyezik és amásolás értelmét nyerte időhatékonyság szempontjából.

A másolás implementálásánál vált leginkább érezhetővé, hogy kritikussá válik a meg-felelő indexek választása, mivel egy rosszul megadott index nem feltétlenül a működésmegállásához, hanem rossz elemek másolásához vezet.

A lenti példában látható egy tableRow elem másolása. A lenavigálást követően lét-rehozzuk az új tableRow-ot, majd, mivel abba annyi gyerekelemet kell tenni, amennyia kiválasztott elemben is volt, ezért készíteni kell egy-egy vezérlőt a header és aparameter gyerekelemekhez is. Mindkettőnél először kitöröljük a oneTableRow me-tódus által a form létrehozásánál automatikusan legyártott gyerekelemeket, majd vé-gigiterálva a régi tableRow-on, minden gyerekelemhez létrehozunk egy új elemet ésátmásoljuk az összes értéket. A parameter-nél ezután még egy törlésre is sor kerül, avalue és deviation paramétereket ugyanis kérték a Kémiai Intézetben, hogy ne máso-lódjanak. Ezért azokat egyszerűen felülírjuk egy üres sztringgel. Ezután be kell helyezni

26

Page 27: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

az elkészült elemeket a helyükre. Végül a kész control-t beillesztjük a kiválasztott elemutáni helyre.

1 cloneTableRow(n: number , i: number) {2 const tableControl = this.algaForm.get(’tables ’) as FormArray;3 const tableRowControl = tableControl.controls[n].get(’tableRows ’) as

FormArray;4 const rowHeadersControl = tableRowControl.controls[i].get(’headers ’)

as FormArray;5 const paramControl = tableRowControl.controls[i].get(’parameters ’)

as FormArray;6 const newTableRow = this.oneTableRow ();7 const newRowHeadersControl=newTableRow.get(’headers ’) as FormArray;8 newRowHeadersControl.removeAt (0);9 for (let index = 0; index < rowHeadersControl.length; index ++) {

10 const newRow = this.oneRowHeader ();11 newRow.patchValue(rowHeadersControl.getRawValue ()[index]);12 newRowHeadersControl.insert(index , newRow);13 }14 const newParamControl = newTableRow.get(’parameters ’) as FormArray;15 newParamControl.removeAt (0);16 for (let index = 0; index < paramControl.length; index ++) {17 const newParameter = this.oneParameter ();18 newParameter.patchValue(paramControl.getRawValue ()[index ]);19 newParameter.patchValue ({ value: ’’, deviation: ’’ });20 newParamControl.insert(index , newParameter);21 }22 tableRowControl.insert(i + 1, newTableRow);23 }

Egy tableRow másolása

2.5.10. Dokumentumok mentése, keresése, szerkesztése és törlé-se

Mentés

Miután a felhasználó kitöltötte az űrlapot és az eleget tesz minden validációs fel-tételnek, beküldi az adatbázisba. Ezt a beküldést az ngSubmit direktíva által indí-tott saveDocument metódus készíti elő. Itt a cleanData metódus minden \n karak-tert kiszűr és átalakítja a kulcs-érték párokat beküldhető JSON formátumúra. Eh-hez hozzácsatoljuk a beküldő felhasználó email-címét és a jelenlegi dátumot, majd aDocumentService newDocument metódusával beküldjük a szerverre, ahol a már emlí-tett route-on átkerül a MongoDB insert metódusához, ami eltárolja a dokumentumot.

Keresés

Ha ezután vissza akarjuk keresni a dokumentumot, a search komponens segítségévelmegtehetjük. Ez a komponens a weboldalon egy, az űrlaptól külön lapon elérhető. Afunkcionalitását illetően képesek vagyunk szabad szavas kereséssel kikeresni dokumen-tumokat - ezeknek néhány hasznos információját tároló listán böngészve kikereshetjüka számunkra releváns dokumentumot, amit teljes egészében megtekinthetünk, sőt, le-hetőségünk van ezután a módosítására vagy akár a törlésére is.

27

Page 28: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

A keresési eredmények megjelenítését egy csomag, az ngx-datatable szolgáltat-ja, amit a HTML kódba tudunk beágyazni, viszont az inputjait a programozónakkell megadnia. Ez egyrészt a megfelelő oszlopok kiválasztását jelenti, másrészről aMongoDB-s keresés implementálását. Az oszlopok megadása a következőképpen törté-nik: a search.document.ts columns változójának megadjuk a dokumentum alapada-tait, valamint a létrehozáshoz és módosításhoz fűződő adatokat. Magának a keresésnekaz első és utolsó fázisa is a searchDocument metódusban történik. Itt küldjük ugyanisa kérést a DocumentService-nek és a kapott adatokat is itt dolgozzuk fel az adattáb-lánk számára (a row változó feltöltése). A DocumentService metódusa jelen esetbentöbb route-ra is küldheti a kérést a keresés típusától függően: ha csak egy szót kere-sünk, akkor a search route-on történik a keresés, ha üresen hagyjuk a keresési mezőt,akkor az összes dokumentumot visszakapjuk a docs route-ról, végül lehetőségünk vankulcs-érték pár alapján is keresni, egy „=” jellel elválasztva a két kifejezést.

A searchadvanced route-on elért searchDocumentsAdvancedmetódus a paraméte-rül kapott szöveget szétválasztja az „=” jel szerint, majd a második paramétert dekódol-ja, ami a különleges karakterek kereséséhez szükséges. Ezután egy vizsgálat következikarra, hogy a második paraméter esetlegesen true vagy false értéket vesz-e fel, mivelezeket átkonvertálja boolean megfelelőikre. Végül végbemegy a keresés a find metó-dussal. Itt meg van adva egy rendezési szempont is: a keresés végeztével a sortmetódusrendezi a kapott eredményeket a létrehozás dátuma szerinti csökkenő sorrendben, ígyaz adattábla alapvetően mindig a legfrissebb dokumentumokat mutatja (a rendezésiszempont viszont állítható a megfelelő mezőre kattintással - ez az ngx-datatable általbiztosított funkció).

1 searchDocumentsAdvanced = (req , res) => {2 let searchText = req.params.text.split(’=’);3 searchText [1] = decodeURI(searchText [1]);4 if (searchText [1] === ’true’ || searchText [1] === ’false ’) {5 searchText [1] = (searchText [1] === ’true’);6 }7 let q = this.model.find({ [searchText [0]]: searchText [1] }).sort({

creationDate: -1 });8 q.exec(function (err , obj) {9 if (err) {

10 return console.error(err);11 }12 res.json(obj);13 });14 }

A kulcs-értékpár szerinti keresés

Szerkesztés és törlés

Tehát ha a keresés után megjelenő adattáblából kiválasztunk egy dokumentumot, an-nak megjelenik a teljes tartalma egy táblázatban. Ennek a táblázatnak a tetején ugyan-akkor megjelenik egy „Edit document” gomb is. Ha megnézzük a HTML kódját, lát-ható, hogy az editDocument metódust hívja. Ez a jelenleg kiválasztott dokumentumazonosítóját letárolja, törli a kijelölést és végül navigál a documentadmin route-ra azazonosítóval együtt. Indul a Document komponens és az ngOnInit életciklusban, mivelparaméterként átkerült az azonosító, lefut az inicializációs szakasz.

28

Page 29: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

Az Angularban minden komponensnek van egy életciklusa, ami az életbe lépésé-től a megszűnéséig biztosít lifecycle hook-okat, hogy ellenőrizzünk bizonyos paramé-tereket, valamint metódusokat futtassunk bennük. Az ngOnInit a komponens létre-jöttekor lép életbe, tehát inicializáló metódusokat hívunk meg benne. Jelen esetbenezek az initAlgaForm és egy Observable metódus. Az Observable hasonló a Promise-hoz, viszont az előbbi több eseményt képes kezelni. Éppen ezért sokan preferálják azObservable-t, viszont a kis méretű Alga Database esetében egyszerűbb volt a Promiseokhasználata, ezért az Observable csak itt van használva.

A documentComponent az ngOnInit ciklust használja, hogy létrehozza az alap űr-lapstruktúrát, begyűjtse a szerverről a szükséges typeahead értékeket és jelen esetben,mivel a szerkesztésre kijelölt dokumentum azonosítója átkerült, lefut a feltételes inici-alizációs szakasz is. Az inicializációban a documentService hívja a getOneDocumentmetódust, ami visszaadja a megfelelő azonosítójú dokumentumot. Lementjük az azo-nosítót későbbi használatra, majd az inEdit változót is igazra állítjuk, ugyancsak ké-sőbbre. Ez a változó biztosítja ugyanis a HTML-ben egy feltételvizsgálattal, hogy afrissítés és törlés gombok csak itt jelenjenek meg és az új dokumentum mentése ne (ésfordítva a változó hamis értéke esetén). Ezután indul az űrlap méretezése: az összes do-kumentumbeli elem hosszát (azaz gyerekelemeinek számát) lekérdezzük és ennyi elemethozunk létre mindegyikhez. Itt több észrevételt tehetünk:

- A ciklusváltozók legtöbb esetben nem 0-tól indulnak. Ennek az az oka, hogyaz életciklus elején lefut az initAlgaForm metódus, ami alapértelmezetten márbiztosít egy-egy elemet az űrlap minden részére.

- Azok a gyerekelemek, amik még más gyerekelemekkel is rendelkeznek (a tableRowpéldául), először törlődnek a struktúrából, ez lehetővé teszi a kényelmesebb hoz-záadást, valamint a bugok elkerülését.

- Miután elkészült a dokumentum váza, a patchValue metódussal egyszerűen rá-illeszthető maga a dokumentum.

Ha ezután a dokumentumot el akarjuk távolítani az adatbázisból, a Remove gomb-bal megtehetjük, ez a deleteDocument metódussal hívja a documentService azonosnevű szolgáltatását, ami a szerver felé irányítja a kérést. Hasonlóan, ha az átszerkesztettdokumentumot akarjuk feltölteni, az Update gomb lenyomására az updateDocument hí-vódik. Itt egy alapvető verziókövetés is végbemegy: a dokumentum mellett eltárolódikegy tömbbe az új módosítás dátuma és a módosító felhasználó email címe is. Ezál-tal visszakövethető, kik és mikor szerkesztettek. Mind a törlés, mind a frissítés a márismertetett modal segítségével ki is ír egy üzenetet a művelet sikeréről.

2.5.11. Dokumentumok betöltése fájlból

Mivel a Kémiai Intézet kutatói a régi Excel táblázatba sok dokumentumot XML fáj-lokból töltöttek fel, így ésszerű volt megadni a lehetőséget az automatikus XML-bőlvaló feltöltésre a webalkalmazásban is.

A lehetőség default megjelenik egy drag and drop ablak formájában, amíg doku-mentum típusnak a folyóirat cikk van kiválasztva. Amint egy fájlt behúz a felhasználó,aktiválódik egy esemény, ami a dropped metódust hívja. Ez előkészíti a fájlt a fel-dolgozásra. A file-drop komponens engedi, hogy több fájlt is a feldolgozási listára

29

Page 30: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.5. Az üzleti logika implementációja

helyezzünk egyszerre, ezért ez egy for ciklusban külön-külön történik. Miután betöltötta fájlolvasó objektum, elindul a belső insertText metódus, ami a fájlból kitölti azűrlapot.

1 insertText(loadedFile , template: TemplateRef <any >) {2 let x2js = new X2JS();3 let document = x2js.xml2js(loadedFile.target.result);4 let authorNames = document[’xml’][’records ’][’record ’][’

contributors ’][’authors ’][’author ’];56 let titleForCheck = document[’xml’][’records ’][’record ’][’titles ’

][’title ’][’style’]. __text;7 this.docsService.countTitle(titleForCheck).then((res) => {8 let count = <any >(res as Array <string >);9 if (count !== 0) {

10 this.modalRef = this.modalService.show(template);11 this.appRef.tick();12 }13 }, (err) => {14 console.log(err);15 });

Feltöltés fájlból

Mivel a fájl XML típusú, viszont a MongoDB JSON-nel dolgozik, ezért az X2JS cso-mag segítségével először átkonvertáljuk. Ezután kimentjük a szerzőneveket egy későbbiciklusban való iteráláshoz. Ugyanezt megismételjük a dokumentum címével is. Itt márlátható a konvertált fájlban való navigálás módja: a tömbelemek egy-egy csomópontotjelölnek, amiket kijelölhetünk és lekérhetjük a szövegértékét is (ha van) a __text névrehivatkozással.

A documentService countTitlemetódusa összeszámolja, mennyi azonos című cikklett már feldolgozva. Mivel a cím egyedi cikkenként, ezért ha már szerepel az adatbá-zisban egy feldolgozás, az valószínűleg azt jelenti, hogy csak egy másolat kerülne be azúj fájlból. Ezért modalon keresztül a felhasználó egy figyelmeztetést kap erről.

1 this.algaForm.patchValue ({2 url: document[’xml’][’records ’][’record ’][’urls’][’related -urls’

][’url’][’style’].__text ,3 year: document[’xml’][’records ’][’record ’][’dates ’][’year’][’

style’].__text ,4 title: titleForCheck ,5 });67 const control = <FormArray >this.algaForm.controls[’authors ’];8 control.removeAt (0);9 let i = 0;

10 for (let obj of authorNames) {11 this.addAuthor ();12 control.at(i).patchValue ({ name: obj[’style’]. __text }, {

onlySelf: true });13 i++;14 }15 ...16 this.appRef.tick();17 }

Feltöltés fájlból (folytatás)

30

Page 31: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.6. A webalkalmazás kinézete és használata

Ezután megkezdődik az űrlap kitöltése: a patchValue metódus a megfelelő mezőketkitölti a struktúra legfelső szintjén. A szerzők esetében muszáj manuálisan inicializálniés feltölteni a mezőket. Az elemek másolásához hasonlóan itt is célszerű először törölnia default létrehozott elemet és csak ezután iterálni végig a szerzők listáján.

Az ezt követő kitöltések is hasonlóak, ezért a fenti példában nem szerepelnek. Azegyetlen lényeges különbség, hogy ezeknél meg van valósítva a kivételkezelés, mivelegyes elemek hiányozhatnak a fájlból, a journal mező esetében pedig kétféleképp ismeg lehet adva az információ. A metódust egy tick metódus zárja, ami frissíti aváltozásokat, enélkül nem jelennének meg a feltöltött adatok a mezőkben.

2.6. A webalkalmazás kinézete és használataZárásként a webalkalmazás kinézetéről lesz szó. Az alábbi listán sorrendben olvashatóka következő oldalakon levő képes demonstrációk leírásai.

- A login képernyő, ami a betöltés (és az azt jelző animáció) után jelenik meg.

- A User Admin oldalon látható táblázat a jelenlegi felhasználókról. Az oldalt csakaz admin jogosultságú felhasználók láthatják, ők képesek felhasználókat törölniis a rendszerből.

- Ugyanezen az oldalon található az új felhasználó felvétele is. A szerepkörök kivá-lasztásánál Ctrl+ a jogosultságok kiválasztásával egyszerre több jogosultság ismegadható egy felhasználónak.

- Az űrlap első lapjának részlete, ahol a felhasznált tudományos cikk/folyóirat ada-tait lehet megadni. Látható az XML fájl feldolgozó funkció is.

- Az űrlap legkomplexebb table eleme. A Copy Table gombbal az egész aktuálislap másolható egy új table elembe, a Remove Table gombbal törölhető, ha nemez az utolsó megmaradt table elem. Ugyanez vonatkozik a gyerekelemek mellettlevő másolás és törlés ikonokra is.

- A keresés oldal adattábla része. Felül található a keresősáv, alatta pedig a talá-latok kigyűjtve.

- Miután kiválasztottunk egy dokumentumot az adattáblából, alatta részletes leírástalálható róla. Ugyanitt van a Dokumentum szerkesztésére szolgáló gomb is.

- Rossz felhasználói név vagy jelszó megadása esetén megjelenő modal.

- Amennyiben már csak egy table maradt és törölni szeretnénk azt, ez a modaljelenik meg helyette.

31

Page 32: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.6. A webalkalmazás kinézete és használata

32

Page 33: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.6. A webalkalmazás kinézete és használata

33

Page 34: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.6. A webalkalmazás kinézete és használata

34

Page 35: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.6. A webalkalmazás kinézete és használata

35

Page 36: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.6. A webalkalmazás kinézete és használata

36

Page 37: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.6. A webalkalmazás kinézete és használata

37

Page 38: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.6. A webalkalmazás kinézete és használata

38

Page 39: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

2.6. A webalkalmazás kinézete és használata

39

Page 40: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

3. fejezet

Összefoglalás

A gyakorlati tapasztalataim azt mutatják, hogy az Angular keretrendszer a változatosfunkcióinak köszönhetően hatékony az alacsony szintű JavaScript kiterjesztéseként. Adinamikusan betöltődő, saját életciklussal rendelkező komponensek, a modulok, direk-tívák és legfőképp az űrlapkezelő funkciók jelentősen megkönnyítették az Alga Databa-se fejlesztését. A MongoDB jól alkalmazható NoSQL adatbázisrendszer, amennyibena dokumentum-alapú adattárolás megfelel a projekt jellegét figyelembe véve. Az Exp-ressJS routere egyszerű hozzáférést nyújtott a szerveroldali metódusokhoz. A NodeJScsomagkezelője pedig rengeteg eszközt szolgáltatott ahhoz, hogy egyszerűsítse a fejlesz-tést.

A webalkalmazás fejlesztésében a Kémiai Intézettel folytatott megbeszélések nagyszerepet játszottak. Minden visszajelzés előrevitte a projektet, legyen szó akár új funkci-ók hozzáadásáról, már létezők átalakításáról, vagy a kinézet megváltoztatásáról. Mivelilyen nagy volt a szerepük a fejlesztésben, a kutatók végül olyan alkalmazást kaptak,amit egyszerűen és kényelmesen tudnak használni. Ez bizonyította a prototípusos fej-lesztés sikerességét.

40

Page 41: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

Irodalomjegyzék

[1] Isaias, P., & Issa, T. (2015). High level models and methodologies for informationsystems. New York: Springer., 21.

[2] Isaias, P., & Issa, T. (2015). High level models and methodologies for informationsystems. New York: Springer., 33–34.

[3] „Component Decorators.” Ng-Book: the Complete Guide to Angular 4, by FelipeCoury et al.

[4] „Bootstrapping Crash Course.” Ng-Book: the Complete Guide to Angular 4, byFelipe Coury et al.

[5] „MongoDB Architecture.” www.mongodb.com/mongodb-architecture Web. 14 Mar.2018.

[6] „Terminology and Concepts” docs.mongodb.com/manual/reference/sql-comparisonWeb. 15 Mar. 2018.

[7] angular.io/api/forms/FormBuilder Web. 25 Mar. 2018.

41

Page 42: Szakdolgozatmidra.uni-miskolc.hu/document/30074/26010.pdf · 2. fejezet Elméleti háttér 2.1. A fejlesztés menete Ahogyazabevezetésbenolvasható,aszakdolgozathozkészítettwebalkalmazásterede

Adathordozó használati útmutató

A mellékelt CD-n található a felhasználói dokumentáció és egy zip fájlban a programösszecsomagolva. A teszt adatbázist a weboldal automatikusan betölti futtatáskor. Aprogram futtatásához a következők szükségesek:

- Programok: NodeJS, MongoDB, böngésző

- Parancssorból el kell navigálni a MongoDB telepítési könyvtárába, majd ebbe amappába: Server/3.4/bin. Itt kell futtatni a mongod programot, egészen addig,amíg a webalkalmazást használni szeretnénk.

- Ezután el kell indítani a szervert és lefordítani a programkódot. Két új parancs-sorra van szükség. El kell navigálni a chemdb mappájába (miután azt átmásoltuka merevlemezre) és az első parancssorban a npm run gulp serve-api, a másik-ban pedig az npm run client parancsot kiadni. Miután elindult a szerver éslefordult a kód, a böngészőből a localhost:4200 URL-en elérjük az oldalt.

- A webalkalmazásba a gilbert email és abcd jelszó párossal lehet belépni az elsőhasználatkor, ez teljes jogosultságot biztosít a rendszerben.

42