Un système de template avec Groovy et Java

La génération de rapports au format texte brut (TXT) peut parfois devenir un vrai casse-tête, surtout s'il contient une mise en forme particulière quelles que soient les données.

Pour se faciliter la tâche, il est possible d'utiliser un moteur de templates basé sur Groovy, exécutable en Java, qui assurera la stabilité du rendu avec un effort réduit.

Commençons par le code Java générant notre "rapport" :

import groovy.text.SimpleTemplateEngine;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.codehaus.groovy.control.CompilationFailedException;

public class ReportUtil {

 public static void main(String[] args) {
  Map<String, Object> data = new HashMap<String, Object>();

  Map<String, String> context = new HashMap<String, String>();
  context.put("mascotte", "Duke");
  context.put("auteur", "DevellOpPeF");
  context.put("tool", "GRoOvY");
  context.put("date", "01042012");

  data.put("context", context);
  
  List<String[]> remerciements = new ArrayList<String[]>();
  remerciements.add(new String[]{"Rodolphe","Pour avoir retrouvé ces sources"});
  remerciements.add(new String[]{"Olivier","Pour ses questions pertinentes sur Groovy/Java"});
  
  data.put("remerciements", remerciements);

  try {
   buildFileFromGroovyTemplate(ReportUtil.class.getClassLoader()
     .getResource("TestReport.tmpl").toURI(), "txt", data);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 public static String buildFileFromGroovyTemplate(URI templateFilePath,
   String outputType, Map<String, Object> dataProvider)
   throws CompilationFailedException, IOException {

  String outputFileName = "out_" + System.currentTimeMillis() + "."
    + outputType;
  String outputFilePath = "C:/test/" + outputFileName;

  File outputFile = new File(outputFilePath);
  if (outputFile.exists()) {
   outputFile.delete();
  }

  File tmplFile = new File(templateFilePath);
  if (tmplFile.exists()) {
   FileWriter fileWriter = new FileWriter(outputFilePath, false);

   new SimpleTemplateEngine().createTemplate(new FileReader(tmplFile))
     .make(dataProvider).writeTo(fileWriter);

   fileWriter.close();
  }

  return outputFileName;
 }

}

Son contenu est assez simple :

  • La méthode main constitue le jeu de données à utiliser,
  • La méthode buildFileFromGroovyTemplate lance le moteur Groovy pour générer le fichier final à partir du template TestReport.tmpl et par l'intermédiaire du SimpleTemplateEngine

Il suffit d'utiliser la dépendance suivante pour compiler cette classe :

<dependency>
 <groupId>org.codehaus.groovy</groupId>
 <artifactId>groovy</artifactId>
 <version>1.8.6</version>
</dependency>

Voici maintenant le plus important, le contenu du template :

<%
/////// FUNCTIONS

// Method to write string on given char number
def format(format, text) {
 String.format(format,text)
}

def writePageHeader()
{
%>Hi! from ${context["mascotte"]}!

I was generated with Groovy, run by Java and built by ${context["auteur"]}...


Remerciements :
<%}

def writeFirstQuarter() {
%>


7aJeS6viEuWwWk0hX3Bj8twFQi5q7VQ6xZXE
l2Oe8tA3F7OW2AcPEGahtIffLSf6UugDZ3yX
QNL31XLtRuB5pabFbMsFjFsueIIEm1I9ET35
cd4XIYyRrOIsOM5HIdMoqv9t71NMoJDUcAl6
MfbMIxEW8dyC7RChMz3YUWlbDPP23R3G5kTD
bT2iH4cWbhgkcpZGf2tDUt8neMWFdVdzgy8c
EsSDawQv02JeUb7SsZCwhrpfj7B99RvE2FHT
zJZAvF7bF7F2B87JSvuarvksYckRrLN6Vd6I
w6UzumNNBjYOsw1y3pY0WO3BF5hGPGf9A8zu
fxGivMreSlo5lp6JFsbnUK8SH1HqguzSRo0F
q02oIAaQqFvBXFqOKUikYpvXUeQPNx7vd0Ww
xcspJ5BaLPMJCbAZp1MsSEaxTUnvYNbJAZmK
cnlMsCian5gfFgDbbZpZ5pMsdbRFAbmvgzAQ
OVyz7IPPNQE7DlYD82qhMDAJsAJ8np6E6ay2
oNxpWXquVZ${context["tool"]}3PwACcLc0F6984kiKrGi
<%}

def writeSecondQuarter() {
%>EaGQM4WH5VEf2OH9x8hnLc8fWJc5NLPSsWpb
nKqvv77q3LcJrXyDMb8ICPI5ZX5oX6WME7A2
8T5HOUtK21EPEJMEBHCt5Mw2nXUuNsLL6GSJ
DnDbk2LCZYfspil2jJhArVYCE4b2ylmpicXP
KBapEyy3XAsGpJ34ZoyjfedT9FlZPQtZS58X
HA8mU8nDXEU2tdbr9O7QDzI8yKcusJCmKAry
cVx5UQFGvk${context["auteur"]}qZze5ybzbHNK2It
xfGLFoGsXiZtxpW6DuJgeFyNrnnxFRQ16WCA
RIpvWCdMvkrEoYaqYVmAgYBznssLORhuZOTx
Oq5PBx0d4E6ssT06FI0CNtrXkT4ti2Bxe4At
rrv70yQvAvjBpJ8qfjzxVYcd5ImXo9jCet9T
UBDHf8PWWbWC0bunHyFOyJAyc4tAyKhnLl7n
lf5mJlhflLbYBAH8nbKB2Lp8C4qmalyJVz2t
bFEXDHTf0wWW3kbcM8VV1FSI0PipDmr1biP2
HozZjRhO1l7Uqc2nhiYKDkC45dg5ZURu2l4p
YhnzdwDQjrs89rk5Dli0p1dcxK0yXedxIeMw
<%}

def writeThirdQuarter() {
%>A1DdfnctUK475FZI0dZ1iJtZ2s9ixQmxIcYc
Ae8y20H1X2IHgQ6DCuOTepuW1nhR7sH8EFt4
oUAFj16WJ27Q1BVV8S4cdalDp6ZwKRLmdLbS
YlMGccBLiLrl6F3mY4rDIFhqpTYZ5tLTNYZ9
KX107aJWnE1AYEZbDpPPQ23had8kwNr6qUwo
K0TDymjtzak6USOF199vq8pLWzMiWc9udSqI
ROF1azSd9hY8LBRcJUCxbmFNwl11My8rmDUJ
H1DNFv57hHrfqNk5XLpJh1UHWi0f364Bc9O1
CgOXcq6dNbuKnSKDK8M9zrSpVbXIkXymCmHb
zTZw2woP3PdY9gHGeeI3A91lhIsZqrVBcxcg
<%}

def writeLastQuarter() {
%>iYnZHyol6IMPK8${format("%-16s",context["date"])}8Xrbcq
s9mfwL0aUjySD8H0oaL1ghXIT0f64jcijuLa
xieIhx9Tj5Aerj8hGjj7kYUCJhrxpWoV3Atp
hRg9TbhvpPJHqDIFf6puW9aR3BKelwlXBXXV
yTi5qa7w3htdDu9z1My98bR3lf5kd2PHLcDx
Y3yhvNTl65sJCv4GpJGFPvH7ighmCqaat5GR
EiYLt50Kh3wFUOAayJ0yMMHYquiEynhqWEx0
BHTJy3hD8L2fxPliGlJHYh2It33wZb1a5Kpz
<%}


/////// MAIN

writePageHeader()

remerciements.each {
%>- ${format("%-15s",it[0])} : ${format("%-100s",it[1])}
<%}

writeFirstQuarter()
writeSecondQuarter()
writeThirdQuarter()
writeLastQuarter()
%>

Pour ceux qui ne connaissent pas Groovy, sa syntaxe est très proche de celle de Java et/ou JSF. Les instructions Groovy sont placées dans des balises <% (...) %>. Tout ce qui est en dehors correspond au contenu du template, ce qui sera écrit dans le fichier final. Dans ce contenu, l'accès aux variables se fait pas l'usage de ${...}

Ce que l'on trouve ici :

  • La méthode format est utilisée pour écrire une donnée selon un format particulier, en complétant si besoin est par des espaces afin d'assurer la mise en page.
  • Les méthodes writePageHeader, writeFirstQuarter,writeSecondQuarter, writeThirdQuarter et writeLastQuarter permettent de segmenter la génération du contenu, une manière parfois plus lisible de répartir le code.
  • En dernière partie, un bloc intitulé "Main" qui est constitué des appels aux méthodes précédentes et qui va donc entrainer la génération du rapport.
  • Une boucle each parcourant les éléments de la liste remerciements passée en paramètre

Voici donc le résultat (avec un formattage HTML pour la présentation sur cette page) :

Hi! from Duke

I was generated with Groovy, run by Java and built by DevellOpPeF...

Remerciements :

Rodolphe        : Pour avoir retrouvé ces sources
Olivier         : Pour ses questions pertinentes sur Groovy/Java


7aJeS6viEuWwWk0hX3Bj8twFQi5q7VQ6xZXE
l2Oe8tA3F7OW2AcPEGahtIffLSf6UugDZ3yX
QNL31XLtRuB5pabFbMsFjFsueIIEm1I9ET35
cd4XIYyRrOIsOM5HIdMoqv9t71NMoJDUcAl6
MfbMIxEW8dyC7RChMz3YUWlbDPP23R3G5kTD
bT2iH4cWbhgkcpZGf2tDUt8neMWFdVdzgy8c
EsSDawQv02JeUb7SsZCwhrpfj7B99RvE2FHT
zJZAvF7bF7F2B87JSvuarvksYckRrLN6Vd6I
w6UzumNNBjYOsw1y3pY0WO3BF5hGPGf9A8zu
fxGivMreSlo5lp6JFsbnUK8SH1HqguzSRo0F
q02oIAaQqFvBXFqOKUikYpvXUeQPNx7vd0Ww
xcspJ5BaLPMJCbAZp1MsSEaxTUnvYNbJAZmK
cnlMsCian5gfFgDbbZpZ5pMsdbRFAbmvgzAQ
OVyz7IPPNQE7DlYD82qhMDAJsAJ8np6E6ay2
oNxpWXquVZGRoOvY3PwACcLc0F6984kiKrGi
EaGQM4WH5VEf2OH9x8hnLc8fWJc5NLPSsWpb
nKqvv77q3LcJrXyDMb8ICPI5ZX5oX6WME7A2
8T5HOUtK21EPEJMEBHCt5Mw2nXUuNsLL6GSJ
DnDbk2LCZYfspil2jJhArVYCE4b2ylmpicXP
KBapEyy3XAsGpJ34ZoyjfedT9FlZPQtZS58X
HA8mU8nDXEU2tdbr9O7QDzI8yKcusJCmKAry
cVx5UQFGvkDevellOpPeFqZze5ybzbHNK2It
xfGLFoGsXiZtxpW6DuJgeFyNrnnxFRQ16WCA
RIpvWCdMvkrEoYaqYVmAgYBznssLORhuZOTx
Oq5PBx0d4E6ssT06FI0CNtrXkT4ti2Bxe4At
rrv70yQvAvjBpJ8qfjzxVYcd5ImXo9jCet9T
UBDHf8PWWbWC0bunHyFOyJAyc4tAyKhnLl7n
lf5mJlhflLbYBAH8nbKB2Lp8C4qmalyJVz2t
bFEXDHTf0wWW3kbcM8VV1FSI0PipDmr1biP2
HozZjRhO1l7Uqc2nhiYKDkC45dg5ZURu2l4p
YhnzdwDQjrs89rk5Dli0p1dcxK0yXedxIeMw
A1DdfnctUK475FZI0dZ1iJtZ2s9ixQmxIcYc
Ae8y20H1X2IHgQ6DCuOTepuW1nhR7sH8EFt4
oUAFj16WJ27Q1BVV8S4cdalDp6ZwKRLmdLbS
YlMGccBLiLrl6F3mY4rDIFhqpTYZ5tLTNYZ9
KX107aJWnE1AYEZbDpPPQ23had8kwNr6qUwo
K0TDymjtzak6USOF199vq8pLWzMiWc9udSqI
ROF1azSd9hY8LBRcJUCxbmFNwl11My8rmDUJ
H1DNFv57hHrfqNk5XLpJh1UHWi0f364Bc9O1
CgOXcq6dNbuKnSKDK8M9zrSpVbXIkXymCmHb
zTZw2woP3PdY9gHGeeI3A91lhIsZqrVBcxcg
iYnZHyol6IMPK801042012        8Xrbcq
s9mfwL0aUjySD8H0oaL1ghXIT0f64jcijuLa
xieIhx9Tj5Aerj8hGjj7kYUCJhrxpWoV3Atp
hRg9TbhvpPJHqDIFf6puW9aR3BKelwlXBXXV
yTi5qa7w3htdDu9z1My98bR3lf5kd2PHLcDx
Y3yhvNTl65sJCv4GpJGFPvH7ighmCqaat5GR
EiYLt50Kh3wFUOAayJ0yMMHYquiEynhqWEx0
BHTJy3hD8L2fxPliGlJHYh2It33wZb1a5Kpz

Les paramètres passés au template sont bien contenus dans le rapport final (si, en cherchant bien!)

Voilà tout, au final il est assez simple de disposer de la puissance de Groovy, conjointement à un projet Java classique. Bon courage!


Fichier(s) joint(s) :

0 commentaires: