nyomtatványok kezelése Java-ban

Jasper Report Dev

Forráskód - Jasper Reports 6.2.2

Hogyan használjuk fel a Jasper Reports library kódját

2016. július 06. - lacimol

Az esetek többségében a Jasper Studio használata a vizuális felületen való kattintgatásban kimerül, de speciális esetekben szükség lehet a forráskód mélyebb ismeretére is. Ilyen eset lehet a listák kezelése kapcsán használandó JsonDataSource osztály kódja vagy a hibakezelés is.

A forráskódot a https://sourceforge.net/projects/jasperreports/files/jasperreports oldalról tölthetjük le, ha kiválasztjuk a szükséges verziót (pl: 6.2.2), majd a "jasperreports-x.x.x-project.zip" elemet választva. A letöltött fájl kicsomagolása után importálhatjuk az Eclipse-be Maven projektként.

A JsonDataSource kódjának részlete:

public class JsonDataSource extends JRAbstractTextDataSource implements JsonData {
... @Override public Object getFieldValue(JRField jrField) throws JRException { if (currentJsonNode == null) { return null; } String expression = jrField.getDescription(); if (expression == null || expression.length() == 0) { expression = jrField.getName(); if (expression == null || expression.length() == 0) { return null; } } Object value = null; Class<?> valueClass = jrField.getValueClass(); JsonNode selectedObject = getJsonData(currentJsonNode, expression); if (Object.class != valueClass) { boolean hasValue = selectedObject != null && !selectedObject.isMissingNode() && !selectedObject.isNull(); if (hasValue) { try { if (valueClass.equals(String.class)) { if (selectedObject.isArray()) { value = selectedObject.toString(); } else { value = selectedObject.asText(); } } else if (valueClass.equals(Boolean.class)) { value = selectedObject.booleanValue(); } else if (Number.class.isAssignableFrom(valueClass)) { value = convertStringValue(selectedObject.asText(), valueClass); } else if (Date.class.isAssignableFrom(valueClass)) { value = convertStringValue(selectedObject.asText(), valueClass); } else { throw new JRException(EXCEPTION_MESSAGE_KEY_CANNOT_CONVERT_FIELD_TYPE, new Object[] { jrField.getName(), valueClass.getName() }); } } catch (Exception e) { throw new JRException(EXCEPTION_MESSAGE_KEY_JSON_FIELD_VALUE_NOT_RETRIEVED, new Object[] { jrField.getName(), valueClass.getName() }, e); } } } else { value = selectedObject; } return value; }
... }

List helyett ArrayNode

A fenti kódban látszik, hogy a mező visszatérési értéke csak String, Number, Boolean vagy Date lehet. Ha egy lista elemeit szeretnénk visszakapni java.util.List típusként, akkor csalódnunk kell. Ebben az esetben csak java.lang.Object-ként kérhetjük el, de még így sem cast-olhatjuk List-re, hanem csak JsonNode lehet (selectedObject). Látható az is, hogy ha tömböt String-ként kérünk el, akkor azt ugyan visszakapjuk, de már csak String-ként dolgozhatunk vele (["", "", ""]). A tömb elemeinek számát például nem kérdezhetjük le így (csak csűrés-csavarással: replace + Arrays.asList).

Hogyan tudjuk meg egy adott lista elemeinek számát?

A megoldást a kódban továbbugrálva kaphatjuk meg: getJsonData - goDownPathWithAttribute - goDownPath:

protected JsonNode goDownPath(JsonNode rootNode, String simplePath) {
		if(rootNode != null && !rootNode.isMissingNode()) {
			JsonNode result = null;
			if (rootNode.isObject()) {
				result = rootNode.path(simplePath);
			} else if (rootNode.isArray()) {
				result = mapper.createArrayNode();
				for (JsonNode node: rootNode) {
					JsonNode deeperNode = node.path(simplePath);
					if (!deeperNode.isMissingNode()) {
						if (deeperNode.isArray()) {
							for(JsonNode arrayNode: deeperNode) {
								((ArrayNode)result).add(arrayNode);
							}
						} else {
							((ArrayNode)result).add(deeperNode);
						}
					} 
				}
			}
			return result;
		} 
		return rootNode;
	}

A createArrayNode() visszatérési értéke com.fasterxml.jackson.databind.node.ArrayNode, amelynek már van size() metódusa, így megkaphatjuk az adott lista elemeinek számát is.

Visszatérési érték bővítése List-tel

