Sous Rapport avec Jasper et Ireport
Par Eric le mercredi 3 décembre 2008, 11:02 - Jasper - Lien permanent
Présentation
Cet article montre comment créer un rapport à trois niveaux de maitre détail
en java. On utilisera exclusivement jasper et java sans utiliser la moindre
ligne SQL pour générer les rapports. Il sera intéressant de voir ici deux
techniques pour passer des listes de détails de manière différentes aux sous
rapports. Soit en implémentant directement l'interface JRDataSource,
soit en créant de simple collection et en configurant dans Ireport le passage
des listes en paramètre.
Le rapport que nous allons créer va afficher dans un premier temps la liste des
pays européens et un troisième niveau avec les principales villes de chacun des
pays. En maitre, nous aurons les informations concernant l'Europe, nom et
couleur associée à ce continent à savoir le bleu. En détail, nous trouverons la
liste des pays européens. Dans ce détail, nous allons créer un nouveau détail
qui affichera la liste des principales villes du pays. NB : Toute
ressemblance entre la réalité et les données affichées dans ces rapports n'est
que pure coincidence !!!
Création d'un maître détail avec jasper en implémentant la datasource
Partie Java
La première étape de ce rapport consiste à afficher les informations générales du continent européens, ici le nom du continent, la couleur associé qui est le bleu, puis de faire un sous rapport dans le détail afin d'afficher les pays européens. Voici la classe définissant un pays :
public class Pays {
private String nom;
private Integer population;
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public Integer getPopulation() {
return population;
}
public void setPopulation(Integer population) {
this.population = population;
}
}
Cette classe ne présente rien de spécial, il s'agit d'un simple POJO avec
des attributs et des accesseurs.
Voyons maintenant la classe Continent contenant les informations générales
liées à un continent ainsi qu'une liste des pays.
public class Continent extends AbstractJRDataSource<Pays> {
private String nom;
private String couleur;
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String getCouleur() {
return couleur;
}
public void setCouleur(String couleur) {
this.couleur = couleur;
}
}
La liste des pays n'apparait pas ici en Collection, en revanche, on étend
une classe maison
AbstractJRDataSource<Pays> dont voici
le code :
public abstract class AbstractJRDataSource<T> implements JRDataSource {
protected int index=0;
protected List<T>listeObj = null;
public boolean next() throws JRException {
index++;
return (index <= listeObj.size());
}
public Object getFieldValue(JRField field) throws JRException {
T obj = listeObj.get(index-1);
Object value;
try {
String methodName = "get"+field.getName().substring(0,1).toUpperCase()+field.getName().substring(1);
value = MethodUtils.invokeExactMethod( obj, methodName, null);
} catch (Exception e) {
throw new JRException(e.getMessage());
}
return value;
}
public List<T> getListeObj() {
return listeObj;
}
public void setListeObj(List<T> listeObj) {
this.listeObj = listeObj;
}
}
Il s'agit d'une classe générique dont un peut définir librement le type de la liste implémentée via le template, celle-ci implémente les méthodes getFieldValue() et next() de l'interface JRDataSource de Jasper. L'implémentation de l'interface JRDataSource va nous permettre de facilement alimenter les sous raports en créant de simple liste de pays. Voici maintenant le code de création des rapports :
public class SubReportDemo {
public static void main(String[] args) {
Continent continent = init();
JasperReport jasperReport = null;
JasperPrint jasperPrint = null;
Map<Object,Object> parameterMap = new HashMap<Object,Object>();
parameterMap.put( "reportName", "Rapport DEMO" );
parameterMap.put( "nom", continent.getNom() );
parameterMap.put( "couleur", continent.getCouleur() );
InputStream reportStream = SubReportDemo.class.getClassLoader().getResourceAsStream("rapport_demo_parent.jrxml");
try {
jasperReport = JasperCompileManager.compileReport(reportStream);
jasperPrint = JasperFillManager.fillReport(jasperReport, parameterMap, continent);
JasperExportManager.exportReportToPdfFile(jasperPrint, "/tmp/reportEurope_"+new Date()+".pdf");
} catch (JRException e) {
e.printStackTrace();
}
}
private static Continent init(){
Continent europe = new Continent();
List<Pays> paysEurope = new ArrayList<Pays>();
Pays france = new Pays();
france.setNom("FRANCE"); france.setPopulation(60000000);
paysEurope.add(france);
Pays italie = new Pays();
italie.setNom("Italie"); italie.setPopulation(45000000);
paysEurope.add(italie);
Pays angleterre = new Pays();
angleterre.setNom("Angleterre"); angleterre.setPopulation(55000000);
paysEurope.add(angleterre);
europe.setListeObj(paysEurope);
europe.setNom("Europe");
europe.setCouleur("bleu");
return europe;
}
}
la Liste des pays est renseigné dans la classe continent via la méthode setListeObj() définit comme template Pays => public class Continent extends AbstractJRDataSource<Pays>
Partie iReport
Création du rapport principal
Pour commencer, nous allons définir les paramètres, Le titre du rapport sera
passé en paramètre au rapport puis affiché sur celui-ci. Reste les données à
afficher dans la partie entête en l'occurence les données de l'objet
continent : le nom et la couleur que nous passons en tant que
paramètres, En tant que champs, nous passerons les données affichées dans la
partie détail (partie automatiquement alimentée avec les méthodes de
l'interface que nous avons implémentée : JRDataSource) provenant
de la classe Pays.
Ensuite, nous disposons les données sur
le rapports :
Voici alors le résultat obtenu avec la
partie Maître Continent et les Détails Pays 
Etape 2 : Sous Rapport en java avec jasper
Nous avons vu en première partie comment faire un simple maître détail en utilisant Jasper et en implémentant l'interface JRDataSource mise à disposition par l'API jasper. Voyons maintenant comment créer un sous rapport dans la partie détail du rapport. Nous allons ajouter en dessous de chaque pays, une liste des principales villes. Nous allons créer un sous rapport dans la partie détail. Voyons tout d'abord les modification au niveau structure objet.
Partie JAVA
On commence par ajouter la classe ville dont voici les attributs :
public class Ville {
private String nom;
private Integer population;
private Double superficie;
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public Integer getPopulation() {
return population;
}
public void setPopulation(Integer population) {
this.population = population;
}
public Double getSuperficie() {
return superficie;
}
public void setSuperficie(Double superficie) {
this.superficie = superficie;
}
}
Ensuite, on modifie la classe Pays pour y ajouter la collection de ville. Ici, on n'étend pas l'interface DataSource, on verra comment sera créer la dataSource dans iReport un peu plus tard...
public class Pays {
private String nom;
private Integer population;
private Collection<Ville> villes;
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public Integer getPopulation() {
return population;
}
public void setPopulation(Integer population) {
this.population = population;
}
public Collection<Ville> getVilles() {
return villes;
}
public void setVilles(Collection<Ville> villes) {
this.villes = villes;
}
}
Pour la partie java... on a finit !
Partie iReport
En dessous des informations concernant le pays, nous allons créer un rapport
secondaire. Une boîte de dialogue s'ouvre alors, nous sélectionnerons just
create subreport element
Dans les propriétés du rapport secondaire, nous nommons le rapport qui sera
appélé dans l'onglet Rapport Secondaire (autre)
par exemple
Rapport_Villes.jasper
.
Ensuite, nous passons à l'onglet Rapport Secondaire
et nous définissons
les paramètres du rapport secondaire en réutilisant les paramètres du rapport
principal dans Expression de mappe de paramètre
avec la valeur :
new HashMap($P{REPORT_PARAMETERS_MAP}), En dessous, on
sélectionne : Utiliser l'expression de source de donnée
et en
valeur, on y met notre collection qui alimente la datasource : new
JRBeanCollectionDataSource($F{villes})
. Une fois fait, l'onglet problem
mentionne que nous n'avons pas tout a fait terminé, il faut rajouter dans le
rapport principal la propriété que nous avons ajouté dans je code java de la
classe Pays à savoir villes de type : java.util.Collection. On
rajoute le champs et nous pouvons passer au sous rapport.
A venir !!!