PDF fájl készítése

A PDF népszerű fájlformátum. Az Adobe cég 30+ éves szabványa. Hordozható: azaz minden eszközön, platformon ugyanúgy jelenik meg. Számos nézegető program támogatja, köztük böngészőprogramok is. A PDF rövidítés a Portable Document Format betűszava. Többnyire kimeneti formátumnak tekinthető. Az évek során folyamatosan fejlődött: ma már űrlapokat is tartalmazhat, elektronikusan aláírható, hitelesíthető, és hivatalos ügyek során is használják.

PDF fájl többféleképpen is készíthető. Például:

  • irodai szoftverek Mentés másként… menüpontjában,
  • Adobe Acrobat szoftverrel,
  • online alkalmazásokkal sokféle fájlformátum konvertálható PDF-be,
  • speciális célszoftverek is generálhatnak PDF fájlokat.

Utóbbi esetekre néhány példa:

  • online megvásárolt koncertjegyet e-mail csatolmányaként kapunk PDF-ben, ugyanígy számlát is róla,
  • online tanfolyamunk záró tesztjét követően letölthető tanúsítványt, badge-t, online IQ tesztünk eredményeként oklevelet kapunk PDF fájlként,
  • kérdőívek kitöltése során egyéni válaszainkat visszaigazolásként PDF-et kapunk, vagy a kérdőív kitöltési időszakának végén összesített eredményt, PDF riportot kapunk.

Java program készít PDF fájlt

Adatokra van szükség. Korábbi Munkakör, létszám, névsor lekérdezése blog bejegyzésünkben az Oracle HR sémából kétféleképpen is lekérdeztük a szükséges adatokat. Ezt érdemes előzetesen tanulmányozni, hogy a további tartalom könnyebben érthető legyen. A Java SE szoftverfejlesztő tanfolyam megközelítése alapján, az egyszerűbb SQL paranccsal előállított eredménytáblát a PDF generálása előtt még csoportosítani kell (munkakörönként). A Java adatbázis-kezelő tanfolyam megközelítése alapján, az összetettebb SQL paranccsal elkészített, denormalizált eredménytábla közvetlenül felhasználható.

A cél egy táblázat elkészítése, amely 3 oszlopból áll: munkakör, létszám és névsor. Az azonos munkakörű alkalmazottak névsora egy táblázat egyetlen cellájában legyen megjeleníthető. Az elkészült táblázatból készüljön PDF fájl.

A teendők lépésenként

Szükséges az iText csomag importálása: com.itextpdf.text. Korábbi változata az 5-ös, aktuális változata a 8-as. Előbbi nagyon elterjedt, utóbbi még kevésbé ismert. A továbbiakban a kötelező kivételkezeléshez kötődő forráskód-részletek bemutatásától eltekintünk.

Tehát adott az összes szükséges adat egy  ArrayList<MunkakorLetszamNevsor> lista generikus listában. A POJO mindhárom szükséges és összetartozó tulajdonságot tárolja: String munkakor, int letszam, String nevsor.

Hasznos egy általánosan használható cella() függvény elkészítése, amely képes adott szöveget, adott betűmérettel, adott betűstílussal, adott igazítással „megjeleníteni”:

Létre kell hozni a pdfFajl objektumot, beállítani a méretét és a margókat, illetve fájlba kell irányítani:

Létre kell hozni a táblázat előtt megjelenő szöveget (ez nem a szövegszerkesztés szerinti valódi fejléc):

Létre kell hozni a táblázatot, megfelelő beállításokkal:

Létre kell hozni a táblázat fejlécét:

Végig kell haladni az adatokon és elő kell állítani a szükséges táblázatcellákat, végül le kell zárni a fájlt:

A PDF fájl és a belekerülő táblázatobjektum szerkezete DOM-szerű, illetve azonos a grafikus felhasználói felület felépítése során használt AWT/swing konténerszemlélettel.