A fenti getFieldValue() metódust bővíthetjük a következő kódrészlettel:

    @Override
	public Object getFieldValue(JRField jrField) throws JRException {
		...		
		if (Object.class != valueClass) {
			boolean hasValue = selectedObject != null && !selectedObject.isMissingNode() && !selectedObject.isNull();
			if (hasValue) {
				try {
					if (valueClass.equals(String.class)) {
						...
					} else if (List.class.equals(valueClass)) {
						List<Object> result = new ArrayList<Object>();
						if (!selectedObject.isMissingNode() && selectedObject.isArray()) {
							value = this.convertToList(selectedObject, result);
						} else {
							value = result;
						}
						
					} ...
				} catch (Exception e) {
					...
				}
			}
		} ...
		
		return value;
	}

A listát összepakoló metódus szöveges elemként teszi be a listaelemeket, függetlenül azok típusától (a jelenlegi cél a lista elemszámának kiderítése). A listába ágyazott mélységi listák felderítését a rekurzivitás biztosítja.

private List<Object> convertToList(JsonNode selectedObject, List<Object> result) {
		for (JsonNode node : selectedObject) {
			if (!node.isMissingNode() && node.isArray()) {
				List<Object> innerResult = new ArrayList<Object>();
				result.add(innerResult);
				this.convertToList(node, innerResult);
			} else {
				// don't care about type
				result.add(node.asText());
			}
		}
		return result;
	}

A módosított kód használata

A maven install után a target mappában találjuk a "jasperreports-6.2.2.jar" fájlt. A Jasper Studio telepített mappájában keressünk rá a "jasperreports*.jar"-ra és a 6.2.2-es verziót tartalmazzó mappában írjuk felül a legenerált jar fájllal az ottani jart (a mappa helye a frissítésektől függ). Ez a fájl nálam a következő helyen található:

..\configuration\org.eclipse.osgi\506\0\.cp\lib\jasperreports-6.2.2-20160505.150232-15.jar

Az $F{issues} mező class property-jét Object-ről java.util.List-re állítjuk. Így, ha egy jármű bejegyzéseinek számára vagyunk kíváncsiak, akkor a korábban használt kifejezés helyett az $V{issueSize} változóban egy egyszerűbbet használhatunk (nem kell a MissingNode miatti feltétel és nem kell cast-olni sem):

//($F{issues} instanceof ArrayNode) ? ((ArrayNode)$F{issues}).size() : 0;
$F{issues}.size()

Lista rendezése és szűrése

Rendezés

Egy adott lista elemeinek sorba rendezését célszerű megoldani már szerver oldalon a generált json fájlban. Ha ez nem lehetséges, akkor a Jasper Studio is kínál erre lehetőséget rendező mezők (Sort Field) formájában. Az Outline-on az adott Dataset alatt (Pl: Issues) a "Sort fields"-re jobb gombbal kattintva adhatunk hozzá új rendezési feltételt. Itt megadhatjuk a mező nevét, majd a hozzáadás után a Properties ablakban a rendezési irányt is lehet változtatni. Az IssueList-en az Issues Dataset-nél a "km" mezőt hozzáadva kilométer állás szerint rendezhetjük a rekordokat (jelenleg a json-ban is így van rendezve).

Sajnos ez a rendezési megoldás nem tökéletes. Ha ugyanis egy rendezett listán belül is használnánk "subDataSource-os" listát (itt a vehicles-en belül az issues), például a Vehicles Dataset "year" mező szerinti rendezésekor, akkor a következő hibát kapjuk:

net.sf.jasperreports.engine.JRException: net.sf.jasperreports.engine.JRRuntimeException: 
net.sf.jasperreports.engine.fill.JRExpressionEvalException:
Error evaluating expression for source text:
((JsonDataSource)$P{REPORT_DATA_SOURCE}).subDataSource("issues")
at com.jaspersoft.studio.editor.preview.view.control.ReportControler.fillReport(ReportControler.java:530)
at com.jaspersoft.studio.editor.preview.view.control.ReportControler.access$20(ReportControler.java:505)
at com.jaspersoft.studio.editor.preview.view.control.ReportControler$5.run(ReportControler.java:386)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
...
Caused by: java.lang.ClassCastException:
net.sf.jasperreports.engine.fill.SortedDataSource cannot be cast to net.sf.jasperreports.engine.data.JsonDataSource
at Cars_Vehicles_1466103932643_94221.evaluate(Cars_Vehicles_1466103932643_94221:197) at net.sf.jasperreports.engine.fill.JREvaluator.evaluate(JREvaluator.java:276) ... 22 more

