Úvod do problematiky tisku sestav
Tento článek vznikl jako projekt pod vedením doc.
                  Ing. Pavla Herouta, Ph.D., Západočeská
                  univerzita v Plzni, Fakulta
                  aplikovaných věd, Katedra
                  informatiky a výpočetní techniky
                  Copyright © Kamil Ježek, 2007
Table of Contents
Java je programovací jazyk, který obsahuje velice
                    obsáhlé a bohaté knihovny funkcí pro různé oblasti
                    využití. Pochopitelně existují i oblasti, pro které
                    bychom metody v knihovnách Javy hledali marně. Na
                    druhou stranu obliba zmíněného jazyka a velká
                    základna programátorů zajišťuje, že pro mnoho
                    problémů lze nalézt řešení v podobě dodatečných
                    knihoven (reprezentovaných převážně .jar soubory). Přesně do
                    tohoto kontextu lze zařadit tisk sestav.
Ve standardních třídách z Java API bychom metody
                    pro jednoduchý tisk sestav hledali marně. Protože
                    se však jedná o velmi potřebnou vlastnost pro mnoho
                    aplikací, byla vytvořena knihovna funkcí nazvaná
                    JasperReports. Systém je vyvíjen open-source
                    komunitou a sám využívá další nástroje z produkce
                    open-source vývojářů.
Díky velkému počtu uživatelů a vývojářů
                    představuje JasperReports robustní nástroj, který
                    se rychle vyvíjí a je k dispozici naprosto zadarmo.
                    Jelikož je systém celý napsán v Javě a pracuje s
                    XML dokumenty snadno se používá a je přenositelný
                    napříč platformami.
JasperReports bohužel trpí nedostatkem
                    dokumentace a to zejména v češtině. Z toho důvodu
                    vznikla tato publikace. Neklade si za cíl vysvětlit
                    všechny aspekty návrhu sestav a kompletně popsat
                    API JasperReports, ale má čtenáře seznámit se
                    základními postupy při návrhování sestav a volání
                    tisku z Java programu.
Přestože text není enormně rozsáhlý, na konci
                    čtení by uživatel měl být schopen vytvořit takovou
                    sestavu, která bude použitelná v rozsáhlém
                    programu. Ne snad proto, že je uvedený text
                    geniálně napsán, ale právě díky jednoduchosti a
                    elegantnosti systému JasperReports. Kapitoly
                    uživatele provedou postupně od základů systému až
                    ke složitějším sestavám. Po prostudování tohoto
                    návodu by měl uživatel rozumět návrhu sestav a mít
                    dostatek vědomostí na to, aby dokázat “objevovat” další možnosti
                    tisku.
K tomu, abychom mohli využívat JasperReports
                      pro tisk v Javě, potřebujeme instalovat jako
                      první samotné knihovny systému JasperReports.
                      Nejsnadněji je nalezneme na webových stránkách
                      samotného projektu, které se nacházejí na adrese:
kde se snadno doklikáme ke stažení celého
                      balíku knihoven. Nebo lze přímo použít odkaz na
                      stažení:
Doporučuji stáhnout celý .zip soubor, který obsahuje nejen
                      knihovnu JasperReports, ale také další podpůrné
                      knihovny, které tento systém využívá. Dále ve
                      staženém souboru nalezneme zdrojové kódy, několik
                      ukázek a různé další soubory. Nás bude nejvíce
                      zajímat v adresáři dist soubor JasperReports-xy.jar, kde xy je verze
                      souboru a dále sada .jar souborů v adresáři lib. Samotné API pro
                      tisk je obsaženo právě v souboru JasperReports-xy.jar,
                      avšak ten pro svojí funkčnost využívá také další
                      knihovny z adresáře lib. Nemusí být pravda, že právě náš
                      program produkující tisk bude využívat všechny
                      tyto soubory, ale je lepší je všechny do projektu
                      začlenit, neboť nejsme autory JasperReports a
                      nevíme při jaké příležitosti je ta která knihovna
                      potřeba.
Aby náš program mohl používat stažené soubory,
                      je třeba je začlenit do CLASSPATH. V každém
                      vývojovém prostředí se tato volba nachází jinde
                      avšak většinou se jedná o menu s názvem library,
                      či project library. Alternativně můžeme nastavit
                      do systémové proměnné CLASSPATH cestu do
                      adresáře, kam jsme uložili stažené soubory.
Tímto bychom měli připraveny potřebné knihovny
                      pro tisk. Nic nám nebrání v tom, začít tvořit
                      první tiskové sestavy, avšak jak bude uvedeno
                      dále, každá sestava se v JasperReports popisuje
                      speciální šablonou ve formátu XML souboru. Pokud
                      by nebyla jiná cesta, je možné si tuto sestavu
                      napsat ručně v textovém editoru. Taková práce je
                      však dosti nepraktická. Hodil by se grafický
                      editor, kde bychom rovnou viděli, jak naše
                      sestava bude vypadat a nemuseli se probírat nic
                      neříkajícími XML tagy. Naštěstí takový systém
                      existuje a jmenuje se iReport. Jelikož oba
                      projekty, jak iReport tak JasperReport spolu úzce
                      souvisejí, je možné grafický návrhář iReport
                      stáhnout ze stejné webové adresy jako
                      JasperReport. K dispozici je jak instalátor pro
                      MS Windows, tak zdrojové soubory, nebo celý
                      projekt iReport. Přičemž sám tento návrhář je
                      napsán v Javě.
Tip
Mimo iReport je možné dohledat i jiné
                        návrháře, ale mé zkušenosti říkají, že iReport
                        je dostatečně dobrý o čemž svědčí i fakt, že je
                        přímo doporučován ke stažení na webových
                        stránkách společně s JasperReports.
Tip
Oba projekty, JasperReports a iReport jsou
                        dostupné zdarma včetně zdrojových kódů
