Utilizzare Jasper Reports – Creare report da Java

Utilizzare Jasper ReportNella scorsa puntata con l’aiuto di Maven abbiamo creato la struttura di base di un progetto Java, pre-configurato con le librerie necessarie a Jasper Reports e gli automatismi necessari per compilare i report. In questo appuntamento vedremo quindi come creare i report direttamente dal nostro codice Java.

Il codice Java

Per vedere in azione la compilazione avevamo creato il report src/main/jasperreports/testReport.jrxml, che veniva compilato in target/classes/testReport.jasper. Ricordiamo che i file con estensione .jasper sono dei file binari (ecco perché devono essere compilati), pronti per essere eseguiti; il termine compilazione è usato proprio per questo motivo!

La generazione automatica del progetto dovrebbe aver creato una classe App nella directory src/main/java/it/artera/jr/App.java, e il relativo test JUnit AppTest in src/test/java/it/artera/jr/AppTest.java. Maven infatti promuove appieno le pratiche di sviluppo Agile, ad esempio il Test-Driven Development (TDD), che prevede che vengano scritti prima i test e poi il codice che li fa andare a buon fine. Per questo motivo la fase di test ha un ruolo importante nel ciclo di compilazione-packaging-deploy.

Scriviamo dunque il nostro primo test; aggiungiamo il seguente metodo all’interno della classe AppTest:

public void test_sampleReport() throws Exception {
    // crea l'istanza di App
    App app = new App();
    // esegui il report
    app.sampleReport("target/test/testReport.pdf");
    // controlla che venga scritto il file di output
    assertTrue(new File("target/test/testReport.pdf").exists());
}

Il comando

mvn test

compila i file modificati ed eseguire tutti i test. Se proviamo a lanciarlo, otteniamo un errore:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running it.artera.jr.AppTest
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.028 sec <<< FAILURE!

Results :

Tests in error:
  test_sampleReport(it.artera.jr.AppTest)

Tests run: 1, Failures: 0, Errors: 1, Skipped: 0</pre>
La classe <em>App</em> infatti non ha un metodo <em>sampleReport()</em>. Modifichiamo quindi <em>App</em> in questo modo:
<pre>package it.artera.jr;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import net.sf.jasperreports.engine.JasperRunManager;
import net.sf.jasperreports.engine.data.JRMapCollectionDataSource;

/**
 * Hello world!
 *
 */
public class App {

    public void sampleReport(String outputDir) throws Exception {
        // carica il report compilato
        InputStream is = getClass().getResourceAsStream("/testReport.jasper");

        // imposta directory e file di output
        File outDir = new File(outputDir);
        outDir.mkdirs();
        OutputStream os = new FileOutputStream(new File(outDir, "testReport.pdf"));

        // crea una java.util.Collection contenente dei dati
        Collection data = createSampleData();
        // la avvolge in un'implementazione di JRDataSource
        JRMapCollectionDataSource dataSource = new JRMapCollectionDataSource(data);

        JasperRunManager.runReportToPdfStream(is, os, null, dataSource);
    }

    private Collection createSampleData() {
        Map row;
        Collection data = new ArrayList();

        row = new HashMap();
        row.put("name", "Lorem");
        data.add(row);

        row = new HashMap();
        row.put("name", "Ipsum");
        data.add(row);

        row = new HashMap();
        row.put("name", "Docet");
        data.add(row);

        return data;
    }
}

Vi ricordate il report di prova? Aveva solamente un campo chiamato name. Nel codice qui sopra vediamo come ai report Jasper sia possibile passare una qualsiasi collezione di dati, purché correttamente inizializzata, ed essi verranno correttamente formattati senza doversi preoccupare della loro provenienza!
In questo caso la Collection fornita dal metodo createSampleData() viene avvolta (wrapped) in un oggetto JRMapCollectionDataSource; questa classe implementa l’interfaccia net.sf.jasperreports.engine.JRDataSource, il cui scopo è fare da tramite fra i report e i dati. Molto comodo!

Rilanciamo il comando

mvn test

A questo punto otterremo una schermata simile a questa:

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running it.artera.jr.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.812 sec

Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------

Il report

Andando a controllare nella directory target/test scopriamo che c’è un file testReport.pdf: il nostro primo report!

Linkografia