Affichage des articles dont le libellé est business intelligence. Afficher tous les articles
Affichage des articles dont le libellé est business intelligence. Afficher tous les articles


Java et Business Intelligence avec JasperSofts

Pour faire suite à mon article sur la manipulation de documents Office avec Java et rester dans le domaine de l'informatique décisionnelle, voici une présentation de l'outil JasperReports et de son éditeur graphique iReport de la société JasperSofts. Cet exemple se base sur la dernière version (3.7.6 à l'heure de l'écriture) qui offre de nombreuses facilités quant à la mise en place de rapports.

Je vais fournir dans cette article tout le code et les fichiers nécessaires à reproduire l'exemple. En pièce jointe se trouve un lien vers le workspace que j'ai utilisé (diminué des librairies nécessaires à JasperReports pour des raisons de volume d'upload). Je vais donc décrire ici les quelques subtilités que j'ai rencontrées mais le rapport mis en place se compose de la majorité des éléments couramment recherchés (sous-rapport, diagrammes, listes, tableaux croisés, styles, temps d'évaluation...), donc il vous suffira de l'explorer de fond en comble pour trouver votre bonheur! :)

J'ai choisi de créer un rapport au format PDF car à mon sens il est celui qui propose le meilleur rendu pour les différents composants disponibles. Les objets utilisés dans le code sont volontairement simplistes pour ne pas compliquer la compréhension de leur organisation et de leur utilisation dans le modèle.

Voici un aperçu du rapport final créé pour cet article :

Regardons le code de la classe principale qui permet de le générer (Reporter.java) :

package com.developpef;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

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;
import net.sf.jasperreports.engine.util.FileResolver;

public class Reporter {

private static final String ENCOURAGEMENT = "Bonne lecture!";

private static final String CLASSIQUE = "Hope this helps...";

public static void main(String[] args) {
 List<TestBean> beans = new ArrayList<TestBean>();
 beans.add(getBean(ENCOURAGEMENT));
 beans.add(getBean(CLASSIQUE));

 try {
  FileResolver fileResolver = new FileResolver() {
   @Override
   public File resolveFile(String fileName) {
    URI uri;
    try {
     uri = new URI(Thread.currentThread()
       .getContextClassLoader().getResource(
          "com/resources/" + fileName).getPath());
     return new File(uri.getPath());
    } catch (URISyntaxException e) {
     e.printStackTrace();
     return null;
    }
   }
  };
  HashMap<Object, Object> parameters = new HashMap<Object, Object>();
  parameters.put("REPORT_FILE_RESOLVER", fileResolver);
  URL jasperModelUrl = Thread.currentThread().getContextClassLoader()
    .getResource("com/resources/jasper/reportTest.jasper");
  URL resourceFolder = Thread.currentThread().getContextClassLoader()
    .getResource("com/resources/jasper/");
  InputStream stream = new FileInputStream(new File(jasperModelUrl
    .toURI()));
  JRBeanCollectionDataSource datasource = new JRBeanCollectionDataSource(beans);
  JasperPrint jasperPrint = JasperFillManager.fillReport(stream,
    parameters, datasource);
  File finalPdfPath = new File(resourceFolder.toURI().getPath()
    + "reportTest.pdf");
  JasperExportManager.exportReportToPdfFile(jasperPrint, finalPdfPath
    .getAbsolutePath());
  Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler "
    + finalPdfPath.getAbsolutePath());
 } catch (Exception e) {
  e.printStackTrace();
 }
}

private static TestBean getBean(String conclusion) {
 TestBean bean = new TestBean();
 bean.setAuthor("Developpef");
 bean.setHomeUrl("http://developpef.blogspot.com/");
 bean.getStatsHolder().getStats().add(new StatBean("Mozilla", 60));
 bean.getStatsHolder().getStats().add(new StatBean("IE", 25));
 bean.getStatsHolder().getStats().add(new StatBean("Others", 15));
 bean.getStatsHolder().getStatsOS().add(new StatBean(502, "Windows"));
 bean.getStatsHolder().getStatsOS().add(new StatBean(158, "Linux"));
 bean.getStatsHolder().getStatsOS().add(new StatBean(12, "Other Unix"));
 bean.getArchives().add(new ArchiveBean("Eclipse", "Septembre", 2));
 bean.getArchives().add(new ArchiveBean("Eclipse", "Octobre", 7));
 bean.getArchives().add(new ArchiveBean("Java", "Septembre", 10));
 bean.getArchives().add(new ArchiveBean("Java", "Octobre", 3));
 bean.getArchives().add(new ArchiveBean("Java", "Novembre", 6));
 bean.getJavaBeans().add(new StatBean(null, 0));
 bean.getJavaBeans().add(new TestBean());
 bean.getJavaBeans().add(new ArchiveBean(null, null, 0));
 bean.getJavaBeans().add(new StatsHolder());
 bean.setJavaTxt1("Ce texte est issu de Java et fait donc partie du contenu "
   + "dynamique du rapport. "
   + "Seuls les quelques POJO listés ci-dessous ont suffit à créer "
   + "tous les graphiques et autres listes présentés ici :");
 bean.setJavaTxt2("Ce rapport assez simple ne se compose que d'une seule page mais est"
   + " édité pour 2 éléments, comme le prouve le code barre basé sur le hashCode"
   + " de ce texte. " + conclusion);
 return bean;
}
}