A felhasznált programozási tételek: sorozatszámítás, kiválasztás, megszámolás, kiválogatás, illetve kombináltan: csoportosítás, rendezés.

Az eredmény

Az elkészült PDF fájl másfél oldalas, itt letölthető, megtekinthető. A dokumentumról készült képernyőkép:


Továbbfejlesztési lehetőségek

Igényeinktől függően, illetve előzetes tapasztalatainkra és a meglévő tudásunkra építve számos ötlet merülhet fel. Mindhárom tanfolyam esetén testre tudjuk szabni azt az SQL parancsot, ami a szükséges adatokat lekérdezi. Az iText csomag helyett felfedezhetjük a PDF Clown, a PDFBox, illetve a Spire.PDF csomagok funkcionalitását is.

  • A Java SE szoftverfejlesztő tanfolyam tematikájához kötődve egyszerűbb dolgokat tudunk megvalósítani. Használhatunk további stílusokat: betűre, bekezdésre, cellára, táblázatra vonatkoztatva, színeket, szegélyeket. Többoldalas dokumentum esetén hozzáadhatunk oldalszámot, oldalszám / oldalak száma mezőt, tényleges fej- és láblécet, generálásra vonatkozó időbélyeget, képezhetjük szabály alapján a PDF fájl nevét, illetve tallózhatjuk annak helyét (hol jöjjön létre).
  • A Java EE szoftverfejlesztő tanfolyam tematikájához kötődve az előzőeken felül elhelyezhetjük a generált fájlt egy szerveren és elküldhetjük e-mailben a letöltéséhez szükséges URL-t. A letöltés korlátozható darabszámmal és időben is (például max. 3 db letöltés lehetséges a következő 48 órán belül). A PDF fájlba belekerülhet szöveges vízjel, céges logó és saját képként dinamikusan előállított grafikon. Például a JFreeChart grafikon készítése projekt swing-es GUI felületéből néhány utasítással készíthetünk JPG vagy GIF formátumú képet, ami könnyen beilleszthető PDF-be. Online, webes API szolgáltatás használatával az előállított PDF fájl tömöríthető, illetve belekerülhet QR kód, vonalkód is.
  • A Java adatbázis-kezelő tanfolyam tematikájához kötődve az előzőeken felül a JDBC alapú back-end kicserélhető JPA alapúra. A PDF láblécébe beleírhatjuk, hogy az adatbázis-szerveren kinek a nevében futott (DB User) az a lekérdezés, ami előállította a szükséges adatokat. Megoldható a generált PDF egyedi azonosítója, azaz kétszer nem állítható elő „ugyanaz”. Modulárisan továbbfejlesztve gyakorolhatjuk a tudatosan felépített MVC architekturális tervezési minta használatát. Limit feletti méretű PDF fájlt több kisebbre szétdarabolhatunk.

A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

Alkalmazottak életpálya modellje – mi lenne, ha…?

Kiss Balázs kolléga Alkalmazottak életpálya modellje – munkakör, fizetés jutalék blog bejegyzése inspirálta ezt a blog bejegyzést. Az Oracle HR sémában az értékesítési vezetők adható havi fizetése 10000 és 20000 között van, átlagfizetésük 12200. Az üzletkötők paraméterei hasonlóan: 6000, 12000, 8350. A pénznem USD. Mi lenne, ha…? Ha többféleképpen is kalkulálhatnánk jutalékokat fizetési modellek alapján. Vajon hogyan lehetne választani? Következzen kétféle fizetési modell az alkalmazottak jutalékaihoz kötődően.

Alkossunk egy fizetési modellt! Hogyan kalkuláljuk a jutalékokat?

A jutalék negyedévente kerül kifizetésre és a havi fizetés megadott százaléka. Például: Elizabeth Bates üzletkötő havi fizetése 7300, jutaléka 15%, azaz minden 3. hónapban a fizetése 8395 helyett 10585. A negyedévek első két hónapjában a cég bérköltsége 691400, az utolsó hónapjában pedig 765090. Mindez arra a 106 fő alkalmazottra vonatkozik, akik részleghez tartoznak. Nincs benne az az 1 fő, aki nincs részleghez rendelve.