A problémát az okozza, hogy a belső lista elemeinek eléréséhez a JsonDataSource (JDS) subDataSource metódusát használnánk, de a rendezett lista minden adattípus esetén SortedDataSource-ot ad vissza, ami nem cast-olható JDS-ra és nem elérhető a szükséges metódus sem. A problémát a SortedDataSource vagy a JDS bővítésével lehetne feloldani, de erre egyelőre nincs megoldás. Ezért is célszerű már a riportban felhasználás előtt rendezni az adatokat.

Szűrés

  1. Egyszerű szűrés (subDataSource és attributum)
  2. Feltételek használata
    • Beépített paraméter használata ($V{COLUMN_COUNT})
    • Komplex feltétel (&&)
    • Saját változó használata (tömb mérete)

Egyszerű szűrés

A List elemben a Dataset-nél van lehetőség egyszerű szűrési feltétel megadására a subDataSource elkérésénél.  Itt csak az alap operátorokat használhatjuk és csak egy mezőre. Ha csak azokat az járműveket használnánk, ahol a gyártási év 2006-os (Ford), akkor a következő kifejezést kell használnunk a JRDataSource Expression-ben:

((JsonDataSource)$P{REPORT_DATA_SOURCE}).subDataSource("vehicles(year == 2006)")

Feltételek használata

A Vehicles Dataset-nél az  "Edit query, filter..." gombra kattintva, a "Filter Expression" fül alatt a Expression editorban tetszőleges feltétel megadható.

filter_expression.png

// ha az 1996 és 2010 közötti járművekre szűrnénk:
// ha a year mezőt alapértelmezett String-ként hoztuk létre, akkor Integer-re kell alakítanunk
$F{year} != null && Integer.valueOf($F{year}) >= 1996 && Integer.valueOf($F{year}) <= 2010
// ha a year mező típusa Integer
$F{year} != null && $F{year} >= 1996 && $F{year} <= 2010

// ha csak a lista első két elemét jelenítenénk meg:
$V{COLUMN_COUNT} <= 2

// ha csak azokat a járműveket, ahol van bejegyzés:
// ekkor az $F{issues} mezőben be kell állítani a "issues.date" értéket a Description részen,
// 1. így String-ként kapjuk vissza egy tömb értékét, majd a $V{issuesSize} változóban az
// Arrays.asList($F{issues}.replaceAll("\\[","").replaceAll("\\]","").split(",")).size(); értéket kell megadnunk
// 2. Object-ként kapjuk vissza, amit a $V{issuesSize} változóban ArrayNode-ra alakítunk
// ($F{issues} instanceof ArrayNode) ? ((ArrayNode)$F{issues}).size() : 0;
$V{issuesSize} > 0

*: Az ArrayNode használatához célszerű importálni a com.fasterxml.jackson.databind.node.ArrayNode osztályt (ahogy korábban a JsonDataSource-t), de az alap projektben nem lehet, így mindig a teljes nevet kellene kiírnunk. Erre megoldás lehet, ha a "MyReport - jobb click - Properties" részen hozzáadjuk a Library-nál a "JasperReports Library Dependecies"-t.

A listák használatának kezdetén már látszott, hogy a Jasper Reports használata nem úszható meg minimális programozási tudás nélkül (alap feltételek, cast-olás és operátorok), de a fenti feltételeknél már többre is szükség lehet. Például a tömbök esetén várt java.util.List helyett visszaadott ArrayNode nincs dokumentálva, csak a forráskódból következtethető ki (JsonDataSource). A Jasper Reports forráskód felhasználásáról a későbbiekben írok. A fenti rendezést és szűréseket tartalmazó videó megtalálható itt, a forrásfájlok pedig itt.

A fenti feltételek mindegyike - a meglévő négy elemből - csak ugyanazt a két járművet adja vissza: Honda és Ford.

cars_year_filtered_full.png

A Jasper Studio frissítése

Az alkalmazás fejlesztői időnként kisebb-nagyobb fejlesztéseket végeznek és ehhez új verziót adnak ki. A Studio beépített update manager-rével könnyen elvégezhetjük a frissítést. A kisebb verziókat mindig érdemes gyorsan lekövetni, de a nagyobb váltásoknál célszerű az első néhány javítást megvárni. Jelenleg a 6.2.1-es verziót használjuk, de már megjelent a 6.2.2-es, így ezt érdemes frissíteni. A telepítés 5-10 percet vesz igénybe és a Jasper Studio újraindításával végződik:

Help - Check for Updates - Next - Next - Accept - <Security warning> OK - <Restart> Yes.

Ha az újraindítás után a projektünk piros jelölést kap (valamelyik fájl hibásnak tűnik), akkor a Projekt kijelölése után végezhetünk egy kis "tisztogatást":  (MyProject) - Project - Clean.

Lista a listában

tömbök kezelése a nyomtatványon

