I. Introduction▲
Outre les fonctionnalités offertes par JasperReports en terme d'utilisation de différents types de DataSource, les templates, les graphes, les Scriptlets… vient s'ajouter le concept des SubReports qui représente une fonctionnalité très avancée à cette API. Dans cet article nous allons voir comment insérer un SubReport (sous-rapport) dans un rapport parent et y passer différents types de paramètres.
II. SubReport et rapport parent utilisant la même source de données▲
II-A. Présentation▲
Dans cet article nous allons utiliser MS ACCESS comme SGBD. Dans un premier lieu, nous allons créer une base de données qui portera pour nom testSubReports.mdb et contiendra deux tables.
Contrat :
et Echeance :
Ainsi, pour chaque contrat nous aurons plusieurs échéances. Nous pouvons alimenter ces deux tables par des données initiales.
Contrat :
et Echeance :
II-B. Configuration de la source de données▲
Dans cette section nous allons construire deux rapports : un master (rapport parent et un SubReport (sous-rapport) qui utiliseront la même source de données lors de l'exécution.
Créons tout d'abord un ODBC pointant sur la base de données récemment créée testSubReports.mdb et nous allons le nommer testSubReports.
Une fois l'ODBC créé, nous allons configurer une nouvelle source de données sous iReport pointant sur ce dernier. Pour créer une source de données sous iReport vous pouvez vous référer à cet article.
II-C. Création des rapports▲
Dans ce paragraphe nous allons créer deux sous-rapports dont l'un fera appel à l'autre. Nous n'allons pas passer par l'assistant de iReport pour la création du sous-rapport afin de mieux comprendre les différentes phases.
II-C-1. Création du rapport master (parent)▲
Le rapport parent utilisera la source de données que nous venons de créer et utilisera la table Contrat.
Sous iReport créer un rapport vide: Fichier --> Nouveau document. Nommer ce rapport MyMasterReport.
Saisir la requête qui alimentera ce rapport en cliquant sur l'icône :
select *
from Contrat
L'écran où nous devons saisir la requête ressemble à :
Cliquer sur OK. Vous allez constater que les deux champs id et Nom de la table Contrat ont été ajoutés à la liste des champs de l'état :
Nous sélectionnons ces deux champs que nous faisons glisser sur l'état sur la bande détail comme suit :
Nous lançons notre rapport pour nous assurer qu'il n'y a pas de problème pour le moment. Il doit avoir l'allure comme ceci :
Jusqu'à maintenant nous n'avons créé que le rapport parent (le master). Mais nous n'en avons pas encore fini, nous allons y revenir après avoir fini avec le sous-rapport.
II-C-2. Création du subrapport (sous-rapport)▲
De la même manière qu'on a créé le rapport parent nous allons créer le sous-rapport, qu'on va nommer MySubReport. Ce Deuxième rapport attaque la table Echeance.
En gros vous devrez avoir un rapport qui ressemble à ceci :
Vous pouvez constater que toutes les marges de ce rapport ont été enlevées (footer, header, summary…). Car seule la bande détail nous intéresse.
Maintenant nous devons créer le lien qui va lier entre le rapport parent et le sous-rapport. Ce lien n'est autre qu'un paramètre qui sera créé au niveau du sous-rapport et qui sera alimenté par le rapport parent. Ce lien doit refléter la jointure entre les deux tables de la base de données, à savoir le numéro de contrat (champ NumContrat).
Créons alors un paramètre de même type que le champ de jointure (NumContrat) : String avec pour nom
Revenons à la requête du sous-rapport pour la modifier comme suit :
C'est bon le sous-rapport est prêt pour intégration au niveau du rapport parent.
Au niveau du rapport parent nous allons insérer, dans la bande détail, un rapport secondaire en cliquant sur l'icône :
Comme dit avant, nous n'allons pas utiliser l'assistant de iReport pour la création du sous-rapport. Dans l'écran qui se présente nous allons donc choisir : Just create the SubReport element et cliquer sur Terminer.
Votre rapport doit ressembler à quelque chose comme ça :
Ce nouveau rapport secondaire créé doit pointer sur le sous-rapport précédemment créé. Pour ce faire, cliquer droit sur ce nouvel élément inséré et choisir Propriétés, l'écran suivant s'ouvre :
Sélectionnez l'onglet Rapport secondaire et dans Expression de connexion/source de données sélectionnez Utiliser l'expression de connexion, dans la zone de texte vous verrez que l'expression $P{REPORT_CONNECTION} a été ajoutée automatiquement. Cette expression veut dire que la connexion qu'utilisera le sous-rapport est la même connexion utilisée par le rapport parent. En effet, $P{REPORT_CONNECTION} ne fait que récupérer la connexion courante du rapport. $P{REPORT_CONNECTION} fait partie des paramètres intégrés d'un rapport qu'on ne peut ni modifier ni supprimer.
Après avoir configuré la connexion du sous-rapport, nous allons maintenant paramétrer le champ de liaison entre les deux rapports. Sur le même écran précédent, sélectionner l'onglet Rapport secondaire (autre) et choisir Paramètres de rapport secondaire en y mentionnant aussi le nom du fichier Jasper de notre sous-rapport.
Cliquer sur le bouton … montré dans la figure précédente.
Dans cet écran nous devons saisir le nom de paramètre qui servira de jointure entre les deux rapports. Le nom doit respecter la casse et doit être identique à celui créé au niveau du sous-rapport, à savoir NumContrat et aura pour valeur le champ NumContrat du rapport parent.
Cliquer sur OK. La création des rapports est terminée. Nous pouvons compiler les deux rapports, mettre dans les deux jasper dans le répertoire C:\\JASPER et exécuter le rapport parent pour voir le résultat.
Dans le rapport parent j'ai mis dans propriété Expression de rapport secondaire : « C:\\JASPER\\MySubReport.jasper ». On pourrait ne pas fixer ce chemin dès le début et y mettre par exemple : $P{PATH_TO_SubReportS} + java.io.File.separator + « MySubReport.jasper ». Dans ce cas il faut créer le paramètre PATH_TO_SubReportS et le remplir à partir de la classe Java pour spécifier le chemin où se trouve le sous-rapport.
II-D. Exécution des rapports à partir d'une classe Java▲
Créons tout d'abord une nouvelle application Java, dans ce cas c'est testSubReports. Nous allons créer une simple classe TestSubReport, dans le package jaub, qui va exécuter ces rapports. En fait, seul le rapport parent sera appelé, ce dernier appellera à son tour le sous-rapport.
Les différents JAR de l'api JasperReports et qui vont avec doivent être ajoutés au CLASSPATH de l'application.
Dans cette classe, nous insérons le code suivant :
package
jaub;
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.FileNotFoundException;
import
java.io.IOException;
import
java.sql.Connection;
import
java.sql.DriverManager;
import
java.sql.SQLException;
import
net.sf.jasperreports.engine.JRException;
import
net.sf.jasperreports.engine.JasperExportManager;
import
net.sf.jasperreports.engine.JasperFillManager;
import
net.sf.jasperreports.engine.JasperPrint;
import
net.sf.jasperreports.view.JasperViewer;
public
class
TestSubReport {
public
TestSubReport
(
) {
}
public
static
void
main
(
String[] args) throws
JRException, IOException {
FileInputStream fis =
null
;
try
{
File file =
new
File
(
"C:
\\
JASPER"
);
fis =
new
FileInputStream
(
new
File
(
file, "MyMasterReport.jasper"
));
JasperPrint jasperPrint =
JasperFillManager.fillReport
(
fis, null
,
getConnection
(
));
// export de l'état dans un fichier pdf
JasperExportManager.exportReportToPdfFile
(
jasperPrint,
"C:
\\
Test1SubReport.pdf"
);
// Affichage du rapport dans l'objet JasperViewer
JasperViewer.viewReport
(
jasperPrint);
}
catch
(
FileNotFoundException ef) {
System.out.println
(
"fichier introuvable"
);
}
finally
{
if
(
getConnection
(
) !=
null
) {
try
{
getConnection
(
).close
(
);
}
catch
(
SQLException ex) {
}
}
fis.close
(
);
}
}
private
static
Connection getConnection
(
) {
Connection conn =
null
;
try
{
Class.forName
(
"sun.jdbc.odbc.JdbcOdbcDriver"
);
}
catch
(
ClassNotFoundException e) {
}
// connexion à la base de données
try
{
String DBurl =
"jdbc:odbc:testSubReports"
;
conn =
DriverManager.getConnection
(
DBurl);
}
catch
(
SQLException e) {
}
return
conn;
}
}
À l'exécution de classe notre état est exporté dans un fichier pdf C:\Test1SubReport.pdf et affiché dans l'objet JasperViewer.
Dans cette section nous avons vu comment éditer un rapport parent appelant un sous-rapport. Ces deux rapports utilisaient la même connexion à la base de données. Dans ce qui suit, nous allons voir comment un rapport parent, utilisant une connexion à la base de données différente de celle utilisée par le sous-rapport appelé.
III. SubReport et rapport parent utilisant deux sources de données différentes▲
III-A. Configuration des sources de données▲
Dans cet article nous allons nous contenter d'utiliser le même SGBD pour le rapport parent et le sous-rapport, à savoir MS ACCESS. Ce qui va changer par rapport à la section précédente c'est qu'on va créer une deuxième base de données qui sera utilisée par le sous-rapport.
Créons alors une nouvelle base de données testSubReports2.mdb et montons là en ODBC sous le nom testSubReports2. Cette base de données contient une seule table Adresse.
Cette table est alimentée par les données suivantes :
III-B. Création des rapports▲
Tout d'abord, nous allons configurer la nouvelle source de données testSubReports2 :
Choisir cette source de données comme étant la source de données par défaut de notre sous-rapport :
Comme procédé dans la section précédente, nous allons créer deux nouveaux rapports MySubReport2 et MyMasterReport2.
Avant de saisir la requête SQL, nous devons créer le paramètre qui servira de liaison entre les deux rapports : NumContrat de type String.
Le MySubReport2 sera alimenté par la requête suivante :
Les trois champs de la table Adresse apparaitront dans la liste des champs du rapport :
Sélectionnez les champs que vous désirez et glisser les dans la bande détail de votre rapport :
Étant donné que notre sous-rapport n'utilisera pas la même source de données que le rapport parent, alors nous allons créer un paramètre MyConnection de type java.sql.Connection qui servira de source de données pour le sous-rapport, ce paramètre sera alimenté à partir de notre classe Java qu'on verra par la suite.
java.sql.Connection n'existe pas comme choix dans la liste Type de classe de paramètre. Cette expression doit alors être saisie manuellement dans l'écran montré dans la figure précédente.
Le rapport parent sera créé de la même manière qu'avant, ce qui changera c'est l'élément Expression de connexion/source de données dans les propriétés du rapport secondaire inséré au niveau du rapport parent. Dans la section précédente cet élément avait pour valeur $P{REPORT_CONNECTION} dans Utiliser l'expression de connexion.
Dans ce deuxième cas nous allons mettre la valeur $P{MyConnection} dans Utiliser l'expression de connexion :
Le rapport secondaire doit pointer sur le sous-rapport qui sera mis dans C:\\JASPER.
Les deux rapports ont été bien créés. Vous n'avez qu'à les compiler et mettre les deux fichiers jasper MyMasterReport2.jasper et MySubReport2.jasper dans C:\\JASPER.
III-C. Exécution des rapports à partir d'une classe Java▲
Créons une classe TestSubReport2 dans le package jaub et insérons-y le code suivant :
package
jaub;
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.FileNotFoundException;
import
java.io.IOException;
import
java.sql.Connection;
import
java.sql.DriverManager;
import
java.sql.SQLException;
import
java.util.HashMap;
import
java.util.Map;
import
net.sf.jasperreports.engine.JRException;
import
net.sf.jasperreports.engine.JasperExportManager;
import
net.sf.jasperreports.engine.JasperFillManager;
import
net.sf.jasperreports.engine.JasperPrint;
import
net.sf.jasperreports.view.JasperViewer;
public
class
TestSubReport2 {
public
TestSubReport2
(
) {
}
public
static
void
main
(
String[] args) throws
IOException, JRException {
FileInputStream fis =
null
;
try
{
Map parameters =
new
HashMap
(
);
// Alimenter le paramètre MyConnection par la connexion
// qui servira de source de données au sous-rapport
parameters.put
(
"MyConnection"
, getConnectionForSubReport
(
));
File file =
new
File
(
"C:
\\
JASPER"
);
fis =
new
FileInputStream
(
new
File
(
file, "MyMasterReport.jasper"
));
JasperPrint jasperPrint =
JasperFillManager.fillReport
(
fis,
parameters, getConnection
(
));
// export de l'état dans un fichier pdf
JasperExportManager.exportReportToPdfFile
(
jasperPrint,
"C:
\\
Test2SubReport.pdf"
);
// Affichage du rapport dans l'objet JasperViewer
JasperViewer.viewReport
(
jasperPrint);
}
catch
(
FileNotFoundException ef){
System.out.println
(
"fichier introuvable"
);
}
finally
{
if
(
getConnection
(
) !=
null
) {
try
{
getConnection
(
).close
(
);
}
catch
(
SQLException ex) {
}
}
fis.close
(
);
}
}
private
static
Connection getConnection
(
) {
Connection conn =
null
;
try
{
Class.forName
(
"sun.jdbc.odbc.JdbcOdbcDriver"
);
}
catch
(
ClassNotFoundException e) {
}
// connexion à la base de données
try
{
String DBurl =
"jdbc:odbc:testSubReports"
;
conn =
DriverManager.getConnection
(
DBurl);
}
catch
(
SQLException e) {
}
return
conn;
}
private
static
Connection getConnectionForSubReport
(
) {
Connection conn =
null
;
try
{
Class.forName
(
"sun.jdbc.odbc.JdbcOdbcDriver"
);
}
catch
(
ClassNotFoundException e) {
}
// connexion à la base de données testSubReports2
// Cette connexion sera passée en paramètre et utilisée
// par le sous-rapport
try
{
String DBurl =
"jdbc:odbc:testSubReports2"
;
conn =
DriverManager.getConnection
(
DBurl);
}
catch
(
SQLException e) {
}
return
conn;
}
}
À l'exécution de classe notre état est exporté dans un fichier pdf C:\Test2SubReport.pdf et affiché dans l'objet JasperViewer.
IV. Téléchargement des sources▲
Le code source de l'application est disponible dans l'archive suivant :
Après décompression, vous aurez trois répertoires :
- JASPER : Contient les fichiers Jasper/Jrxml, les fichiers jasper sont à mettre dans C:\JASPER ;
- testSubReports : contient le code source de l'application, ainsi que les différents fichiers JAR nécessaires ;
- les bases de données : contient les deux bases de données ACCESS utilisées dans ce tutoriel.
V. Conclusion▲
Nous avons vu dans cet article comment utiliser des SubReports (sous-rapports) à travers un rapport master (parent) en utilisant l'api JasperReports. Le lecteur pourra élargir son étude en utilisant deux SGBD différents à la fois, il faudra juste faire attention aux types des champs de jointures qui doivent être de même type pour éviter de faire des conversions de types.
VI. Remerciements▲
Un grand merci à Fleur-Anne.Blain et Ricky81 pour leurs retours et remarques très précieuses.