Összesített megoldás

A lekérdező SQL parancs:

Eredményül ezt az eredménytáblát adja:

Részlegekre összesített 1. megoldás

Vegyük figyelembe azt a 106 fő alkalmazottat, akik részleghez tartoznak (a 107 fő közül). Az alábbi lekérdező SQL parancsot futtatva:

Az eredménytábla 11 rekordból áll. A százalékok a részlegre jutó bérköltség arányát fejezik ki (tényleges fizetésre és jutalékos fizetésre vonatkoztatva).

Részlegekre összesített 2. megoldás

Balázs írta, hogy a Sales részlegben 35-en dolgoznak. Ez akkor helytálló, ha a munkakörök alapján kérdezzük le és láttuk, hogy a 35 főből értékesítési vezetőként 5 fő, üzletkötőként 30 fő dolgozik. Igen ám, de van egy olyan alkalmazott, aki nem tartozik egy részleghez sem ( DEPARTMENT_ID IS NULL), ezért kapjuk az előző eredménytábla szerint a Sales részlegben a 34 főt. Ugyanis az azt előállító lekérdező parancs a  DEPARTMENT_ID részlegazonosító alapján kapcsolja össze a két táblát ( EMPLOYEES és DEPARTMENTS). Ha az ő fizetését is figyelembe kell venni, akkor ez lehetséges az alábbi lekérdező paranccsal:

Az eredménytáblában az utolsó, 12. rekord tartalmazza az eddig hiányzó 1 fő alkalmazott adatait:

Az eredménytábla – az utolsó rekord kivételével – majdnem megegyezik az előzővel. A fizetési modell szerint a negyedévek első két hónapjában a cégre vonatkozó bérköltség 7000-rel növekszik és a negyedévek harmadik hónapjában pedig 8050-nel. A fizetések arányát százalékban egy tizedesjeggyel ábrázolva szinte nem vehető észre a különbség. A rekordok azonos sorrendjétől tekintsünk most el, hiszen a UNION és az ORDER BY alparancsok alkalmazása együtt külön történet. Aki érti, hogy mire gondolok, most biztosan kacsint egyet. 😉 Aki még nem érti, annak részletesen elmagyarázzuk Java adatbázis-kezelő tanfolyamunkon. Továbbá a százalékokat összesítve a kerekítésük miatt nem kapunk pontosan 100%-ot.

Az így kapott adatok kiegészítik a Top 5 fizetésű alkalmazottak listája blog bejegyzésben kapott adatokat. Ott nem szerepelnek az alkalmazottak részlegei, de természetesen könnyen összepárosíthatók. Másképpen: a 107 fő alkalmazottból 35 fő (32,7%) kapja a fizetések 45%-át jutalék nélkül, illetve 50,4%-t jutalékkal kalkulálva. Tehát érdemes/megéri a Sales részlegben dolgozni. Még akár jutalék nélkül is. 🙂

A bejegyzéshez tartozó teljes Java forráskódot (ami beépítve tartalmazza a fenti SQL lekérdező parancsokat) ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

A feladatok a Java adatbázis-kezelő tanfolyam 13-16. óra: Konzolos kliensalkalmazás fejlesztése JDBC alapon, 1. rész alkalmához és a 33-36. óra: Grafikus kliensalkalmazás fejlesztése JDBC alapon, 1. rész alkalmához kötődnek.

Az SQL forráskód formázásához a Free Online SQL Formatter-t használtam.

Alkossunk másik fizetési modellt! Várjuk hozzászólásban a megoldás SQL parancsait.

Vajon hogyan változna az előző fizetési modell, ha a negyedévente kifizetendő jutalék számítási alapja a havi fizetés helyett a háromhavi – időszakra vonatkozó – fizetés megadott százaléka lenne? Hogyan alakulna a cég bérköltsége?