Esetenként szükség lehet egy lista egy másik lista elemen belüli megjelenítésére. Ilyen például a szervizkönyvben a gépjármű listán belüli bejegyzés lista. Ez alapján egy autó adatai alatt láthatjuk a szerviz és vizsga dátumokat. A fenti feladat megoldható két lista elem egymásba ágyazásával. Ehhez bővítenünk kell a kezdeti adatforrást egy "vehicle" elemen belüli új tömbbel ("issues"), azaz a járművekhez csatoljuk a hozzájuk kapcsolódó bejegyzéseket.

{
  "personal": {
    "name": "Molnár László",
    "birthPlace": "Baja",
    "birthDate": "1975-04-03"
  },
  "vehicles": [
    {
      "make": "Honda",
      "model": "Civic",
      "year": 1996,
      "issues": [{
        "date": "1996-01-01",
        "km": 0,
        "description": "Vétel"
      }, {
        "date": "1997-02-03",
        "km": 15677,
        "description": "Szerviz"
      }, {
        "date": "1998-03-04",
        "km": 25400,
        "description": "Vizsga"
      }]
    },{
      "make": "Ford",
      "model": "S-Max",
      "year": 2006,
      "issues": [{
        "date": "2006-06-01",
        "km": 0,
        "description": "Vétel"
      }, {
        "date": "2007-02-03",
        "km": 25111,
        "description": "Szerviz"
      }, {
        "date": "2008-03-04",
        "km": 45500,
        "description": "Vizsga"
      }]
    },{
      "make": "Škoda",
      "model": "Ŕoomster",
      "year": 2016
    },{
      "make": "Лада",
      "model": "Нива",
      "year": 1986
    }
  ]
}

A tömbök kezelése

A fenti adatforrás 4 elemet tartalmaz a vehicles tömbben és - 2 elemen belül -  további 3-3 elemet az issues-ban. Például a Ford S-Max első vizsgájának időpontjára (2008-03-04) így hivatkozhatunk: "vehicles[1].issues[2].date", ha egy külön adatmezőbe   kiemelnénk csak ennek az egy elemnek a dátum mezőjét ($F{vehiclesIssueDate}).

A tömbök számozása 0-tól kezdődik, így a vehicles[1] a második járműre mutat (Ford). Sajnos a Dataset editor nem ad támogatást a sorszámok megadásához, mert bármelyik elemet adnánk a field-ekhez, mindig a sorszám nélküli elérési utat menti el (a módosításokat a "Data preview" fülön próbálgathatjuk). Ha nem adjuk meg a tömbök adott elemének számát (vehicles.issues.date), akkor az ezen az elérési úton lévő összes elemet  (2*3) visszakapjuk egy tömbben (["1996-01-01","1997-02-03",...]). Így a "vehicles[1].issues[2].date" és a "vehicles.issues.date[5]" ugyanazt az elemet adja vissza.

arrayspath.png

Lista a listában

Az újabb lista behúzásához a "MainReport" fülről át kell lépnünk a már létező List elemre (dupla kattintás). A Properties fülön érdemes rögtön elnevezni az eddigi List néven futó listánkat (mondjuk VehicleList-nek). Így a Design részen már ez fog megjelenni és könnyebben meg tudjuk majd különböztetni a behúzandó allistától. A behúzáshoz növeljük meg a VehicleList elemet vertikálisan, majd a Palette-ről húzzunk be egy új List elemet. Adjuk meg adatforrásnak az "issues" blokkot(*) és adjuk hozzá a szükséges mezőket (date, km, description), majd ezt az listát is nevezzük el (IssueList). A VehicleList-en lévő 3 mezőt vonjuk egybe és emeljük ki vastagon (bold). Az IssueList-en a km mezőt bővítsük a " km" mértékegységgel a szövegmezőben.

(*) A belső lista adatforrásánál (DataSet) nem a fő adatforrásból kiindulva kell megadnunk az expression mezőben a kifejezést (...subDataSource("vehicles.issues")), hanem a korábbi külső lista "vehicles" adatforrásából indulunk (...subDataSource("issues")).

arraysinarray.png

A módosítások eredménye az előnézeti képen (preview):

carslistinlist.png

A forrásfájlok letölthetők innen, a videó pedig elérhető itt. A következő posztban a listák sorrendjével és szűrésével foglalkozom majd.

Egyedi és speciális karakterek

A Jasper Studio-ban az alapértelmezett betűkészlet a Helvetica, amihez a Nyugat-Európai Cp1252-es kódtáblát használja. Ez a Preview generálásakor nem okoz gondot, de ha exportáljuk a PDF-et vagy külső forrásból generáljuk, akkor a logikai betűkészlethez tartozó JVM-ben regisztrált (fizikai) betűtípust fogja használni (ha az egyáltalán létezik az adott operációs rendszerben) és lemaradnak a magyar ékezetes karakterek (pl: ő, ű).

