Primo articolo su JasperReports, una libreria Java Open Source che consente la generazione dinamica di report a partire da una fonte dati e la successiva renderizzazione in svariati formati, tra i quali PDF e HTML. Esempio pratico di utilizzo.
Introduzione
Nel precedente articolo è stata descritta l‘architettura di JasperReports. In questo vedremo un esempio pratico di utilizzo delle API di tale libreria all‘interno di un‘applicazione Java. Per l‘esempio faremo riferimento, come fonte dati, ad un database Access (per semplicità ; ovviamente il db potrà essere di un vendor diverso da Microsoft) chiamato jasper e contenente una sola tabella, addresses avente cinque campi: id di tipo numerico, firstname, lastname, street e city di tipo testo.
Layout di un report
Ricordando lo schema di principio spiegato nell‘articolo precedente (e riportato per comodità anche in questo in figura 1), la prima cosa da fare è quella di definire il layout dei report che dovrà generare l‘applicazione.
Un layout non è altro che un file XML, con estensione .jrml, e costruito secondo lo schema definito in jasperreport.dtd.
In testa al layout troviamo la dichiarazione della versione dell‘XML e l‘indicazione del DTD adottato.
]>
Il tag root del file sarà
Gli attributi di questo tag sono gli attributi di pagina del report. Un report Jasper è in grado di accettare parametri in ingresso dalla classe Java preposta alla sua generazione. Il tag
Il tag
SELECT * FROM addresses
Quindi, tramite il tag
È possibile definire anche delle variabili tramite il tag
($V{CityNumber} != null)?(new Integer($V{CityNumber}.intValue() + 1)):(new Integer(1))
A questo punto possiamo definire le logiche di raggruppamento dei dati tramite il tag
$F{City} " " + String.valueOf($V{CityNumber}) + ". " + String.valueOf($F{City}) Count : $V{CityGroup_COUNT}
Qualora volessimo uno sfondo personalizzato diverso da quello bianco di default, possiamo utilizzare il tag
"src/jr/test/jr.watermark.gif"
Infine dobbiamo definire il layout delle regioni della pagina titolo, header, dettaglio, footer e sommario, rispettivamente tramite i tag
$P{ReportTitle} ID Name Street $F{Id} $F{FirstName} + " " + $F{LastName} $F{Street} "Page " + String.valueOf($V{PAGE_NUMBER}) + " of" " " + String.valueOf($V{PAGE_NUMBER}) "There were " + String.valueOf($V{REPORT_COUNT}) + " address records on this report."
Codice Java per la generazione di report
La classe Java del nostro esempio preposta alla generazione del report si chiama GeneralTest. Il metodo che esegue tutte le operazioni è createReport:
private int createReport( String[] pStrArgs )
Come parametro in ingresso riceve un array di stringhe. La prima operazione che viene eseguita è la creazione del semicompilato (file .jasper) secondo il template indicato come primo argomento dell‘array pStrArgs:
// compilazione del report (creazione del .jasper a partire dal .jrxml)try{JasperCompileManager.compileReportToFile( pStrArgs[0]);}catch( Exception jre ){System.out.println( "GeneralTest.createReport(): eccezione: " + jre.getMessage() );return -1;}
Il metodo compileReportToFile della classe JasperCompilerManager esegue la compilazione. A questo punto, ricordando la figura 2, abbiamo ottenuto il file .jasper da cui l‘applicazione, in qualsiasi momento, sarà in grado di generare il report Nella nostra classe di esempio la generazione del report avviene subito dopo la creazione del semicompilato, ma nulla ovviamente vieta di eseguire l‘operazione in un secondo momento. Per la generazione del report, il metodo fillReportToFile della classe JasperFillManager ha bisogno di una connessione verso il database da cui recuperare i dati. Il metodo getConnection della nostra classe di esempio crea la connessione:
private Connection getConnection() throws ClassNotFoundException, SQLException{String lStrDriver = "sun.jdbc.odbc.JdbcOdbcDriver";String lStrConnectString = "jdbc:odbc:Jasper";String lStrUser = "";String lStrPassword = "";Class.forName( lStrDriver );Connection lConn = DriverManager.getConnection( lStrConnectString, lStrUser, lStrPassword );return lConn;}Il codice necessario per la creazione del report (file .jrprint) è il seguente:
// passaggio dei parametri al reportMap lParameters = new HashMap();lParameters.put( "ReportTitle", "General test" );lParameters.put( "FilterClause", "" );lParameters.put("OrderClause", "Id" );// creazione della connessione verso il databaseConnection lConnection = getConnection();// creazione del report (file .jrprint)JasperFillManager.fillReportToFile( pStrArgs[1], lParameters, lConnection );
Il primo argomento del metodo fillReportToFile è il nome del file .jprint da creare.
Adesso dobbiamo decidere cosa fare del nostro report. Possiamo visualizzarlo, mandarlo in stampa o salvarlo su file in uno dei formati previsti da JasperReports. Nel nostro esempio viene salvato su un file PDF, grazie al metodo exportReportToPdfFile della classe JasperExportManager:
// export del report in PDFJasperExportManager.exportReportToPdfFile( pStrArgs[2], pStrArgs[3] );
I due argomenti in ingresso al metodo exportReportToPdfFile sono, rispettivamente, il nome del report .jprint e il nome da assegnare al file PDF su cui viene salvato.
Il risultato finale sarà un report come quello mostrato in figura 2:
L‘esempio completo è allegato all‘articolo.
Conclusioni
In questo articolo abbiamo visto quali sono i passi comuni a tutte le operazioni di generazione di report tramite JasperReports e come viene realizzata la perfetta separazione del layout dai dati. Una volta definito un layout, la logica di generazione dei report diventa una operazione meccanica. Nel prossimo ed ultimo articolo vedremo come è possibile implementare un JRDataSource ad hoc per l‘integrazione della libreria con una nostra applicazione e come rendere più agevole la creazione dei layout JRML mediante l‘utilizzo di iReport, una applicazione Open Source basata su JasperReports.
1Teodor Danciu “Documentazione ufficiale di JasperReports”http://jasperreports.sourceforge.net/2http://jasperreports.sourceforge.net/”JasperReports and iReports”