Alkalmazottak életpálya modellje – munkakör, fizetés, jutalék

Az Oracle HR sémában 11 részleg található 107 alkalmazottal, akik 19 különböző munkakörben végzik munkájukat. Nyilvánvalóan mindenkinek a fizetése pozitív ( SALARY>0), havi, USD pénznemben. Két munkakörre jellemző, hogy tartozik hozzá jutalék ( COMMISSION_PCT), amely pozitív valós szám. A 17 többi munkakörben foglalkoztatott alkalmazott esetében az adatbázis EMPLOYEES táblájának jutalék mezőjében NULL található. Az Oracle HS séma:

Oracle HR séma

Életpálya-modellnek tekinthető a munkakörhöz ( JOB_ID és JOB_TITLE) tartozó adható legkisebb és legnagyobb fizetés ( MIN_SALARY, MAX_SALARY) nyújtotta mozgástér. Minden alkalmazottra teljesül, hogy a fizetése a megadott határok között található (zárt intervallumként kezelve). Ennek ellenőrzésére használható az alábbi SQL parancs:

Eredménytábla:

A MIN(SALARY) oszlopban található a valós/kapott fizetések minimuma. A mellette lévő oszlopok hasonlóan a maximumot és az átlagot mutatják. A részlegben található alkalmazottak számát az utolsó, COUNT_EMPLOYEE oszlop tartalmazza.

35 fő dolgozik a Sales részlegben. Az 5 fő Sales Manager (értékesítési vezető) jutaléka a fizetés 20%-ától 40%-áig terjedhet 10%-os lépésközzel (3-féle lehet). A 30 fő Sales Representative (üzletkötő) jutaléka a fizetés 10%-ától 35%-áig terjedhet 5%-os lépésközzel (6-féle lehet). Ennek igazolására használható az alábbi SQL parancs:

Eredménytábla:

A bejegyzéshez tartozó teljes Java forráskódot (ami beépítve tartalmazza a fenti SQL lekérdező parancsokat) ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

A feladatok megoldása során nem foglalkoztam külön azzal az egy alkalmazottal, akinek nincs részlege. A feladatok a Java adatbázis-kezelő tanfolyam 13-16. óra: Konzolos kliensalkalmazás fejlesztése JDBC alapon, 1. rész alkalmához és a 33-36. óra: Grafikus kliensalkalmazás fejlesztése JDBC alapon, 1. rész alkalmához kötődnek.

Az SQL forráskód formázásához a Free Online SQL Formatter-t használtam.

Gyűjtsünk össze adatokat névjegykártya készítéshez!

névjegy

Induljunk ki az Oracle HR sémából!

Az EMPLOYEES táblából szükséges adatok: alkalmazottak neve konkatenálva a FIRST_NAME és LAST_NAME mezőkből, illetve a meglévő elérhetőségek: EMAIL (kiegészítve), PHONE_NUMBER és a hozzáadott WEBSITE. A JOBS táblából szükséges a munkakör megnevezése a JOB_TITLE mezőből, és a részleg neve a DEPARTMENTS tábla DEPARTMENT_NAME mezőből.

Építeni kell a DEPARTMENTS és EMPLOYEES táblák közötti 1:N kapcsolatra (azaz egy adott részlegben több alkalmazott is dolgozik), amelyet a DEPARTMENT_ID mező valósít meg. Nem szükséges az EMPLOYEES és DEPARTMENTS táblák közötti 1:N kapcsolat (azaz egy adott alkalmazott vezetőként több részleget is vezethet). Szükséges a JOBS és az EMPLOYEES táblák közötti 1:N kapcsolat, ami a JOB_ID mezővel valósul meg.

