Rapports BIRT avec Spring Boot

1. Introduction

Dans ce tutoriel, nous allons intégrer BIRT (Business Intelligence and Reporting Tools) à Spring Boot MVC, pour servir des rapports statiques et dynamiques au format HTML et PDF.

2. Qu'est-ce que BIRT ?

BIRT est un moteur open source pour créer des visualisations de données qui peuvent être intégrées dans des applications Web Java.

Il s'agit d'un projet logiciel de haut niveau au sein de la Fondation Eclipse et s'appuie sur les contributions d'IBM et d'Innovent Solutions. Il a été lancé et sponsorisé par Actuate fin 2004.

Le cadre permet de créer des rapports intégrés à un large éventail de sources de données.

3. Dépendances de Maven

BIRT a deux composants principaux: un concepteur de rapport visuel pour créer des fichiers de conception de rapport et un composant d'exécution pour interpréter et rendre ces conceptions.

Dans notre exemple d'application Web, nous allons utiliser les deux en plus de Spring Boot.

3.1. Dépendances du framework BIRT

Comme nous avons l'habitude de penser en termes de gestion des dépendances, le premier choix serait de chercher BIRT à Maven Central.

Cependant, la dernière version officielle de la bibliothèque principale disponible est la 4.6 à partir de 2016 , tandis que sur la page de téléchargement d'Eclipse, nous pouvons trouver des liens pour au moins deux versions plus récentes ( la version actuelle est 4.8 ).

Si nous choisissons d'opter pour la version officielle, le moyen le plus simple de faire fonctionner le code est de télécharger le package BIRT Report Engine, qui est une application Web complète également utile pour l'apprentissage. Nous devons ensuite copier son dossier lib dans notre projet (environ 68 Mo) et dire à l'EDI d'y inclure tous les fichiers JAR.

Il va sans dire qu'en utilisant cette approche, nous ne pourrons compiler que via l'EDI , car Maven ne trouvera pas ces jars à moins que nous ne les configurions et ne les installions manuellement (plus de 100 fichiers!) Dans notre dépôt local.

Heureusement, Innovent Solutions a décidé de prendre les choses en main et a publié sur Maven Central ses propres versions des dernières dépendances BIRT, ce qui est formidable, car il gère pour nous toutes les dépendances nécessaires.

En lisant les commentaires sur les forums en ligne, il n'est pas clair si ces artefacts sont prêts pour la production, mais Innovent Solutions a travaillé sur le projet aux côtés de l'équipe Eclipse depuis le début, notre projet s'appuie donc sur eux.

Intégrer BIRT est désormais très simple:

 com.innoventsolutions.birt.runtime org.eclipse.birt.runtime_4.8.0-20180626 4.8.0 

3.2. Dépendances de Spring Boot

Maintenant que BIRT est importé dans notre projet, il nous suffit d'ajouter les dépendances standard de Spring Boot dans notre fichier pom.

Il y a cependant un piège, car le jar BIRT contient sa propre implémentation de Slf4J , qui ne fonctionne pas bien avec Logback et lève une exception de conflit au démarrage.

Comme nous ne pouvons pas le supprimer du fichier jar, pour résoudre ce problème, nous devons exclure Logback :

 org.springframework.boot spring-boot-starter-logging   ch.qos.logback logback-classic   

Maintenant, nous sommes enfin prêts à commencer!

4. Rapports BIRT

Dans le framework BIRT, un rapport est un long fichier de configuration XML , identifié par l'extension rptdesign .

Il indique au moteur ce qu'il doit dessiner et où , du style d'un titre aux propriétés requises pour se connecter à une source de données.

Pour un rapport dynamique de base, nous devons configurer trois choses:

  1. la source de données (dans notre exemple, nous utilisons un fichier CSV local, mais cela pourrait facilement être une table de base de données)
  2. les éléments que nous voulons afficher (graphiques, tableaux, etc.)
  3. la conception de la page

Le rapport est structuré comme une page HTML, avec en-tête, corps, pied de page, scripts et styles.

Le cadre fournit un ensemble complet de composants prêts à l'emploi , y compris l'intégration aux sources de données, mises en page, graphiques et tableaux traditionnels. Et nous pouvons l'étendre pour ajouter le nôtre!

Il existe deux façons de générer un fichier de rapport: visuel ou programmatique.

5. Le concepteur de rapports Eclipse

Pour faciliter la création de rapports, l'équipe Eclipse a créé un plugin d' outil de conception de rapports pour son IDE populaire.

Cet outil dispose d'une interface simple glisser-déposer de la palette sur la gauche, qui ouvre automatiquement la fenêtre de configuration pour le nouveau composant que nous ajoutons à la page. Nous pouvons également voir toutes les personnalisations disponibles pour chaque composant en cliquant dessus sur la page puis sur le bouton Editeur de propriétés (mis en évidence dans l'image ci-dessous).

Pour visualiser l'ensemble de la structure de la page dans une arborescence, il suffit de cliquer sur le bouton Plan .

L' onglet Explorateur de données contient également les sources de données définies pour notre rapport:

L'exemple de rapport affiché dans l'image se trouve dans le chemin /reports/csv_data_report.rptdesign

Un autre avantage du concepteur visuel est la documentation en ligne, qui se concentre davantage sur cet outil plutôt que sur l'approche programmatique.

Si nous utilisons déjà Eclipse, il suffit d'installer le plugin BIRT Report Design , qui comprend une perspective prédéfinie et l'éditeur visuel.

Pour les développeurs qui n'utilisent pas actuellement Eclipse et ne veulent pas changer, il existe un package Eclipse Report Designer , qui consiste en une installation portable Eclipse avec le plugin BIRT pré-installé.

Une fois le fichier de rapport finalisé, nous pouvons l'enregistrer dans notre projet et revenir au codage dans notre environnement préféré.

6. L'approche programmatique

Nous pouvons également concevoir un rapport en utilisant uniquement du code , mais cette approche est beaucoup plus difficile en raison de la faible documentation disponible, alors soyez prêt à fouiller dans le code source et les forums en ligne.

Il convient également de noter que tous les détails de conception fastidieux tels que la taille, la longueur et la position de la grille sont beaucoup plus faciles à gérer en utilisant le concepteur .

Pour prouver ce point, voici un exemple de comment définir une page statique simple avec une image et un texte:

DesignElementHandle element = factory.newSimpleMasterPage("Page Master"); design.getMasterPages().add(element); GridHandle grid = factory.newGridItem(null, 2, 1); design.getBody().add(grid); grid.setWidth("100%"); RowHandle row0 = (RowHandle) grid.getRows().get(0); ImageHandle image = factory.newImage(null); CellHandle cell = (CellHandle) row0.getCells().get(0); cell.getContent().add(image); image.setURL("\"//www.baeldung.com/wp-content/themes/baeldung/favicon/favicon-96x96.png\""); LabelHandle label = factory.newLabel(null); cell = (CellHandle) row0.getCells().get(1); cell.getContent().add(label); label.setText("Hello, Baeldung world!");

Ce code générera un rapport simple (et laid):

L'exemple de rapport affiché dans l'image ci-dessus se trouve à ce chemin: /reports/static_report.rptdesign.

Une fois que nous avons codé l'apparence du rapport et les données qu'il doit afficher, nous pouvons générer le fichier XML en exécutant notre classe ReportDesignApplication .

7. Joindre une source de données

Nous avons mentionné précédemment que BIRT prend en charge de nombreuses sources de données différentes.

Pour notre exemple de projet, nous avons utilisé un simple fichier CSV avec trois entrées. Il se trouve dans le dossier des rapports et se compose de trois lignes simples de données, plus des en-têtes:

Student, Math, Geography, History Bill, 10,3,8 Tom, 5,6,5 Anne, 7, 4,9

7.1. Configuration de la source de données

Pour laisser BIRT utiliser notre fichier (ou tout autre type de source), nous devons configurer une source de données .

Pour notre fichier, nous avons créé une source de données de fichier plat avec le concepteur de rapports, le tout en quelques étapes:

  1. Open the designer perspective and look at the outline on the right.
  2. Right-click on the Data Sources icon.
  3. Select the desired source type (in our case the flat file source).
  4. We can now choose either to load an entire folder or just one file. We used the second option (if our data file is in CSV format, we want to make sure to use the first line as column name indicator).
  5. Test the connection to make sure the path is correct.

We attached some pictures to show each step:

7.2. The Data Set

The data source is ready, but we still need to define our Data Set, which is the actual data shown in our report:

  1. Open the designer perspective and look at the outline on the right.
  2. Right-click on the Data Sets icon.
  3. Select the desired Data Source and the type (in our case there's only one type).
  4. The next screen depends on the type of data source and data set we're selected: in our case, we see a page where we can select the columns to include.
  5. Once the setup is complete, we can open the configuration at any time by double-clicking on our data set.
  6. In Output Columns, we can set the right type of the data displayed.
  7. We can then look at a preview by clicking on Preview Results.

Again, some pictures to clarify these steps:

7.3. Other Data Source Types

As mentioned in step 4 of the Data Set configuration, the options available may change depending on the Data Source referred.

For our CSV file, BIRT gives options related to which columns to show, the data type, and if we want to load the entire file. On the other hand, if we had a JDBC data source, we may have to write an SQL query or a stored procedure.

From the Data Sets menu, we can also join two or more data sets in a new data set.

8. Rendering the Report

Once the report file is ready, we have to pass it to the engine for rendering. To do this, there are a few things to implement.

8.1. Initializing the Engine

The ReportEngine class, which interprets the design files and generates the final result, is part of the BIRT runtime library.

It uses a bunch of helpers and tasks to do the job, making it quite resource-intensive:

Image source: Eclipse BIRT documentation

There is a significant cost associated with creating an engine instance, due primarily to the cost of loading extensions. Therefore, we should create just one ReportEngine instance and use it to run multiple reports.

The report engine is created through a factory supplied by the Platform. Before creating the engine, we have to start the Platform, which will load the appropriate plug-ins:

@PostConstruct protected void initialize() throws BirtException { EngineConfig config = new EngineConfig(); config.getAppContext().put("spring", this.context); Platform.startup(config); IReportEngineFactory factory = (IReportEngineFactory) Platform .createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY); birtEngine = factory.createReportEngine(config); imageFolder = System.getProperty("user.dir") + File.separatorChar + reportsPath + imagesPath; loadReports(); }