A fenti ok miatt is célszerű már a nyomtatványtervezés elején kiválasztani egy pdf-hez csatolható betűkészletet, majd telepíteni a Jasper Studio-ba és a generáló környezet alá (classpath). A betűkészletnek unicode karakterek kezelésére is képesnek kell lennie (pl: a *.ttf fájl nem néhány 10 KB, hanem több 100 KB kell legyen).

Telepítés a Jasper Studio-ba

A betűkészleteket az un Font Extension rendszeren keresztül telepíthetjük a Jasper-hez. Ez egy jar fájl, amiben benne van az adott betűtípus (pl: ttf) és a használatát leíró xml fájl. Létrehozni a Window - Preferences - Jasper Studio - Fonts részen lehet az "Add" gombra kattintva. A nevét, a *.ttf fájl elérési útját (pl: Open Sans), az Encoding-ot (kódkészlet) meg kell adni és az "Embed this font in PDF"-et be kell pipálni (csatolás a PDF-hez). Innen az exportálással lehet létrehozni a generálási helyen használandó jar fájlt.

sansunicode.png

Kódkészlet

Ha magyar ékezetes karaktereket használnánk a nyomtatványon, akkor a Cp1250-es vagy a Identity-H a megfelelő választás. Előbbinél csak az adott kódkészlet kerül beágyazásra, utóbbinál a teljes unicode (karakterenként 2 byte-on, kicsit nagyobb helyett foglalva).

Telepítés a generáló környezetbe

A generálás történhet lokálisan (standalone) vagy webes környezetben (Tomcat szerver). Előbbinél a mainfest fájlon keresztül beállítható az elérési út, utóbbinál a Tomcat lib könyvtárába kell másolni az exportált jar fájlt. Ha dinamikusan feltölthető betűket szeretnénk, akkor az ExtensionsRegistry és ExtensionsRegistryFactory osztályok implementálásával ez is megoldható. Ha nincsenek egyedi igényeink, de biztos akarunk lenni, hogy az alap betűkészletek meglesznek az adott környezetben (pl: Arial esetén), akkor használhatunk előre elkészített csomagokat is.

Használat

Az adott elemet kiválasztva a Properties panelen a Font részen állítható be a korábban telepített betűkészlet. Ha a betűtípus mellett a nagyságban vagy típusban is eltérnénk az alap beállításoktól és több helyen használnánk ezeket, akkor érdemes egy új Style elemet felvenni és azt használni az adott elem Appearance részén. Ha egy Frame-en belül több Text elem is van, akkor ilyenkor elég csak a Frame-ben átállítani a Style-t.

Videó a betűkészlet használatáról:

A betűkészlet különbségek bemutatásához felvettem két új járműt a listába. Az egyik Cp1250-es kódolású szlovák (Skoda), a másik Cp1251-es orosz betűkészletet használó szöveg (Lada). A lenti Roomster-t persze nem speciális R-rel írják, de a szemléltetéshez pont jó :)

 

A projekt fájljai letölthetők innen.

További információk: 

http://jasperreports.sourceforge.net/sample.reference/fonts
http://community.jaspersoft.com/wiki/custom-font-font-extension 

Listák a nyomtatványon

Az autós nyomtatványon eddig a személyes adatokat jelenítettük meg, de a szervizkönyvhöz szükség van a járművek felsorolására is. A következőkben két autó tulajdonságait teszem fel a nyomtatványra lista elem formájában.

A Jasper Studio-ban a tömbök ábrázolásához használhatunk táblázatot (Table) és listát (List). Mindkettő adatfelhasználása megegyezik, de a lista megjelenése egyszerűbb. A járműlistához az eddig is használt adatforrást állítom be (cars.json), amelyből a "vehicles" tömböt fogom listaként megjeleníteni:

{
   "personal": {
      "name": "Molnár László",
      "birthPlace": "Baja",
      "birthDate": "1975-04-03"
   },
   "vehicles": [{
      "make": "Honda",
      "model": "Civic",
      "year": 1996
   },{
      "make": "Ford",
      "model": "S-Max",
      "year": 2006
   }]
}

A lista beszúrásához be kell húzni egy "List" elemet, majd a varázslón végig kattintva létrehozhatjuk a listát. Ebben be lehet állítani az adatforrást és a használandó mezőket (make, model, year). Az adatokat a riport fő adatforrásából vesszük, annak egy szelete lesz a lista forrása. Ezt a subDataSource metóduson keresztül, a json path ("vehicles") megadásával tehetjük meg: 

((net.sf.jasperreports.engine.data.JsonDataSource)$P{REPORT_DATA_SOURCE}).subDataSource("vehicles")

list.png

Sajnos a felület nem ad semmilyen segítséget a JsonDataSource metódusaihoz (pl: felugró listából választás lehetősége, azaz code complete), így ezt mindenképpen kézzel kell megadnunk a DataSource expression mezőben. Ha a JsonDataSource osztályt importáljuk, akkor a csomag jelölés is elhagyható, de a cast-olás mindenképpen szükséges:

((JsonDataSource)$P{REPORT_DATA_SOURCE}).subDataSource("vehicles")

A lista hozzáadása után arra duplán kattintva egy új fül jelenik meg a Design nézet alatt, a Main mellett lesz egy List is. Ez utóbbiban tudjuk a listára felpakolt mezőket kezelni. A listaelemek rendezése után a Preview-ban generált pdf-en látható a 2 autó adatait tartalmazó lista.

Videó a listák kezeléséről:

 

További információk: http://community.jaspersoft.com/wiki/lists-jaspersoft-studio

Képek a nyomtatványon

Egyedi dokumentumok szerkesztésekor a legtöbb esetben a használni kívánt képet egyszerűen beillesztjük és csatoljuk a fájlhoz (például egy word doc készítésekor). A Jasper Reports-nál nincs ilyen lehetőség (*), de lehet paraméterként átadni képet (java.awt.Image, java.io.InputStream) vagy Jasper repository-t használni (server-re feltöltve) vagy írhatunk egy saját FileResolver-t is (java.io.File), de a legegyszerűbb megoldás a szöveges alapú hivatkozás (java.lang.String).

*: Kép csatolása a design felületről közvetlenül nem lehetséges, de Base64 kódolás segítségével megoldható. Így a generált nyomtatványon látható lesz a kép, de design nézetben nem.

A Jasper Studio-ban a kép elemek nyomtatványhoz adása több módon történhet. Behúzhatjuk őket közvetlenül a Project Explorer-ből, mint a korábbi posztban vagy a Palette-ről betehetünk egy Image elemet, aminél több további mód közül választhatunk (lásd lenti videó). A szöveges megoldások közül néhány:

  • relatív: csak fájlnév, beolvasva a classPath-ról ("rendszam.jpg")
  • abszolút: teljes elérési út ("c:\images\rendszam.jpg")
  • url: "http://www.valoskilometer.hu/images/articles/Car.png"
  • parameter: $P{IMAGE_URL} vagy $P{IMAGE_DIR} + "rendszam"

A fentiek közül az első kettő inkább teszteléshez használható, a közvetlen url elsősorban statikus képekhez, amíg a paraméterben megadott "útvonal és név" kombó jól használható minden esetben. A Design módban beállított érték a lentihez hasonló kódot eredményez a jrxml forrásban:

<image>
     <reportElement x="150" y="0" width="200" height="100"/>
     <imageExpression class="java.lang.String"><![CDATA["rendszam.jpg"]]></imageExpression>
</image>

 

images.png

A képek legtöbb beállítási lehetősége a megjelenítésre vonatkozik (mint bármely szerkesztőben: méretezés, elhelyezkedés), de van néhány, amely a működést befolyásolja. A legtöbb ilyen maradhat alapértelmezett beállításon, de a hibakezelést érdemes a kép típusának megfelelően beállítani. Például logo vagy vonalkód esetén hibára kellene futnia (error), mert ezek nélkül nem jó a nyomtatvány. Egy díszítő elem esetén lehet üres (blank), de egy aláírás képnél el is dönthetjük, hogy később aláíratjuk manuálisan (blank) vagy mindenképpen kell az aláírás (error). Az icon lehetőség inkább csak hibakereséshez használható.

A képek fő jellemzői:

  • cache:
    • default: String alapú expression esetén alapértelmezetten true, egyébként false
    • true: mindig cache-ből olvas, ha lehet
    • false: mindig újratölti
  • lazy: csak HTML esetén érdekes (nem tölti be rögtön a képet, csak a html megnyitása esetén)
  • on error type (hiba esetén):
    • error: hibaüzenet jelenik meg, de a riport nem (exception)
    • blank: megjelenik a riport, de a kép helye üres marad
    • icon: a kép helyén egy icon jelenik meg

Képek kezelése:

További információk: http://jasperreports.sourceforge.net/sample.reference/images/index.html

A nyomtatványok struktúrája és elemeinek rendezése