JasperReports je systém, který podle vstupní
                      šablony produkuje výstup. Pro uživatele nabízí
                      bohaté API pro tisk do různých formátů.
                      Standardní Java API poskytuje rozhraní zaměřené
                      zejména na tisk komponent JFC Swingu. V našich
                      programech však častěji potřebujeme tisknout
                      sestavy a v současné době se jeví JasperReports
                      jako nejlepší volba.
Vytvoření každé sestavy se skládá ze čtyř
                      základních kroků.
- 
Vytvoření vstupní šablony ve formátu 
 .jrxml
- 
Zkompilování šablony do .jasper souboru 
- 
Vložení vstupních dat do sestavy 
- 
Volání metod z JasperReports API pro tisk 
 sestavy
Vstupní .jrxml
                      šablona není nic jiného, než XML soubor. Ten
                      obsahuje sadu specifických elementů, které
                      říkají, jak bude sestava vypadat, kde co bude
                      umístěno a jaká data se kde vloží. Popis všech
                      elementů a jejich význam zde však neuvádím, neboť
                      sestavy budeme tvořit v iReport, který nás od
                      ruční přípravy šablony naprosto odstíní.
Zkompilovaný .jasper soubor představuje
                      serializovanou třídu, která vznikla ze vstupní
                      šablony. Podle konkrétních požadavků na náš
                      program, se můžeme rozhodnout, zda si naše
                      sestavy předem zkompilujeme a program dále šíříme
                      jenom s .japser
                      soubory. Nebo můžeme sestavy kompilovat za běhu
                      užitím metod z knihoven JasperReports. Program
                      potom šíříme s .jrxml soubory. Druhou možnost
                      zvolíme pravděpodobně v situaci, kdy čekáme, že
                      se sestavy budou modifikovány za běhu programu.

Vstupní data sestavy jsou dvojího typu. Do
                      sestavy vkládáme parametry a datový zdroj.
                      Parametry se vkládají jako kolekce typu Map. Datový zdroj je objekt
                      zděděný od JRDataSource. Různé typy datových zdrojů budou popsány dále.
                      Zde postačuje informace, že datové zdroje mohou
                      být například kolekce JavaBeanů, spojená s
                      databází atd.
Rozhraní JasperReports pak obsahuje sadu metod,
                      které umožňují vytvářet různé tiskové sestavy ať
                      už výstupem na tiskárnu, nebo exportem do HTML,
                      či PDF souboru.
Pro vytvoření první sestavy si otevřeme editor
                      iReport. Volbou Menu / Nový dokument a založíme
                      novou šablonu. Otevře se nám šablona s několika
                      sekcemi (title, pageHeader, columnHeader atd.). V
                      nástrojové liště nalezneme několik nástrojů pro
                      kresbu čar, obdélníků, elips, či psaní textu.
                      Podle své fantazie vytvořte nějakou sestavu a
                      uložte.

Nyní zbývá vytvořit program, který naší sestavu
                      vytiskne. Otevřete si proto váš oblíbený editor.
                      Zde připomeňme, že je potřeba nastavit prostředí
                      tak, aby v CLASSPATH byl uveden soubor jasperreports-xy.jar a
                      všechny soubory s adresáře LIB ve staženém
                      balíku.
Pro správnou funkci je třeba importovat balík
import net.sf.jasperreports.engine.*;
A následně vložíme několik volání metod z
                      JasperReports API pro tisk sestavy:
    public static void main(String[] args) throws JRException {
        JasperReport jr = JasperCompileManager.compileReport(
                             "reports/example1.jrxml");
        JasperPrint jp = JasperFillManager.fillReport(
                             jr, null, new JREmptyDataSource());
        JasperPrintManager.printReport(jp, true);
    } 
Uvedený kód předpokládá, že jsme uložili
                      sestavu se jménem example1.jrxml do podadresáře reports. Všiměte si
                      také, že uvedené metody mohou vyhodit vyjímku
                      JRException. Uvedený
                      program nejprve metodou compileReport() zkompiluje vstupní
                      šablonu. Následně metodou fillReport()
                      vloží data a nakonec voláním printReport() tiskne. Hodnota null v metodě fillReport() říká, že
                      nepředáváme žádně parametry do sestavy. Objekt
                      JREmptyDataSource
                      označuje, že nevkládáme žádný datový zdroj. Zde
                      je dobré zdůraznit, že pokud naše sestava
                      nevyužívá datový zdroj, ale tiskne pouze statický
                      obsah (případně doplněný o parametry). Jako je
                      tomu v našem případě, skutečně potřebujeme volat
                      metodu s parametrem JREmptyDataSource. Kdybychom volali
                      například s hodnotou null, výsledná sestava by byla prázdá
                      (prázdný list). Třídy JasperCompileManager, JasperFillManager a JasperPrintManager obsahují velké
                      množství statických metod pro kompilaci, plnění a
                      tisk sestavy. Podrobný popis lze nalézt v
                      dokumentaci. Nejvýznamnější uvedu v následujících
                      částech textu.
V uvedeném příkladu je vidět, že jsme vyšli ze
                      zdrojové .jrxml
                      šablony a za běhu programu si šablonu
                      zkompilovali (tedy .jasper soubor se fyzicky nikam
                      neukládal, pouze se vygeneroval v paměti) a
                      výsledek vytiskli na tiskárnu.

V předchozí kapitole jsme si ukázali, jak
                      vytvořit nejjednodušší statickou sestavu.
                      Zpravidla však potřebujeme tisknout výstup dat
                      našeho programu, což pochopitelně JasperReports
                      umožňuje. Jelikož JasperReports je vhodný pro
                      tisk sestav, obsahuje prostředky pro vkládání
                      seznamů dat. Mimoto umožňuje sestavu různě
                      parametrizovat vstupem doplňkových parametrů.
                      Dále máme možnost provádět jednodušší výpočty
                      přímo v sestavě. Abychom toho dosáhli, můžeme v
                      šabloně použít celkem tři typy dat: parametry
                      (parametrs), datové pole (fields), proměnná
                      (variable) s následujícím významem:
- 
Parametr – v sestavě se označuje 
 konstrukcí
 $P{název}
 konkrétní hodnoty, která se umístí někde v
 sestavě. Například si můžeme takto předat
 do hlavičky název firmy při tisku faktury.
 Do sestavy se vkládá jako instanceMap<String,s významem
 Object>
 [název_proměnné, hodnota]
- 
Field – v sestavě se označuje 
 konstrukcí
 $F{název}
 hodnoty. Například seznam zboží na faktuře.
 Do sestavy se vkládá jako instance třídy
 zděděné odJRDataSource. JasperReports pak
 seznam těchto hodnot opakuje pro jednotlivé
 řádky sestavy,
- 
Variable – v sestavě se označuje 
 konstrukcí$V{název}. Používá se pro různé
 výpočty prováděné přímo v sestavě.
 Například můžeme sečíst sumu zboží na
 faktuře. JasperReport obsahuje některé
 předdefinované výpočty, pro součet, průměr,
 největší hodnotu, nejmenší hodnotu atd.
Teď se může zdát situace mírně komplikovaná,
                      ale práce se vstupními daty sestavy je vcelku
                      jednoduchá. Vždy potřebujeme provést tuto
                      posloupnost kroků:
- 
V návrháři iReport vytvořit příslušnou 
 proměnnou, pole, či parametr
- 
Použít element TextFieldpro umístění proměnné do
 sestavy na místo, kde se má zobrazit
- 
Při volání tisku z našeho programu vložit 
 příslušná data.
Uvedený postup nejlépe ilustruje příklad.
                      Představme si, že chceme tisknout jednoduchou
                      sestavu s objednávkou zboží. V sestavě chceme
                      zobrazit v titulku (měnitelný) název naší
                      společnosti, následně vypsat objednané zboží s
                      název a cenou a na konci výslednou cenu sečíst.
Nejprve si otevřeme iReport, kde založíme
                      sestavu example2.jrxml. Vložíme si proměnné a
                      parametry, které budeme potřebovat. Potřebujeme
                      jeden parametr “firma”, dvě pole “zbozi”, “cena” a jednu
                      proměnnou “soucet”,
                      které si myší vhodně umístíme do formuláře. Pro
                      vložení těchto políček do sestavy použijeme
                      nástroj “Text field”
                      nebo Textová “položka” v českém překladu iReport. Na následujícím
                      obrázku je nástroj naznačen číslem “1”.

Užitím tohoto nástroje vložíme postupně políčka
                      $P{firma}, $F{zbozi}, $F{cena}, $V{soucet}, což odpovídá
                      pravidlům uvedeným výše. K inspiraci může
                      posloužit následující obrázek

Následně u každé položky potřebujeme nastavit
                      některé další vlastnosti. Zejména jaký datový typ
                      bude zobrazovat. To provedeme stisknutím pravého
                      tlačítka myši na políčku a z kontextového menu
                      vybereme vlastnosti. Následně na záložce TextField nastavíme
                      příslušný datový typ. U položek $P{firma} a $F{zbozi} můžeme ponechat
                      implicitní typ String. U políček $P{cena}
                      a $V{soucet}
                      nastavíme pro jednoduchost typ Interger.

Tím máme navrhnutou sestavu, kde bude která
                      hodnota zobrazena a jaký datový typ se bude
                      zobrazovat. Jak je vidět, report je rozdělen na
                      několik sekcí. Prozatím nastavme, že informace o
                      zboží budou v části “detail”, název firmy v části “title” a součet v části
                      “summary”. To
                      protože část “title”
                      a “sumary” se
                      zobrazuje pouze na první respektive poslední
                      stránce. Naopak část “detail” je určena pro opakující se
                      hodnoty, které JasperReports opakuje jako řádky
                      sestavy.
Protože takto jsme si pouze vymezili, kde se
                      budou naše hodnoty zobrazovat, musíme ještě
                      příslušné proměnné vytvořit. To uděláme ikonou z
                      nástrojové lišty označenou číslem 2 na obrázku
                      výše. V okně, které se nám otevře můžeme vidět
                      tři záložky: Fields, Parametrs, Variables, které
                      odpovídají jednotlivým typům dat sestavy. Zde
                      vytvoříme odpovídající parametr (Parameters)
                      “firma”, pole
                      (Fields) “zbozi” a
                      “cena” a naposledy
                      proměnnou (Variables) “soucet”. U součtu nastavíme, že proměnná
                      má sčítat hodnotu “cena” v celém reportu, viz následující
                      obrázek:

Jak je vidět, nastavili jsme pro výpočet typ
                      “sum” a výraz $F{cena}, což způsobí
                      součet cen v celém reportu.
Nyní můžeme přistoupit k tvorbě programu,
                      kterým vytvoříme sestavu. Předpokládejme, že
                      zboží objednávky ukládáme v objektu JavaBean
                      (Uveďme, že JavaBean je třída obsahující sadu
                      instančních proměnných a k nim příslušné get a
                      set metody) podle uvedeného kódu:
package jasperbook.example2;
public class Obchod {
private String zbozi;
private int cena;
public Obchod() {
}
public Obchod(String zbozi, int cena) {
this.zbozi = zbozi;
this.cena = cena;
}
public int getCena() {
return cena;
}
public void setCena(int cena) {
this.cena = cena;
}
public String getZbozi() {
return zbozi;
}
public void setZbozi(String zbozi) {
this.zbozi = zbozi;
}
public Object[] toArray() {
Object[] result = new Object[2];
result[0] = cena;
result[1] = zbozi;
return result;
}
}
To že jsme zvolili uložení hodnot v JavaBeanu
                      není náhoda. Jak již bylo uvedeno výše, data
                      vkládaná do sestavy jsou potomky objektu JRDataSource. Jeden z
                      potomků se jmenuje JRBeanCollectionDataSource a umožňuje
                      právě vkládat kolekce JavaBeanů jako datový zdroj
                      sestavy. Obslužný program naší sestavy pak může
                      vypadat takto:
// Potřebujeme Mapu s parametry sestavy
Map<String, Object> params = new HashMap<String, Object>();
params.put("firma", "Nekupto");
List<Obchod> obchod = new ArrayList<Obchod>();
obchod.add( new Obchod("Pračka", 5000) );
obchod.add( new Obchod("Chladnička", 6000) );
obchod.add( new Obchod("Žehlička", 780) );
obchod.add( new Obchod("Sporák", 12000) );
JasperReport jr = JasperCompileManager.compileReport(
"reports/example2.jrxml");
JasperPrint jp = JasperFillManager.fillReport(jr,
params, // Vložíme parametry sestavy
// Vložíme datový zdroj
new JRBeanCollectionDataSource(obchod));
JasperPrintManager.printReport(jp, true);
Jak je vidět, vytvořili jsme si mapu s jedním
                      klíčem, který je stejně pojmenovaný jako parametr
                      v sestavě (tedy “firma”). Tuto mapu potom vkládáme jako parametry
                      sestavy. Následně jsme vytvořili pole se čtyřmi
                      objekty typu zboží, které se vložili jako data do
                      sestavy. Objekt Obchod je napsán podle konvencí
                      JavaBean, proto sestava “pozná”, že metodou getZbozi() ziská pole ($F{...}) zbozi a metodou
                      getCena() pole ($F{...}) cena. Poté už
                      pouze naskládá do řádků všechny položky předaného
                      seznamu.
Po spuštení programu získáme následující
                      výsledek:

V předchozí kapitole jsme si ukázali, jak
                    vytvořit jednoduchou sestavu v JasperReports. Jak
                    je vidět, sestava by potřebovla pouze mírně
                    vylepšit a již by byla použitelná pro reálnou
                    aplikaci. V této kapitole si popíšeme podrobně jak
                    probíhá celý proces tisku od napsání .jrxml šablony až po
                    generování výstupu. Zejména se zaměříme na metody z
                    API JasperReports, které používáme pro jednotlivé
                    kroky procesu.
Než popíšeme podrobně možnosti tisku, uveďme
                    obrázek, ilustrující kompletně proces generování
                    sestavy. Z obrázku lze vyčíst, že před tiskem je
                    třeba sestavu zkompilovat, vložit datový zdroj a
                    parametry. Následně je možné generovat sestavu.
                    Jednotlivé kroky budou popsány v následujíich
                    kapitolách

Jak bylo zmíněno výše, naši sestavu musíme po
                      vytvoření zkompilovat. V JasperReports máme
                      několik možností, jak toho dosáhnout, přičemž v
                      různých situacích využijeme různé způsoby.
                      Zejména nás bude zajímat, zda sestavu chceme
                      kompilovat před spuštěním programu, nebo za běhu
                      programu.
Ke kompilaci sestavy za běhu programu využijeme
                      třídu
JasperCompileManager
Definovanou v balíku
net.sf.jasperreports.engine
Třída obsahuje celou řadu metod pro kompilaci.
                      Nejčastěji však asi využijeme kompilaci ze
                      zdrojového .jrxml
                      souboru do objektu JasperReport, se kterým dále
                      pracujeme.
JasperReport jreport =
JasperCompileManager.compileReport("soubor.jrxml");
Někdy se může hodit zkompilovat šablonu do
                      souboru na disk.
JasperCompileManager.compileReportToFile("soubor.jrxml"); 
// vytovří soubor "report_name.jasper"
JasperCompileManager.compileReportToFile("soubor.jrxml", "soubor2.jasper"); 
// vytovří soubor "soubor2.jasper"
U prvního příkazu je dobré si všimnout, že
                      výsledný soubor se bude jmenovat stejně jako
                      sestava (nikoliv jako jméno souboru ze šablonou).
                      Jméno reportu nastavujeme při jeho vytváření,
                      nebo později z menu Úpravy / Nastavení reportu v
                      návrháři iReport.
Některé další modifikace kompilačních metod lze
                      dohledat v JavaDoc.
Pokud z nějakého důvodu potřebujeme kompilovat
                      sestavu předem, máme celkem dvě možnosti. Sestavu
                      přímo zkompilujeme z návrháře iReport z menu
                      Sestavit / Kompilovat, nebo ikonou z nástrojové
                      lišty. V tomto případě nám iReport vytvoří soubor
                      .jasper
                      pojmenovaný stejně jako .jrxml šablona. Výhodné také je, že
                      iReport zobrazí případné chyby v sestavě (např.
                      nesprávné datové typy, nebo použití
                      neexistujících proměnných). Při tvorbě nové
                      sestavy využijeme s výhodou tuto možnost pro
                      ladění, neboť se často stane, že některé proměnné
                      přiřadíme nesprávný datový typ, či ji zapomeneme
                      definovat.
Pochopitelně můžeme metody z API libovolně
                      kombinovat. Pro inspiraci uvedeme následující
                      kód, který kompiluje šablonu v souboru pouze
                      pokud kompilovaná verze neexistuje a nebo je
                      staršího data.
public static String compile(File sourceFile, File compFile)
throws JRException {
// Pokud zkompilovaný soubor neexistuje,
// Nebo je starší než zdrojový,
// zkompiluj. Jinak použij již zkompilovaný
if (!compFile.exists() ||
compFile.lastModified() < sourceFile.lastModified()) {
JasperCompileManager.compileReportToFile(sourceFile.getPath(),
compFile.getPath());
}
return compFile.getPath();
}
Uvedený kód v našem programu zajistí, že se
                      soubor zkompiluje kdykoliv je šablona
                      aktualizována aniž bychom museli program
                      restartovat. A naopak není zbytečně kompilována
                      při každém volání tisku a běh programu tím
                      zbytečně nezpomaluje.
Pokud chceme mít jistotu, že máme k aktuální
                      verzi našeho programu zkompilovanou poslední
                      verzi sestavy, máme možnost využít task utility
                      ANT, kterým si sestavu zkompilujeme. Podrobnosti
                      k utilitě ANT lze nalézt v její dokumentaci.
                      Potřebný task je definován v balíku:
net.sf.jasperreports.ant
kde nalezneme třídu:
JRAntCompileTask
Následně můžeme vytvořit naší úlohu pro
                      kompilaci v souboru build.xml například takto:
<taskdef name="jrc"
classname="net.sf.jasperreports.ant.JRAntCompileTask">
<classpath>
<fileset dir="/lib">
<include name="**/*.jar"/>
</fileset>
</classpath>
</taskdef>
<target name="-pre-compile">
<mkdir dir="${basedir}/reports"/>
<jrc srcdir="${basedir}/reports"
destdir="${basedir}/reports" >
<include name="**/*.jrxml"/>
</jrc>
</target>
V první části ukázky si vytvoříme nový task
                      pojmenovaný “jrc”,
                      který následně voláme pro kompilaci sestavy.
V sestavě, kterou jsme již vytvořili, jsme si
                      předvedli, jak vložit datový zdroj sestavy.
                      Přičemž jsme využili JRBeanCollectionDataSource, což je jeden
                      ze zástupců datových zdrojů v JasperReports.
Jako první upřesníme, jak fungují datové zdroje
                      sestavy. Datový zdroj vždy představuje seznam
                      nějakých hodnot. Může se jednat o kolekci, či
                      pole, nebo třeba databázovou tabulku. My pak v
                      sestavě určujeme, jak se zobrazí jeden řádek a
                      JasperReports vytiskne tolik řádek, kolik jich je
                      ve zdroji.
Datové zdroje jsou v JasperReports definovány v
                      balíku:
net.sf.jasperreports.engine
a jejich základem je interface
JRDataSource
Pokud chceme, můžeme uvedené rozhraní
                      implementovat a vytvořit si vlastní datový zdroj.
                      V JasperReports API však existuje mnoho tříd
                      implementujících zmíněné rozhraní, s kterými si
                      jistě dlouhou dobu vystačíme. K nejzajímavějším
                      implementacím patří následují (ovšem v JavaDoc
                      lze najít i další):
Často používaný datový zdroj, který přebírá
                      jako parametr pole tříd splňujících konvence
                      JavaBean
JRBeanArrayDataSource(java.lang.Object[] beanArray)
Podobný datový zdroj jako předchozí, ovšem
                      místo pole přebírá kolekci (java.util.Collection) JavaBeanů
JRBeanCollectionDataSource(java.util.Collection beanCollection)
Následující datový zdroj je důležitý, pokud
                      vytváříme “statickou” sestavu. Tedy sestavu s pouze grafickými prvky
                      a případně s několika parametry. Potom se totiž
                      nabízí předpoklad, že sestava bez dat nepotřebuje
                      datový zdroj. Pokud bychom namísto datového
                      zdroje poslali hodnotu null, vytiskne se prázdný list, což je
                      chyba, která se špatně hledá. Proto, pokud
                      tiskneme prázdnou sestavu, musíme vložit
                      následující prázdný datový zdroj:
JREmptyDataSource()
Často náš program pracuje s daty z databáze,
                      která můžeme přímo poslat do sestavy jako objekt
                      java.sql.ResultSet
                      (což je objekt získaný jako výsledek SQL dotazu
                      přes rozhraní JDBC) následujícím způsobem:
JRResultSetDataSource(java.sql.ResultSet rs)
U desktopové aplikace často zobrazujeme data v
                      objektu JTable, jenž
                      využívá model javax.swing.table.TableModel. Tisk
                      takových dat je stejně snadný, neboť existuje
                      datový zdroj, který pracuje přímo s modelem
                      tabulky:
JRTableModelDataSource(javax.swing.table.TableModel model)
V návrháři iReport, lze v menu “Data” nalézt volbu “Dotaz reportu”. V tomto
                      menu, můžeme nastavit datový zdroj přímo v
                      sestavě. Například můžeme vložit přímo SQL dotaz,
                      který naplní data sestavy. Tuto možnost však
                      nedoporučuji příliš používat ve větších
                      aplikacích, neboť ztratíme návaznost mezi
                      aplikací a sestavou. Lepší se jeví vkládat datové
                      zdroje z aplikace a případné změny v aplikaci se
                      snadněji přenesou i do sestav.
Po zkompilování sestavy a před tiskem
                      potřebujeme vložit do sestavy datový zdroj a
                      parametry. Jak již bylo zmíněno, datový zdroj
                      obsahuje jednotlivé řádky sestavy. Parametry
                      představují nějaké dodatečné informace, které
                      potřebujeme přenést na tiskový výstup. Jak bylo
                      zmíněno v předchozí kapitole, datový zdroj je
                      objekt zděděný od třídy JRDataSource. Parametry představuje
                      objekt java.util.Map,
                      kde vkladáme dovjice <String, Object> s významem [název
                      parametru, hodnota parametru]
K vyplnění sestavy parametry a datovým zdrojem
                      využíváme třídu
JasperFillManager
z balíku
net.sf.jasperreports.engine
V dokumentaci projektu JasperReport lze nalézt
                      různé modifikace metody fillReport(), která realizuje naplnění
                      sestavy daty. Mezi základní bezesporu patří
                      následující:
fillReport(JasperReport jasperReport, java.util.Map parameters,
JRDataSource dataSource)
fillReport(java.io.InputStream inputStream, java.util.Map parameters,
JRDataSource dataSource)
fillReportToFile(JasperReport jasperReport,
java.lang.String destFileName, java.util.Map parameters,
JRDataSource dataSource)
JasperReports obsahuje poměrně bohaté API pro
                      různé tiskové výstupy. Neomezuje se pouze na
                      výstup na tiskárnu, ale umožňuje produkovat i
                      další formáty.
Třídy pro tisk nalezneme v balíku
net.sf.jasperreports.engine
Výstup na tiskárnu zajišťuje třída
JasperPrintManager
ve které nalezneme metody tisknoucí buď celý
                      dokument, nebo jeho jednotlivé stránky. Zde
                      uvedeme přehled základních metod:
Následující tři metody tisknou celou sestavu ze
                      vstupního proudu, z objektu JasperPrint a nebo ze
                      souboru na disku.
printReport(java.io.InputStream inputStream, boolean withPrintDialog)
printReport(JasperPrint jasperPrint, boolean withPrintDialog)
printReport(java.lang.String sourceFileName, boolean withPrintDialog)
Obdobně můžeme tisknout pouze konkrétní stránku
                      sestavy, kde zadáváme jako parametr číslo stránky
printPage(java.io.InputStream inputStream, int pageIndex,
boolean withPrintDialog)
printPage(JasperPrint jasperPrint, int pageIndex,
boolean withPrintDialog)
printPage(java.lang.String sourceFileName, int pageIndex,
boolean withPrintDialog)
Nebo můžeme tisknout sekvenci stránek zadáním
                      počáteční a koncové stránky
printPages(java.io.InputStream inputStream, int firstPageIndex,
int lastPageIndex, boolean withPrintDialog)
printPages(JasperPrint jasperPrint, int firstPageIndex,
int lastPageIndex, boolean withPrintDialog)
printPages(java.lang.String sourceFileName, int firstPageIndex,
int lastPageIndex, boolean withPrintDialog)
Jelikož se JasperReports neomezuje pouze na
                      výstup na tiskárnu, můžeme nalézt metody pro
                      výstup do HTML či PDF a to ve třídě
JasperExportManager
K dispozici máme metody pro tisk do HTML
exportReportToHtmlFile(JasperPrint jasperPrint, java.lang.String destFileName)
exportReportToHtmlFile(java.lang.String sourceFileName)
exportReportToHtmlFile(java.lang.String sourceFileName, java.lang.String destFileName)
tisk do PDF
exportReportToPdf(JasperPrint jasperPrint)
exportReportToPdfFile(JasperPrint jasperPrint, java.lang.String destFileName)
exportReportToPdfFile(java.lang.String sourceFileName)
exportReportToPdfFile(java.lang.String sourceFileName, java.lang.String destFileName)
exportReportToPdfStream(java.io.InputStream inputStream, java.io.OutputStream outputStream)
exportReportToPdfStream(JasperPrint jasperPrint, java.io.OutputStream outputStream)
V předchozích kapitolách jsme si ukázali různé
                      možnosti kompilace, vytvoření datového zdroje a
                      tiskové výstupy. V této kapitole si prakticky
                      ukážeme, jak používat zmíněné metody. Uvedeme
                      postupně všechny kroky, jak následovali za sebou
                      v předchozích kapitolách. K výstupu využijeme
                      soubor example3.jrxml, který jsme již vytvořili
                      dříve.
Uvedeme různé varianty metod, které lze podle
                      potřeby kombinovat.
Jako první ukažme kompilaci. Uvedeme příkazy
                      pro kompilaci do objektu JasperReport a do
                      souboru .jasper.
                      Příklady jsou ilustrační, v praxi pochopitelně
                      zvolíme jenom jednu volbu.
//kompilace do objektu JasperReport
JasperReport jreport = JasperCompileManager.compileReport(
"reports/example3.jrxml");
//kompilace do souboru. Výsledný soubor má jméno shodné
//se jménem reportu
JasperCompileManager.compileReportToFile("reports/example3.jrxml");
// kompilace do jiného souboru
JasperCompileManager.compileReportToFile("reports/example3.jrxml",
"reports/compiled3.jasper");
Následně si vytvoříme datový zdroj. Přeskočíme
                      JRCollectionBeanDataSource, neboť byl
                      použit v kapitole 3.3 Sestava s daty. Dále
                      přeskočíme JREmptyDataSource, neboť jeho použití je
                      zřejmé.
V dalším textu předpokládejme, že máme k
                      dispozici následují dvě metody vracející kolekci
                      a pole objektů zboží:
List<Obchod> obchodCollection();
Obchod[] obchodArray()
Datový zdroj pro pole JavaBeanů získáme
                      následujícím voláním:
JRDataSource jrsource = new JRBeanArrayDataSource(obchodArray());
Dále si ukážeme jak získat datový zdroj z
                      databáze. Příklad bude pouze ilustrativní, neboť
                      k funkční verzi bychom potřebovali ovladač k
                      databázi, nainstalovaný databázový systém a
                      vytvořenou tabulku zboží. Doufejme, že pro
                      čtenáře, který je seznámen s prací s databázemi v
                      Javě, bude ukázka dostatečně ilustrativní, aby
                      byl schopen podle ní vytvořit funkční kód.
                      Ostatní odkažme na další literaturu, kde lze
                      dohledat podrobnosti práce s databázemi v Javě.
Tento datový zdroj předpokládá, že položky
                      $F{...} v sestavě
                      budou pojmenovány stejně jako sloupečky v tabulce
                      v databázi.
// Datový zdroj z objektu ResultSet
Connection con = ...; //V reálné aplikaci napojení na databázi
Statement stm = con.createStatement();
ResultSet rs = stm.executeQuery("Select * from obchod");
JRDataSource jrsource = new JRResultSetDataSource(rs);
Nakonec si ukážeme jak využít data z tabulky
                      JTable.
                      Předpokládejme použití základního DefaultTableModel modelu.
Nejprve si mírně upravíme třídu Obchod, abychom mohli
                      získat její atributy jako pole, doplněním metody:
    public Object[] toArray() {
        Object[] result = new Object[2];
        result[0] = cena;
        result[1] = zbozi;
        return result;
    }
Následně již vytvoříme objekt DefaultTableModel
DefaultTableModel model = new DefaultTableModel( new Object[] {"zbozi", "cena"}, 0);
for (Obchod zbozi: zboziCollection()) {
    model.addRow(zbozi.toArray());
}
jrsource = new JRTableModelDataSource(model);
Vytvořený model jednoduše využijeme pro
                      přípravu datového zdroje. Tento datový zdroj
                      předpokládá, že položky $F{...} se budou jmenovat podle sloupců
                      tabulky.
