adesso Blog

adesso

Immer mal wieder stolpert man in Projekten über die Anforderung, Word-Dokumente programmatisch zu erzeugen. PDF reicht in solchen Fällen oft als Dateiformat nicht aus, weil die Dokumente aus manuell erstellten Templates erzeugt oder manuell nachbearbeitet werden. Dieser Artikel zeigt, wie man die Open Source Bibliothek “DocxStamper” nutzen kann, um auf Basis eines Templates aus Java-Code heraus ein Word-Dokument zu erzeugen.

DocxStamper

DocxStamper ist eine Open Source Java-Bibliothek, die das .docx-Format mit der Spring Expression Language (SpEL) verknüpft. DocxStamper ist entstanden als Ergebnis von Kundenanforderungen, nachdem eine ausführliche Google-Suche keine einfach zu benutzende Templating-Engine für .docx-Dokumente zu Tage brachte.

Die folgende Abbildung veranschaulicht die Arbeitsweise von DocxStamper.

Funktionsweise von DocxStamper

Wir erstellen ein ganz normales .docx-Dokument, welches als Template dient. In diesem Template verwenden wir SpEL-Expressions, um dynamische Inhalte zu definieren.

Im Java Code definieren wir eine Kontext-Klasse, in der alle dynamischen Inhalte des Dokuments hinterlegt sind. Bei der Generierung eines neuen Dokuments dient das Template zusammen mit einem Objekt dieser Klasse als Input. Die SpEL-Expressions werden dann gegen das Kontext-Objekt ausgewertet und das Ergebnis im neu erzeugten .docx-Dokument ausgegeben.

Im Folgenden schauen wir uns einige Features von DocxStamper noch einmal etwas näher an. Wir gehen dabei von der Anforderung aus, dass wir aus einer Java-Anwendung heraus einen Geschäftsbrief erzeugen möchten, der je nach Empfänger etwas angepasst werden muss.

Um die Beispiele nachzuprogrammieren, muss die folgende Dependency im eigenen Projekt eingetragen werden (Maven-Notation):

<dependency>
    <groupId>org.wickedsource.docx-stamper</groupId>
    <artifactId>docx-stamper</artifactId>
    <version>1.3.0</version>
</dependency>

Die jeweils aktuellste Version kann im Maven Central Repository abgerufen werden.

Platzhalter Ersetzen

Der einfachste Anwendungsfall in so einem Brief ist das Ersetzen von Platzhaltern, zum Beispiel in der Anrede. Die Anrede in unserem Dokument soll so aussehen:

  • “Sehr geehrte Frau Müller,”, wenn es sich um eine Frau handelt, oder
  • “Sehr geehrter Herr Müller,”, wenn es sich um einen Mann handelt.

Alle anderen Anreden klammern wir mal aus, damit das Beispiel einfach bleibt.

Um die Anrede korrekt anzuzeigen, brauchen wir zunächst Informationen über den Nachnamen des Empfängers. Das bilden wir in einer Klasse namens Person ab:

public class Person {
	private String name;
	// Getter und Setter
}

Zusätzlich erstellen wir eine Context-Klasse, die später als Input für die Dokumentenerzeugung dient und zusätzlich noch die Anrede für die jeweilige Person enthält:

public class BriefContext {
    private String anrede;
	private Person person;
	// Getter und Setter
}

In unserem .docx-Template können wir dann die folgende Expression verwenden, um die korrekte Anrede für einen Empfänger zu erzeugen:

 ,
Hier steht der Text des Briefs ...

Mit dem folgenden Code können wir aus diesem Template dann ein Dokument für einen bestimmten Empfänger erzeugen:

BriefContext context = new BriefContext();
Person empfaenger = new Person();
empfaenger.setName("Müller");
context.setAnrede("Sehr geehrte Frau,")
context.setPerson(empfaenger);
InputStream template = ...;  // InputStream, der auf unser Template zeigt
OutputStream out = ...;      // OutputStream, der auf das Ergebnis-Dokument zeigt
DocxStamper stamper =
  new DocxStamperConfiguration()
    .build();
stamper.stamp(template, context, out);
out.close();

Das Ergebnis ist ein Word-Dokument mit der Anrede “Sehr geehrte Frau Müller,”.

Bedingte Anzeige von Elementen

Man möchte die Anrede “Sehr geehrte Frau” bzw. “Sehr geehrter Herr” aber vermutlich gar nicht im Code stehen haben. Eine Template-Engine ist schließlich dafür da solche Text-Schnipsel vom Code in das Template zu verschieben.