Az alap nyomtatvány létrehozása után a felrakott mezőket elrendezzük, majd beállítjuk a nyomtatási oldal paramétereit és kivesszük a nem használandó szakaszokat.

Mezők rendezése

A rendezéshez az egérrel vonszolhatjuk és méretezhetjük az adott mezőt. Finomabb mozgatásokhoz használhatjuk a billentyűzet fel-le-oldalra gombjait is.

11_rendezes.png

Szakaszok (Bands):

A nyomtatványok több horizontális szakaszból állnak. Minden szakasznak más a funkciója, más esetben jelenik meg az adott oldalon.

  • Title: a nyomtatvány címe (az első oldalon jelenik meg, de bekapcsolható, hogy minden oldalon látszódjon)
  • Page header: az oldal fejléce (minden oldalon, általában statikus)
  • Column header: a tartalom blokk fejléce (általában dinamikus)
  • Detail: maga a tartalom (minden oldalon az adott - sorban következő - elem látszik)
  • Column footer: a tartalom blokk lábléce (általában dinamikus)
  • Page footer: az oldal lábléce (minden oldalon, általában statikus)
  • Summary: összegzés (csak a végén jelenik meg)
  • Background: háttér (minden oldalon)

Szakaszok eltávolítása:

A jelenlegi nyomtatványhoz csak a Title és Detail szakaszokra van szükség, így a többit törölhetjük (nem végleges, inkább csak elrejtés). Ezt a műveletet két módon tehetjük meg:

  • A Design editorban: szakasz kijelölése  + jobb kattintás és Delete vagy
  • Az Outline-on: jobb kattintás és Delete

12_band_removed.png

Nyomtatási oldal (Page): 

Az oldal formátumának beállítását az Outline - report kijelölése + Properties ablak: Page format - Edit útvonalon tehetjük meg. Ennél a nyomtatványnál a kezdeti 10 pixeles értéket 40-re állítottam a margóknál (Margins).

13_page_format.png

Képek kezelésének alapjai: 

A nyomtatványhoz két módszerrel adhatunk képeket: a Project exploror-ből közvetlenül behúzva a képet (nem lesz csatolva a riporthoz) vagy Palette-ről egy Image elemet behúzva megadhatjuk a kép kezelésének módját (pl: url alapján). A lenti képernyőn a rendszam.jpg-t húztam be a "Title" szakaszba. A képek csatolásával egy külön posztban foglalkozom majd.

14_image_dropped.png

 

Cím (Title): 

Végül bekerül egy statikus szövegmező a "Title" szakasz tetejére, megnövelt betűmérettel, teljes szélességgel középre igazítva.

16_title.png

Preview

Az eltüntetett szakaszok, a beállított oldal paraméterek és a mezők rendezése után a Preview-ra kattintva összeáll a nyomtatvány előnézeti képe.

17_preview.png

Videó a fenti lépésekről:

További információk: http://community.jaspersoft.com/wiki/report-structure-jaspersoft-studio

Nyomtatvány létrehozása - alapok

Lépések egy új riport létrehozásához:

A következőkben egy alap riportot hozok létre, amiben csak néhány mezőt teszek a nyomtatványra. Ezt kiegészítve és átalakítva a későbbiekben létrejön majd egy autókhoz használható szervizkönyv.

Új projekt létrehozása:

File - New project ("Cars" névvel): A projekt gyűjtő mappa a Jasper Studio-ban lévő nyomtatványok szétválasztásához és átláthatóságához szükséges. Ez a lépés kihagyható és használható az alapértelmezett projekt is (MyProject)

Új nyomtatvány:

File - New Jasper Report - Blank A4 ("Cars" névvel) --> New Data Source (json file): Kezdetnek elég egy üres nyomtatványt választani (Blank). Ha a nyomtatványon dinamikus adatokat is szeretnénk látni, akkor egy Data source-ot (adatforrás) is létre kell hoznunk. Ebből fogja a nyomtatványunk kiolvasni a felhasználandó adatokat.

Új adatforrás:

Az adatforrás létrehozásánál egy JSON típusút válasszunk és adjuk meg egy json file elérési útját. A mostani példához elég egy egyszerű json struktúra néhány adattal (cars.json):

{
   "personal": {
      "name": "Molnár László",
      "birthPlace": "Baja",
      "birthDate": "1975-04-03"
   },
   "vehicles": [{
      "make": "Honda",
      "model": "Civic",
      "year": 1996
   },{
      "make": "Ford",
      "model": "S-Max",
      "year": 2006
   }]
}

01_new_report_wizard.jpg

A létrehozott nyomtatvány áttekintése:

A létrejött Cars.jrxml file "Design" nézetében a nyomtatvány 7 különböző része látszik: title, page header, column header, detail, column footer, page, footer, summary (ezekről bővebben a következő posztban vagy a hivatalos oldalon)

04_empty_report_created.png

Új adatmező hozzáadása (Field):

Ha az adatforrásból fel szeretnénk használni egy adatmezőt, akkor azt hozzá kell adnunk a nyomtatvány adatmezőihez (Fields). Ezek a későbbiekben az Outline - Fields alatt érhetők el. Ezt a középső editor "Design" módja alatt a jobb felső részén lévő kis ikonra kattintva tehetjük meg (Cars.jrxml - Design - Edit dataset ikon (Dataset ans Query editor) -- personal.name - jobb egér kattintás - Add node as field).

02_dataset_add_node.png

Miután a personal alatt lévő3 mezőt hozzáadtuk, az adatmezők a lenti táblázatban láthatók (Fields fül). Ugyan itt megnézhetjük az adatok előnézeti tábláját is (Data preview fül).

03_dataset_nodes.png

Mező hozzáadása a nyomtatványhoz (Outline):

Ha az adatmezők egyikét behúzzuk az Outline-ról, akkor felkerül egy statikus mező az elnevezésnek és egy Text Field az adatmezőnek. Ez utóbbi értéke az adatmező hivatkozási neve lesz: $F{name}, azaz a "name" nevű adatmező tartalmát fogja bele tölteni generáláskor.

05_name_field_dropped.png

Mező hozzáadása a nyomtatványhoz (Palette): 

Ha a Palette-ról húzzuk be a Text Field elemet, akkor annak külön meg kell adnunk az értékét a Properties panelen (Text Field fül és Expression).

07_text_field_dropped.png

Mező szerkesztése:

Ha a mezőt kijelöljük a design nézeten, akkor a jobb alsó részen a Properties panelen megjelennek az adatai. A mező tartalmát az Expression részen módosíthatjuk: Properties - Text Field fül - Expression - Expression editor icon - kattintás a jobb oldali Fields-re - dupla kattintás a birthPlace elemre és a $F{birthPlace} érték bemásolódik - Finish.

08_expression_editor.png

Preview:

A középső editorban a Preview-ra kattintva előnézeti pdf-et generálhatunk (jelenlegi formában a nyomtatvány csak az alapvető működés bemutatását szolgálja).

09_text_field_preview.png

 

A következő posztban a nyomtatvány szerkezeti felépítésével és formai alakításával foglalkozom. A lenti videóban végignézhetőek a fenti lépések.

Jasper Studio telepítés és alapok

Az ismerkedéshez érdemes elsőként a Jasper Studio-t letölteni a JasperSoft Community oldalról. A TIBCOJaspersoftStudio-6.2.0.final-windows-x86_64.zip verzió ~400 MB, de ez már tartalmazza a Java futtató környezetet is (a 6.0 és 6.1 még Java 7-et használ, de a 6.2 már a 8-ast). Az editor az Eclipse fejlesztői környezetre épül, több részre osztva, kis ablakos megjelenéssel (Introduction to Jaspersoft Studio).

A Studio első indításakor meghatározhatjuk a munkaterületet (workspace), azaz hova kerüljenek a projektek és a létrehozott riportok. Érdemes a Jasper Studio kicsomagolási könyvtárába tenni, így később könnyebben hordozható lesz a rendszer.

Az indítás után előfordulhat, hogy nem a beépített Java 8-as környezetet használja a Studio (Project - Properties - JRE). Ilyenkor érdemes átnézni a operációs rendszer környezeti változóit (JAVA_HOME) és ideiglenesen átnevezni a korábbi Java verziót tartalmazó könyvtárat (C:\Program Files mappa), majd ezután indítani a Studio-t.

 jasper_ui.jpg

Balra a Project és Repository Explorer, alatta az Outline, mellette az Editor panel, majd jobbra a Palette és a Property editor.

A Project Explorer-ben találhatóak a riportokhoz létrehozott jrxml fájlok, a Repository-ban a felhasználható adatforrások, az Outline-ban a riport fő elemeinek struktúrája, a Palette-ból tehetünk fel egy új elemet a Riport editorra, a Property editor-ban pedig az egyes elemek tulajdonságait szerkeszthetjük. Az alsó középső részen a riport jelenlegi státuszát és az esetleges hibákat láthatjuk. A középen lévő Editorban 3 megjelenítési forma közül választhatunk: design (grafikus ui), source (jrxml kód) és preview (pdf).

 

Ha kész a telepítés, akkor a File menüpont alatt hozhatunk létre egy új riportot. Erről részletesebben a következő posztban olvashatsz.