jrsource = new JRTableModelDataSource(model);
Po zkompilování sestavy a připravení datového
                      zdroje se dostáváme k naplnění sestavy parametry.
                      Tato operace je opravdu jednoduchá. Nejprve si
                      však připravme pomocnou metodu pro parametry
                      sestavy:
    public Map<String, Object> params() {
        //Naplnění daty
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("firma", "Nekupto");
        return params;
    }
Nyní naplníme data
// Vyplnění a uložení do objektu JasperPrint
JasperPrint jprint = JasperFillManager.fillReport(jreport, params(), jrsource);
// Vyplnění sestavy a uložení do souboru
JasperFillManager.fillReportToFile(jreport, "reports/filled.dat", params(), jrsource);
Jako poslední můžeme sestavu tisknout. Výstup
                      může být do různých formátu. Jako vstup využijeme
                      objekt JasperPrint,
                      nebo vygenerovaný soubor filled.dat.
Nyní máme vše připravené no pro tisk a můžeme
                      si ukázat několik různých možností, jak tisknout
                      do různých formátů. Začněme výstupem na tiskárnu:
//Různé spůsoby tisku celého dokumentu
JasperPrintManager.printReport(jprint, true);
// Tisk pouze první stránky (stránky jsou číslovány od nuly
JasperPrintManager.printPages(jprint, 0, 0, true);
// Tisk pouze jedné stránky
JasperPrintManager.printPage(jprint, 0, true);
Následuje ukázka, jak vytisknout sestavu do
                      HTML souboru. Po otevření výsledné HTML stránky
                      budeme zřejmě mírně zklamáni, neboť grafika
                      (zejména obrázek nákupního košíku) nedopadla
                      dobře. S tím však bohužel nic neuděláme a musíme
                      se spokojit s konstatováním, že JasperReports
                      (alespoň současná verze) špatně exportuje grafiku
                      do HTML formátu.
//Tisk do HTML
JasperExportManager.exportReportToHtmlFile(jprint,
"reports/example3.html");
Jako poslední si ukážeme jak jednoduše
                      exportovat do PDF souboru
//Tisk do PDF
JasperExportManager.exportReportToPdfFile(jprint,
"reports/example3.pdf");
Při tvorbě naší první sestavy si bylo možné
                      všimnout, že iReport zobrazuje stránku rozdělenou
                      na několik sekcí. Význam některých je možné
                      intuitivně odhadnout z názvu, avšak je dobré znát
                      jejich přesný význam.
Nejprve si povíme něco málo o nastavení
                      jednotlivých částí sestavy. Konfiguraci sekcí
                      vyvoláme z menu Pohled / Sekce, případně z
                      nástrojové lišty ikonou Sekce a nebo z
                      kontextového menu kliknutím pravým tlačítkem myši
                      kdekoliv v sestavě a výběrem Vlastnosti sekcí.
                      Otevře se nám dialogové okno

V dialogovém okně nalezneme všechny sekce
                      sestavy. Můžeme nastavit číselně výšku (Band
                      Height), zda se může rozdělit při přechodu na
                      další stránku (Split allowed) a nakonec můžeme
                      definovat za jakých okolností se vytiskne
                      (podotkněme, že implicitně se sekce tisknou
                      vždy). Pokud chceme, vložíme do okénka libovolnou
                      podmínku zapsanou v jazyce Java, která musí
                      vracet hodnotu Boolean. Na základě jejího
                      vyhodnocení se daná sekce vytiskne, nebo
                      nevytiskne. Zde poznamenejme, že JasperReports
                      skutečně umí vyhodnocovat pouze objekty a nikoliv
                      primitivní datové typy. Proto následující
                      podmínka je pro JasperReports chybná
$P{text}.equals("Jasper Reports"); 
// vrací true, nebo false - primitivní datové typy
neboť vrací primitivní datový typ. Problém
                      jednodušše napravíme vytvořením objektu
new Boolean($P{text}.equals("Jasper Reports")); // v pořádku
Dále si také všimněme, že můžeme kombinovat
                      konstrukce jazyka Java s proměnnými
                      JasperReports. Proto jsou uvedené texty možné.
Nyní se již můžeme podívat na konkrétní význam
                      jednotlivých sekcí a zejména na to, kdy a kde se
                      tisknou
- 
title – titulek stránky. Pokud je sestava 
 dlouhá na více stránek, zobrazuje se pouze
 na první.
- 
pageHeader – hlavička stránky. Zobrazuje 
 se vždy na vrchu každé stránky.
- 
columnHeader – hlavička sloupečků 
 tabulky. Bezprostředně obaluje sekci
 detail.
- 
detail – sekce sestavy, kam umísťujeme 
 hlavní obsah. Používá se pro zobrazení
 datové zdroje, neboť jako jediná umí
 vytvořit řádky pro hodnoty datového zdroje,
 které následně tiskne.
- 
columnFooter – patička sloupců sestavy. 
- 
pageFooter – patička stránky. 
- 
lastPageFooter – patička poslední stránky 
 sestavy. Zobrazuje se vždy pouze na
 poslední stránce. Důležitá je jedna její
 vlastnost. Pokud je tato sekce zobrazena,
 pageFooter se na poslední stránce nezobrazí
 na což je třeba myslet při návrhu.
- 
summary – sekce používaná pro závěrečné 
 součty, či shrnutí. Zobrazuje se pouze na
 poslední stránce sestavy. Přestože je
 uvedená v iReport až jako úplně poslední,
 na sestavě se zobrazí před columnFooter.
 Sekce se zobrazí bezprostředně za místem,
 kde končí tisk.
Pro ilustraci si vylepšíme šablonu z našeho
                      předchozího příkladu. Nová sestava může vypadat
                      například takto:

Využili jsme všechny sekce reportu. Stejným
                      programem jako v předchozím příkladu vytiskneme a
                      získáme následující výstup.

Dostali jsme očekávaný výsledek. V obrázku si
                      všimneme, že opravdu sekce pageFooter chybí,
                      neboť se místo ní zobrazila lastPageFooter. A
                      část sumary se zobrazila ihned za koncem
                      tiskového výstupu v sekci detail.
Pokud jsme tiskli předchozí ukázky do formátu
                      PDF, pravděpodobně se chybně zobrazila slova s
                      diakritikou. Tento problém nastává proto, že v
                      sestavě je vždy nutné explicitně uvést, v jakém
                      kódování se má tisknout do PDF, přičemž defaultní
                      nastavení je CP1252.
Nastavení provedeme ve vlastnostech textového
                      políčka v návrháři iReport. Pravým tlačítkem myši
                      nad textovým políčkem vybereme z kontextového
                      menu “Vlastnosti”.
                      Na záložce “Font”
                      dole nalezneme volbu “PDF
                      encoding”. Nastavením volby “CP1250 (Central European)”
                      zajistíme výstup v českém kódování.

V mnoha případech se může stát, že chceme
                      položky v sestavě seskupit podle nějakého
                      kritéria. To JasperReport a návrhář iReport
                      umožňuje. K těmto účelům lze nalézt v menu
                      návrháře položku Pohled / Skupiny reportu.
                      Alternativně lze stejnou volbu vyvolat z
                      nástrojové lišty. V dialogovém okně můžeme
                      vytvořit potřebný počet skupin a nastavit různé
                      vlastnosti.
Ukažme si na jednoduchém příkladu, jak pracovat
                      se skupinami. Dejme tomu, že chceme u zboží na
                      výdejce uvádět skupinu DPH a navíc spočítat cenu
                      za celou skupinu.
Ještě je třeba zdůraznit, že pokud chceme
                      správné rozdělení do skupin, musí data do sestavy
                      přijít seřazená. Jak bude uvedeno dále, v sestavě
                      vždy uvádíme klíčovou hodnotu, která bude
                      definovat skupinu. JasperReport potom postupně
                      vypisuje řádky sestavy a pokud se změní ona
                      klíčová hodnota, vytvoří novou skupinu. O
                      vytvoření nové skupiny tedy rozhoduje pouze změna
                      klíčové hodnoty z řádku na řádek. JasperReports
                      není schopen řádky zpětně přeuspořádat, čili
                      musíme data předem seřadit sami.
Jako první si vytvoříme rozšířenou třídu
                      původní třídy Obchod,
                      která bude uchovávat i DPH. Třídu doplníme navíc
                      o komparátor porovnávající DPH. Klíčová hodnota
                      pro rozdělení do skupin bude tedy DPH a jak již
                      bylo řečeno, musíme data podle této hodnoty
                      předem seřadit.
public class ObchodDph extends Obchod implements Comparable<ObchodDph> {
    private int dph;
    public ObchodDph(String name, int cena, int dph) {
        super(name, cena);
        this.dph = dph;
    }
    public ObchodDph() {
    }
    public int getDph() {
        return dph;
    }
    public void setDph(int dph) {
        this.dph = dph;
    }
    public int compareTo(ObchodDph o) {
        return dph - o.getDph();
    }
}
Program pro tisk zde již neuvedeme celý, neboť
                      by se jednalo o opis již dříve uvedeného. Budeme
                      pouze potřebovat vytvořit několik testovacích
                      dat, data seřadit a vytisknout stejně jako
                      předchozí ukázky.
// testovací data (výpis zkrácen)
List<ObchodDph> obchod = new ArrayList<ObchodDph>();
obchod.add( new ObchodDph("Pračka", 5000, 19) );
obchod.add( new ObchodDph("Chladnička", 6000, 19) );
obchod.add( new ObchodDph("Žehlička", 780, 19) );
obchod.add( new ObchodDph("Sporák", 12000, 19) );
...
// data musíme seřadit
Collections.sort(obchod);
JRDataSource jrsource = new JRBeanCollectionDataSource(obchod);
// metody pro tisk vynechány - stejné jako v předhozích ukázkách
Nyní můžeme otevřít návrhář iReport a
                      zdokonalit předchozí sestavu. Jako první
                      vytvoříme novou položku (field) pro hodnotu DPH,
                      $F{dph}. Následně
                      můžeme vytvořit skupinu pojmenovanou například
                      “dph”. Nezapomeneme
                      vyplnit klíčovou hodnotu, která bude určovat
                      skupinu (Group experession). K dispozici máme
                      ještě několik dalších voleb, jejichž význam by
                      měl být zřejmý z názvu. Viz obrázek

Po potvrzení dialogu se v sestavě objeví dvě
                      nové sekce – dphHeader a dphFooter. Do těchto
                      nových sekcí vložíme hodnotu proměnné $F{dph}, abychom měli
                      přehledně zobrazenu úroveň DPH. Dále vytvoříme
                      proměnnou (variable) $V{dphSoucet}, která sečte cenu za DPH,
                      kterou umístíme do dphFooter. Nastavíme “Calculation Type” na
                      hodnotu “Sum” a
                      “variable expression” na $F{cena}, čímž
                      získáme součet cen. Aby se sčítala pouze hodnota
                      konkrétní skupiny je třeba ještě nastavit “Reset type” pro hodnotu
                      “Skupina” a “Reset group” pro hodnotu
                      “dph”. Tím říkáme,
                      že hodnotu proměnné bude resetovat (nulovat)
                      skupina a konkrétně se bude jednat o skupinu
                      pojmenovanou “dph”
                      (to protože v sestavě můžeme použít více skupin).

Nové hodnoty můžeme do sestavy uspořádat podle
                      následující ukázky.

Spuštěním programu získáme následující
                      výsledek:

Vidíme, že na sestavě se skutečně objevily dvě
                      skupiny DPH pro 5% a 19% se součtem na konci obou
                      skupin.