Tout commence par la création de la liste de beans qui sera passée comme source de données au rapport. Un rapport sera créé pour chaque bean, ce qui dans cet exemple résultera en un PDF de 2 pages. Ces beans doivent être différentiables par le template, c'est la raison pour laquelle il est fortement conseillé de surcharger les méthodes equals() et hashCode() sous peine de voir le rapport répété X fois pour les même données. Ici la distinction se fait grâce à la toute dernière phrase du rapport (variables statiques).

L'en-tête contient une image de fond. Pour permettre au moteur du template de pouvoir la résoudre dans notre classpath et l'insérer dans le PDF, il est indispensable de lui injecter un FileResolver lui permettant d'accéder à tous les fichiers nécessaires (images, sous-rapports...). Pour cela, il faut utiliser le ContextClassLoader afin de parcourir les ressources. Le paramètre fileName correspond au chemin des éléments indiqué dans le template ("images/..." ou "jasper/..").

Il faut également savoir que JasperReports se base sur tout un tas de librairies standards pour créer ses composants. Si vous rencontrez quelques difficultés, il vous suffit de vous rapporter aux documentations respectives :


Fichier(s) joint(s) :



Manipuler des documents Office avec Java

Quand on travaille sur des systèmes d'informations en entreprise, particulièrement dans le cadre de l'informatique décisionnelle (business intelligence), il arrive souvent que l'on rencontre l'obligation de générer des formats de documents précis pour satisfaire les besoins des utilisateurs. Et parmi les formats les plus courants, la famille Office est certainement la plus pénible redoutée.

Bon nombre de développeurs ont eu à s'arracher les cheveux pour satisfaire les caprices particularités de ces chers documents... Mais heureux ceux qui, comme moi récemment, ont croisé la route de l'API Apache POI.

Et là, force est de reconnaitre que la fondation Apache nous gratifie encore une fois d'un travail remarquable en fournissant tout une bibliothèque libre permettant de lire, écrire et utiliser presque tous les types de documents : Word, Excel, Powerpoint, Publisher...

Si vous parcourez les exemples de code cités plus bas, vous vous rendrez compte à quel point la manipulation de ces formats a été simplifiée, cela en est presque énervant!

Les petits bémols (puisqu'il en faut!) sont : d'une part que POI ne prend pas en charge la gestion des graphiques Excel et se révèle quelques fois réticent lorsqu'il s'agit d'évaluer des formules complexes. D'autre part, le code à utiliser peut parfois paraître lourd ou maladroit, mais cela semble inhérent aux contraintes imposées par Office (à en croire le nom des classes : Horrible Spreadsheet, Horrible Document ou même POI : Poor Obfuscation Implementation). Pour y remédier, il existe Formula One, un outil graphique pour générer des templates de documents Excel utilisables en Java. Il permet de réduire considérablement la quantité de code à écrire de passer outre certaines des difficultés pré-citées.

Sources


Fichier(s) joint(s) :