Eine Möglichkeit ist es, einfach beide Ausprägungen im Template vorzusehen, und je nach Geschlecht des Empfängers einfach nur die eine oder die andere anzuzeigen.

DocxStamper erlaubt es, Elemente im .docx-Template mit Kommentaren zu versehen, in denen ebenfalls Expressions genutzt werden können. Um einen Paragraphen nur unter einer bestimmten Bedingung anzuzeigen, wird die Expression-Methode displayParagraphIf zur Verfügung gestellt.

Vorausgesetzt, wir ergänzen das Feld gender in der Person-Klasse und befüllen es entsprechend, können wir die Anrede auch mit dem folgenden Template korrekt anzeigen:

Anrede bedingt anzeigen

Im Ergebnis-Dokument wird dann nur eine der beiden Anreden angezeigt und der Kommentar entfernt.

Etwas Vorsicht ist mit Anführungszeichen in den Kommentaren geboten, denn Word ersetzt Anführungszeichen automatisch mit Zeichen, die nicht von der SpEL interpretiert werden können. Um dies zu verhindern, kopiert man diese Zeichen einfach aus einem Texteditor in das Word-Dokument hinein.

DocxStamper bietet noch weitere Methoden zur Nutzung in Kommentar-Expressions an, so zum Beispiel auch zur Wiederholung von bestimmten Elementen.

Elemente Wiederholen

Ein weiterer häufiger Anwendungsfall einer Template-Engine ist es, Elemente zu wiederholen. Im nächsten Schritt erweitern wir unseren Beispiel-Brief um eine Tabelle von Artikeln mit jeweils einem Preis (wie es z.B. für eine Rechnung notwendig wäre).

Um eine Liste von Artikeln anzuzeigen, benötigen wir zunächst eine Datenstruktur für Artikel:

public class Article {
	private long number;
	private String name;
	private Money price;
	// Getter und Setter
}

Um die Artikel unserem Template zur Verfügung zu stellen, ergänzen wir die BriefContext-Klasse um eine Liste von Artikeln:

public class BriefContext {
	private Person person;
	private List<Article> articles;
	// Getter und Setter
}

Nun können wir ein BriefContext-Objekt mit einer Liste von Artikeln befüllen und im Template wie folgt eine Tabelle anlegen, die einen Artikel pro Zeile auflistet:

Tabellenzeilen wiederholen

Datentypen Konvertieren

Im Beispiel mit der Artikelliste haben wir den selbstgebauten Money-Datentyp verwendet, um einen Geldbetrag darzustellen. Platzhalter mit unbekannten Datentypen ersetzt DocxStamper standardmäßig mit dem Ergebnis der toString()-Methode.

In unserem Fall möchten wir den Geldbetrag aber hübsch formatieren, so dass z.B. “47,11 €” angezeigt wird. Um dies zu erreichen, können wir einen eigenen TypeResolver implementieren:

public class MoneyTypeResolver extends AbstractToTextResolver<Money> {
    protected String resolveStringForObject(Money money) {
        // Money-Objekt in gewünschten String umwandeln...
    }
}

Diesen machen wir über die DocxStamperConfiguration bekannt:

DocxStamper stamper = new DocxStamperConfiguration()
  .addTypeResolver(Money.class, new MoneyTypeResolver())
  .build();

Ist der DocxStamper so konfiguriert, werden alle Money-Werte entsprechend der Implementierung in MoneyTypeResolver in Strings konvertiert.

Zusammenfassung

DocxStamper ist eine Library, die grundsätzliche Templating-Features für .docx-Dokumente zur Verfügung stellt.

Sie ist konfigurierbar und erweiterbar, so dass die meisten Anforderungen an eine .docx-Template-Engine mit ihr umgesetzt werden können.

Wenn du neugierig geworden bist, schau auf Github vorbei.

Autor: Tom Hombergs

Als Softwarearchitekt trägt Tom bei der adesso AG die technische Verantwortung in Softwareentwicklungsprojekten im Java-Umfeld und unterstützt die Kunden als Coach in technischen und methodischen Themen rund um die Softwareentwicklung. Als begeisterter Softwareentwickler ist er auf GitHub aktiv und treibt das Thema „Open Source“ innerhalb von adesso an.

Kategorie:

Java

Schlagwörter:

docx

word

  • adesso.de
  • News
  • Blog
  • Word-Dokumente aus Templates Erzeugen mit DocxStamper

Diese Seite speichern. Diese Seite entfernen.

C71.898,22.5,97.219,25.136,96.279,52.11z"/>