Hasznosak a köztes/átmeneti elnevezések a tábláknál ( D, J, E) és a mezőknél (például EMPLOYEE_NAME) egyaránt. Előbbieknél a mezőnevek minősítéséhez és egyértelmű hivatkozásaihoz kellenek, utóbbinál a metaadatokba kerülnek és utólag kiolvashatók ( ResultSetMetaData) és megjelenítéstől függően tartozhatnak például egy JTable vizuális komponens mögötti DefaultTableModel-hez.

A CONCAT függvénynek két paramétere lehet, ezért csak ott használtam, ahol ez kézenfekvő volt és elegendőnek bizonyult (az EMPLOYEE_NAME-nél nem akartam egymásba ágyazni két CONCAT-ot).

Az első lekérdezés a 107-ből 106 alkalmazott adatait adja vissza.
A második lekérdezés a hiányzó 1 alkalmazott adatai miatt szükséges, akinek nincs beállított részlege ( DEPARTMENT_ID IS NULL). Neki hiányos a COMPANY_DEPARTMENT_NAME adata, de így is egységes lehet az eredménytáblaként kapott adathalmaz (például oszlopok sorrendje és adattípusa).
A két lekérdezés eredményét egyesíteni kell ( UNION).

A lekérdező parancs

A lekérdező utasítást bele kell építeni egy Java kliensprogramba (MVC architekturális tervezési minta szerint a modell rétegbe), ami JDBC alapon kapcsolódik az Oracle adatbázis-szerver HR sémájához olyan felhasználó nevében, aki csatlakozhat és lekérdezhet. Meg kell tervezni és felügyelni kell a biztonságos kapcsolatot (kivételkezeléssel), annak életciklusát (nyit, lekérdez, zár), valamint gondoskodni kell az eredménytábla megjelenítéséről.

A keletkező eredménytábla exportálható Excel-be (XLS, XLSX formátumokba), és kiegészíthető például még egy oszloppal/mezővel (darabszám). Ezután átadható a grafikusnak, aki például felhasználja azt adatforrásként saját névjegykártya tervező szoftverében, vagy használja a Word körlevél varázslóját. Az adatforrás sorrendje ( ORDER BY) megkönnyítheti az elkészült névjegykártyák szétosztását.

A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

A feladat a Java SE szoftverfejlesztő tanfolyam 45-48. óra: Adatbázis-kezelés JDBC alapon, 1. rész alkalmához, illetve a Java adatbázis-kezelő tanfolyam 9-12. óra: Oracle HR séma elemzése, 13-16. óra: Konzolos kliensalkalmazás fejlesztése JDBC alapon, 1. rész, 33-36. óra: Grafikus kliensalkalmazás fejlesztése JDBC alapon, 2. rész alkalomhoz kapcsolódik.

Az SQL forráskód formázásához a Free Online SQL Formatter-t használtam.

Tagadós lekérdezések

Tagadós lekérdezések

Tagadós lekérdezésekAz SQL nyelv utasításai többféleképpen csoportosíthatók. Például: adatdefiníciós utasítások (DDL), adatmanipulációs utasítások (DML), lekérdező utasítások (DQL), adatelérést vezérlő nyelv (DCL). A lekérdezések tanítása során másféle rendszerezés is adható. Például a tagadást tartalmazó lekérdezések önálló kategóriát alkothatnak.

Az Oracle HR sémát használjuk és bemutatunk tagadást tartalmazó lekérdezésre öt példát.

Oracle HR séma

1. Kik dolgoznak olyan részlegekben, ahonnan senki sem vett részt korábban projektmunkában?

A DEPARTMENTS és EMPLOYEES táblák között 1:N fokszámú kapcsolat van, és a DEPARTMENT_ID köti össze ezeket. A belső lekérdezés visszaadja azoknak a részlegeknek az azonosítóját ( DEPARTMENT_ID), amelyekből már legalább egyszer legalább egy alkalmazott részt vett korábban projektmunkában (ez most egy 6 elemből álló halmaz). A külső lekérdezésben a NOT IN predikátum – építve a belső lekérdezés eredményeire – megadja azon részlegek nevét ( DEPARTMENT_NAME), illetve az ott dolgozó alkalmazottak nevét ( EMPLOYEE_NAME), ahol az alkalmazotthoz tartozó részleg azonosítója nincs benne a belső lekérdezés által visszaadott eredménytáblában. 5 részlegben 15 alkalmazottra teljesül a feltétel. A NOT IN predikátum adja a tagadást.

