Es gibt unterschiedliche Template Engine, wie zum Beispiel Apache Velocity aber auch Apache Freemarker.
Bei der Verwendung von Templates, kann man sich einfach auf die Präsentation der Daten konzentrieren. Das läuft nach dem MVC (Model View Controller) Pattern. Die Templats können auch über diesen Online FreeMarker Template Tester ohne Aufwand getestet werden.
Heute mal ein kleines Beispiel, mit Freemarker. Wir wollen Verzeichnisse nach Mindmaps durchsuchen, und alle gefundenen Mindmaps in eine HTML-Seite ausgeben.
Fangen wir mit einem JUnit Test an:
Hier die Testmethode:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@Test @DisplayName("Schreibt eine HTML Seite mit FreeMarker Generator") public void generateHtmlSeite() { List<String> verzeichnise = new ArrayList<String>(Arrays.asList(MINDMAP_INPUT_VERZEICHNISSE)); Generator generator = new Generator(); Configuration cfg = generator.getKonfiguration(CONFIG_DIR); int anzahlMindmpas = generator.generate(ERGEBNIS_HTML, MINDMAP_TEMPLATE, verzeichnise, cfg); assertEquals(654, anzahlMindmpas, "Die Anzahl der Mindmaps hat sich verändert."); } |
Wir brauchen einmalig (Singelton) eine Configuration, hier die Methode:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/** * Liefert die Konfiguration. Dies muss nur einmal (Singelton) aufgerufen * werden. * * @param configPath der Path zu der Konfiguration * @return die Konfiguration */ public Configuration getKonfiguration(String configPath) { // einmalig die Konfiguration anlegen Configuration cfg = new Configuration(Configuration.VERSION_2_3_28); try { cfg.setDirectoryForTemplateLoading(new File(configPath)); cfg.setDefaultEncoding("UTF-8"); cfg.setLocale(Locale.GERMANY); cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); cfg.setLogTemplateExceptions(false); cfg.setWrapUncheckedExceptions(true); } catch (IOException e) { System.err.println("Fehler beim laden der Template Konfiguration. " + configPath + " " + e.getMessage()); } return cfg; } |
Und dann die Methode, die die eigentlich Arbeit macht, die auch mehrfach aufgerufen werden kann:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
private void generateHtml(String ausgabeHtmlDateiName, String mindmapTemplate, List<Mindmap> inputMindmaps, Configuration configuration) { // Datenmodell anlegen für die Nutzung im Template Map<String, Object> datenModell = new HashMap<String, Object>(); datenModell.put("user", "Thomas Wenzlaff"); datenModell.put("mindmaps", inputMindmaps); datenModell.put("datum", new Date()); try { // das Mindmap Template holen, es wird gecached Template template = configuration.getTemplate(mindmapTemplate); // Datenmodel mit dem Template zusammenfügen und in der Konsole und // Ergebnis.html ausgeben Writer outputWriter = new OutputStreamWriter(System.out); template.process(datenModell, outputWriter); Writer fileWriter = new FileWriter(new File(ausgabeHtmlDateiName)); try { template.process(datenModell, fileWriter); } finally { fileWriter.close(); } } catch (TemplateException | IOException e) { System.err.println("Fehler im Template. " + mindmapTemplate + " " + e.getMessage()); } } |
Damit die obige Methode mehrfach aufgerufen werden kann, verwende ich diese Methode, die aber für die Funktionsweise der Template-Engine nicht nötig ist:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/** * Generiert für die Input Verzeichnise mit dem Freemarker Template eine Ausgabe * Datei im HTML Format. * * @param ausgabeHtmlDateiName der zu erzeugende HTML Dateiname * @param mindmapTemplate der Name des Freemarker Template * @param inputVerzeichnise alle Input Verzeichnisse wo Mindmaps gesucht * werden * @param configuration Konfiguration * @return die Anzahl der bearbeiteten Mindmaps */ public int generate(String ausgabeHtmlDateiName, String mindmapTemplate, List<String> inputVerzeichnise, Configuration configuration) { checkParameter(ausgabeHtmlDateiName, mindmapTemplate, inputVerzeichnise, configuration); List<Mindmap> mindmaps = new ArrayList<>(); for (String inputVerzeichnis : inputVerzeichnise) { mindmaps.addAll(getMindmaps(inputVerzeichnis)); } // Sortieren der Mindmaps von A-Z Collections.sort(mindmaps); generateHtml(ausgabeHtmlDateiName, mindmapTemplate, mindmaps, configuration); return mindmaps.size(); } |
Ein einfaches Mindmap BE brauchen wir auch noch:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
package de.wenzlaff.mindmap.be; import java.nio.file.Path; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.Objects; /** * Eine Mindmap BE. * * @author Thomas Wenzlaff * */ public class Mindmap implements Comparable<Mindmap> { private Path path; public Path getPath() { return path; } public void setPath(Path path) { this.path = path; } public String getErstelldatum() { return new Date(getPath().toFile().lastModified()).toGMTString(); } /** * LIefert den Namen der Mindmap Datei. * * @return der Name der Datei. */ public String getName() { return getPath().getFileName().toString(); } /** * Liefert die Größe der Mindmap Datei in kB (1000). * * Im Template Aufruf z.B.: (${mindmap.size} kB) * * @return die Größe der Datei in kB. */ public String getSize() { return "" + getPath().toFile().length() / 1000; } @Override public int hashCode() { return Objects.hash(path); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Mindmap other = (Mindmap) obj; return Objects.equals(path, other.path); } /** * Der Name der Mindmap ohne Prefix. */ @Override public String toString() { return getName().substring(0, getName().length() - 5); } /** * Zum sortieren von A-Z nach Namen. */ @Override public int compareTo(Mindmap mindmap) { return getName().compareTo(mindmap.getName()); } } |
Nun brauchen wir noch ein Apache Freemarker Template:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<html> <head> <title>Mindmaps von ${user}</title> </head> <body> <h1>Mindmaps von ${user}!</h1> <BR> <#list mindmaps as mindmap> ${mindmap}, </#list> <BR> <h1>Anzahl Mindmaps ${mindmaps?size}</h1> Generiert mit TWMindmapGernerator am ${datum?datetime} Uhr </body> </html> |
Dies Template, kann man leicht ändern, um Anpassungen an der Ausgabe zu erhalten.
Dann brauchen wir eine pom.xml mit den Freemarker und JUnit Abhängigkeiten:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>de.wenzlaff.twmindmapgenerator</groupId> <artifactId>de.wenzlaff.twmindmapgenerator</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <junit.jupiter.version>5.0.0-M2</junit.jupiter.version> <junit.vintage.version>4.12.0-M2</junit.vintage.version> <junit.platform.version>1.0.0-M2</junit.platform.version> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <source>${maven.compiler.source}</source> <target>${maven.compiler.target}</target> <encoding>${project.build.sourceEncoding}</encoding> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.28</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>${junit.jupiter.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> <version>${junit.vintage.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> </project> |
Das ist eigentlich alles für das generieren. Jetzt nur noch die Verzeichnisse einlesen und das Ergebnis ausgeben, durch das Starten des JUnit Tests:
Jetzt kann man durch eine kleine Änderung des Templates, z.B. eine Tabelle ausgeben:
1 2 3 4 5 |
<table> <#list mindmaps as mindmap> <tr><td>${mindmap}</td> <td>(${mindmap.size} kB)</td> <td>${mindmap.erstelldatum}</td></tr> </#list> </table> |
Die dann so aussieht:
Genauso könnte man leicht CSV oder auch sonstige Dateiformate ausgeben.
Das ganze Projekt kann von GitLab geladen werden mit
git clone https://gitlab.com/IT-Berater/twmindmapgenerator.git