JASPER REPORT: CREAZIONE DI PDF IN JAVA
JasperReports è una libreria Open Source scritta interamente in linguaggio Java che consente la generazione dinamica di report a partire da una fonte dati e la successiva renderizzazione in diversi formati, tra i quali PDF, HTML e XML.
Il processo di generazione di un report mediante Jasper consta di tre step:
- definizione della struttura e del layout del report sotto forma di file jrxml;
- compilazione del file jrxml e generazione di un file jasper;
- rendering del file jasper mediante la libreria Jasper Reports.
Come esempio, simuleremo la creazione di un report indicante la lista di calciatori acquistati al Fantacalcio 2023/2024 con relativo dettaglio del costo d'acquisto e del ruolo. Tale report verrà generato a seguito dell'invocazione di una rest API all'interno di un'applicazione scritta in Java con l'utilizzo del framework Spring.
Il punto di partenza, neanche a dirlo, è Spring Initializr: aggiungiamo le due dipendenze necessarie al progetto, ossia la componente web del framework ed appunto Jasper:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>6.20.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
A questo punto provvediamo alla creazione di un controller REST del tipo:
package com.soa.reports.controller;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.soa.reports.model.Player;
import com.soa.reports.model.Team;
import lombok.extern.slf4j.Slf4j;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
@Slf4j
@RestController
public class PlayerController {
@GetMapping("/players/report")
public ResponseEntity<Void> generateReport() {
try {
Player p1 = new Player(1, "Victor Oshimen", "Forward", 150d);
Player p2 = new Player(2, "Diego Demme", "Midfielder", 10d);
Player p3 = new Player(3, "Rafael Leao", "Forward", 300d);
List<Player> players = Arrays.asList(p1,p2,p3);
var team = Team.builder().name("SempreSoloForzaNapoli").playersData(players).build();
JRBeanCollectionDataSource beanColDataSource = new JRBeanCollectionDataSource(List.of(team));
JasperPrint report =
JasperFillManager.fillReport
(
JasperCompileManager.compileReport(
ResourceUtils.getFile("classpath:players-details.jrxml")
.getAbsolutePath()) // path of the jasper report
, new HashMap<>() // dynamic parameters
, beanColDataSource
);
HttpHeaders headers = new HttpHeaders();
//set the PDF format
headers.setContentType(MediaType.APPLICATION_PDF);
headers.setContentDispositionFormData("filename", "rosa-fantacalcio.pdf");
//create the report in PDF format
return new ResponseEntity
(JasperExportManager.exportReportToPdf(report), headers, HttpStatus.OK);
} catch(Exception e) {
log.error("Impossible to generate report. Error: {}", e.getMessage(),e);
return new ResponseEntity<Void>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
Il codice sopra esposto è molto semplice: nell'HTTP response stiamo iniettando il report - generato con il metodo exportReportToPdf - sulla base delle informazioni date in input al metodo fillReport.
Jasper è in grado di ricevere due tipi di dato: i parametri, indicati con $P, e i campi o field contrassegnati da $F. Sia i primi che i secondi, necessitano di essere tipizzati: essendo Jasper un prodotto scritto in Java, sarà possibile lavorare su tutti i tipi primitivi di tale linguaggio e gestire oggetti complessi attraverso subreport, tabelle ed altri elementi.
Arrivati a questo punto, abbiamo bisogno di una classe che "modelli" il calciatore della nostra squadra. Supponendo che a noi interessi unicamente il nome, il ruolo ed il costo al quale lo abbiamo acquistato, l'entità avrà la seguente struttura:
package com.soa.reports.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Player {
private int id;
private String name;
private String role;
private double price;
}
Tuttavia, oltre alla lista di giocatori, vogliamo fornire anche un nome al nostro team; motivo il quale cui, creiamo una classe wrapper contenente le seguenti informazioni:
package com.soa.reports.model;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Team {
private String name;
private List<Player> playersData;
}
Per la generazione del template jasper, utilizzeremo l'IDE Jasper Studio. Dopo averlo installato, procediamo alla creazione di un nuovo blank template.
L'obiettivo è mostrare la lista di calciatori all'interno di una tabella, sicché, dalla palette degli elementi di base trasciniamo suddetto elemento all'interno della sezione Dettaglio. Questa sezione rappresenta il fulcro dell'intero report ed ha la caratteristica - non utile nel nostro esempio - di ripetersi per ogni elemento della pagina.
Altre al Dettaglio, l'altra sezione che ci interessa è il titolo al quale andremo ad aggiungere l'elemento titolo sempre con il solito meccanismo del drag and drop; fatto ciò, dobbiamo fornire a Jasper dettagli sui parametri che il backend sta inviando per la generazione del report. In particolare, se ritorniamo al metodo generateReport del controller Rest, è possibile vedere che il datasource fornito in ingresso è una lista di oggetti Team, dove ognuno di essi è caratterizzato dai seguenti due attributi:
- name, di tipo stringa
- playersData, di tipo java.util.List
Per poter creare questi due campi in Jasper, così come il dettaglio della struttura tabellare e le modalità con cui i dati vengono passati dal report principale alla tabella, ritengo sia meglio fornire un video a supporto:
Fatto ciò, non ci resta altro che salvare il template e trasferirlo sotto la folder resources della nostra applicazione Spring.
Invocando l'endpoint http://localhost:8080/players/report, otterremo in output un pdf del tipo:
Trovi il codice sorgente completo di quest'articolo al seguente link:
Comments
Post a Comment