SQL-1

Az eredmény:

SQL-1-eredmény

2. Melyek azok a részlegek, ahol nem minden alkalmazott azonos munkakörben dolgozik?

A DEPARTMENTS és EMPLOYEES táblák között 1:N fokszámú kapcsolat van, és a DEPARTMENT_ID köti össze ezeket. A lekérdezés csoportosítást végez részleg azonosítóra és névre ( DEPARTMENT_ID, DEPARTMENT_NAME), és aggregálja – most megszámolja – a csoportban előforduló egyedi munkakör azonosítókat ( JOB_ID), majd ezek közül kihagyja azokat, ahol a megszámolás 1-et ad (másképpen: azokat hagyja meg, ahol a megszámolás különbözik 1-től, 0 nem lehet, igazából 1-nél több) – ez biztosítja a tagadást. 7 részleget kapunk eredményül.

SQL-2

Az eredmény:

3. Kik azok az alkalmazottak, akik az életpálya modell alapján már nem kaphatnak fizetésemelést?

A JOBS és az EMPLOYEES táblák között 1:N fokszámú kapcsolat van, és a JOB_ID köti össze ezeket. Az életpálya modellhez tartozik egy munkakörhöz tartozó minimális és maximális fizetés ( MIN_SALARY és MAX_SALARY). Azok az alkalmazottak listázandók, akiknél a fizetés megegyezik a betöltött munkakörükhöz adható legmagasabb fizetéssel ( SALARY=MAX_SALARY). Ez jelenti a tagadást. Eredményül egyetlen alkalmazottat kapunk.

SQL-3

Az eredmény:

SQL-3-eredmény

4. Kik a nem vezető munkakörben dolgozó alkalmazottak?

A belső lekérdezés 18 olyan alkalmazott vezetőjének azonosítóját ( MANAGER_ID) adja vissza, akik lehetnek részlegvezetők vagy középvezetők. A külső lekérdezés minden olyan alkalmazott azonosítóját és nevét ( EMPLOYEE_ID, EMPLOYEE_NAME) adja vissza, akik nincsenek benne a belső lekérdezés által visszaadott eredményhalmazban. Ez adja a tagadást. Eredményül 89 alkalmazottat kapunk.

SQL-4

Az eredmény:

SQL-4-eredmény

5. Milyen részlegek találhatók nem amerikai régió területén lévő országokban?

A REGIONS, COUNTRIES, LOCATIONS, DEPARTMENTS táblák között balról-jobbra páronként 1:N fokszámú kapcsolat van és ugyanebben a sorrendben a REGION_ID, COUNTRY_ID, LOCATION_ID köti ezeket össze. A belső lekérdezés azért szükséges, mert vannak üres/fiktív részlegek is, amelyeket ki kell hagyni. Az amerikai régió azonosítója 2 ( REGION_ID), ezt adja most a tagadást. Eredményül 3 részleget kapunk 2 országban és 1 régióban.

SQL-5

Az eredmény:

SQL-5-eredmény

A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

A feladatok megoldása során nem foglalkoztam külön azzal az egy alkalmazottal, akinek nincs részlege. A feladatok a Java adatbázis-kezelő tanfolyam 13-16. óra: Konzolos kliensalkalmazás fejlesztése JDBC alapon, 1. rész alkalmához és a 33-36. óra: Grafikus kliensalkalmazás fejlesztése JDBC alapon, 1. rész alkalmához kötődnek.

Az SQL forráskód formázásához a Free Online SQL Formatter-t használtam.