When we don't need it anymore, we can destroy it:

@Override public void destroy() { birtEngine.destroy(); Platform.shutdown(); }

8.2. Implementing the Output Format

BIRT already supports multiple output formats:HTML, PDF, PPT, and ODT, to name a few.

For the sample project, we implemented two of them with the methods generatePDFReport and generateHTMLReport.

They differ slightly depending on the specific properties needed, such as output format and image handlers.

In fact, PDFs embed images together with text, while HTML reports need to generate them and/or link them.

Thus, the PDF rendering function is quite straightforward:

private void generatePDFReport(IReportRunnable report, HttpServletResponse response, HttpServletRequest request) { IRunAndRenderTask runAndRenderTask = birtEngine.createRunAndRenderTask(report); response.setContentType(birtEngine.getMIMEType("pdf")); IRenderOption options = new RenderOption(); PDFRenderOption pdfRenderOption = new PDFRenderOption(options); pdfRenderOption.setOutputFormat("pdf"); runAndRenderTask.setRenderOption(pdfRenderOption); runAndRenderTask.getAppContext().put(EngineConstants.APPCONTEXT_PDF_RENDER_CONTEXT, request); try { pdfRenderOption.setOutputStream(response.getOutputStream()); runAndRenderTask.run(); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } finally { runAndRenderTask.close(); } }

While the HTML rendering function needs more settings:

private void generateHTMLReport(IReportRunnable report, HttpServletResponse response, HttpServletRequest request) { IRunAndRenderTask runAndRenderTask = birtEngine.createRunAndRenderTask(report); response.setContentType(birtEngine.getMIMEType("html")); IRenderOption options = new RenderOption(); HTMLRenderOption htmlOptions = new HTMLRenderOption(options); htmlOptions.setOutputFormat("html"); htmlOptions.setBaseImageURL("/" + reportsPath + imagesPath); htmlOptions.setImageDirectory(imageFolder); htmlOptions.setImageHandler(htmlImageHandler); runAndRenderTask.setRenderOption(htmlOptions); runAndRenderTask.getAppContext().put( EngineConstants.APPCONTEXT_BIRT_VIEWER_HTTPSERVET_REQUEST, request); try { htmlOptions.setOutputStream(response.getOutputStream()); runAndRenderTask.run(); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } finally { runAndRenderTask.close(); } }

Most noteworthy, we set the HTMLServerImageHandler instead of leaving the default handler. This small difference has a big impact on the generated img tag:

  • the default handler links the img tag to the file system path, blocked for security by many browsers
  • the HTMLServerImageHandler links to the server URL

With the setImageDirectory method, we specify where the engine will save the generated image file.

By default, the handler generates a new file at every request, so we could add a caching layer or a deletion policy.

8.3. Publishing the Images

In the HTML report case, image files are external, so they need to be accessible on the server path.

In the code above, with the setBaseImageURL method, we tell the engine what relative path should be used in the img tag link, so we need to make sure that the path is actually accessible!

For this reason, in our ReportEngineApplication, we configured Spring to publish the images folder:

@SpringBootApplication @EnableWebMvc public class ReportEngineApplication implements WebMvcConfigurer { @Value("${reports.relative.path}") private String reportsPath; @Value("${images.relative.path}") private String imagesPath; ... @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry .addResourceHandler(reportsPath + imagesPath + "/**") .addResourceLocations("file:///" + System.getProperty("user.dir") + "/" + reportsPath + imagesPath); } }

Whatever the path we choose, we have to make sure the same path is used here and in the htmlOptions of the previous snippet, or our report won't be able to display images.

9. Displaying the Report

The last component needed to get our application ready is a Controller to return the rendered result:

@RequestMapping(method = RequestMethod.GET, value = "/report/{name}") @ResponseBody public void generateFullReport(HttpServletResponse response, HttpServletRequest request, @PathVariable("name") String name, @RequestParam("output") String output) throws EngineException, IOException { OutputType format = OutputType.from(output); reportService.generateMainReport(name, format, response, request); }

With the output parameter, we can let the user choose the desired format — HTML or PDF.

10. Testing the Report

We can start the application by running the ReportEngineApplication class.

During startup, the BirtReportService class will load all the reports found in the /reports folder.

To see our reports in action, we just need to point our browser to:

  • /report/csv_data_report?output=pdf
  • /report/csv_data_report?output=html
  • /report/static_report?output=pdf
  • /report/static_report?output=html

Here is how the csv_data_report report looks:

To reload a report after changing the design file, we just point our browser to /report/reload.

11. Conclusion

Dans cet article, nous avons intégré BIRT à Spring Boot, explorant les pièges et les défis, mais aussi sa puissance et sa flexibilité.

Le code source de l'article est disponible à l'adresse over sur GitHub.