FreeMarker Common Operations

1. Einleitung

FreeMarker ist eine Template-Engine, die in Java geschrieben und von der Apache Foundation verwaltet wird. Wir können die FreeMarker-Vorlagensprache, auch als FTL bezeichnet, verwenden, um viele textbasierte Formate wie Webseiten, E-Mail- oder XML-Dateien zu generieren.

In diesem Tutorial werden wir sehen, was wir mit FreeMarker sofort tun können. Beachten Sie jedoch, dass es recht konfigurierbar ist und sich sogar gut in Spring integrieren lässt.

Lass uns anfangen!

2. Schnellübersicht

Um dynamischen Inhalt in unsere Seiten einzufügen, müssen wir eine Syntax verwenden, die FreeMarker versteht :

  • $ {…} In der Vorlage wird in der generierten Ausgabe durch den tatsächlichen Wert des Ausdrucks in den geschweiften Klammern ersetzt - wir nennen dies Interpolation - einige Beispiele sind $ {1 + 2 } und $ {variableName}
  • FTL-Tags sind wie HTML-Tags (enthalten jedoch # oder @ ), und FreeMarker interpretiert sie beispielsweise
  • Kommentare in FreeMarker beginnen mit <# - und enden mit ->

3. Das Include-Tag

Die FTL- Include- Richtlinie ist für uns eine Möglichkeit, das DRY-Prinzip in unserer Anwendung zu befolgen. Wir definieren den sich wiederholenden Inhalt in einer Datei und verwenden ihn in verschiedenen FreeMarker-Vorlagen mit einem einzigen Include- Tag wieder.

Ein solcher Anwendungsfall ist, wenn wir den Menüabschnitt in viele Seiten aufnehmen möchten. Zuerst definieren wir den Menüabschnitt in einer Datei - wir nennen ihn menu.ftl - mit folgendem Inhalt:

Dashboard Add new endpoint

Und auf unserer HTML-Seite fügen wir die erstellte menu.ftl ein :

Dashboard page

Und wir können auch FTL in unsere Fragmente aufnehmen, was großartig ist.

4. Umgang mit Wertexistenz

FTL betrachtet jeden Nullwert als fehlenden Wert. Daher müssen wir besonders vorsichtig sein und Logik hinzufügen, um Null in unserer Vorlage zu behandeln.

Wir können die ?? Operator, um zu überprüfen, ob ein Attribut oder eine verschachtelte Eigenschaft vorhanden ist. Das Ergebnis ist ein Boolescher Wert:

${attribute??}

Wir haben das Attribut auf null getestet , aber das reicht nicht immer aus. Definieren wir nun einen Standardwert als Fallback für diesen fehlenden Wert. Dazu brauchen wir die ! Operator nach dem Namen der Variablen:

${attribute!'default value'}

Mit runden Klammern können wir viele verschachtelte Attribute umschließen.

Um beispielsweise zu überprüfen, ob das Attribut vorhanden ist und eine verschachtelte Eigenschaft mit einer anderen verschachtelten Eigenschaft hat, schließen wir alles ein:

${(attribute.nestedProperty.nestedProperty)??}

Wenn wir alles zusammenfügen, können wir diese schließlich in statische Inhalte einbetten:

Testing is student property exists: ${student???c}

Using default value for missing student: ${student!'John Doe'}

Wrapping student nested properties: ${(student.address.street)???c}

Und wenn die Schüler waren null , würden wir sehen:

Testing is student property exists: false

Using default value for missing student: John Doe

Wrapping student nested properties: false

Bitte beachten Sie die zusätzliche ? C- Direktive, die nach dem ?? . Wir haben es getan, um den booleschen Wert in eine für Menschen lesbare Zeichenfolge zu konvertieren.

5. Das If-Else-Tag

Kontrollstrukturen sind in FreeMarker vorhanden, und das traditionelle Wenn-Sonst ist wahrscheinlich bekannt:

Während die Zweige elseif und else optional sind, müssen die Bedingungen in einen booleschen Wert aufgelöst werden.

Um uns bei unseren Bewertungen zu helfen, werden wir wahrscheinlich eine der folgenden Methoden verwenden:

  • x == y zu überprüfen ist x ist gleich y
  • x! = y , um nur dann true zurückzugeben , wenn x von y abweicht
  • x lt y bedeutet, dass x streng kleiner als y sein muss - wir können auch < anstelle von lt verwenden
  • x gt y wird nur dann als wahr ausgewertet, wenn x streng größer als y ist - wir können > anstelle von gt verwenden
  • x lte y testet, ob x kleiner oder gleich y ist - die Alternative zu lte ist <=
  • x gte y testet, ob x größer oder gleich y ist - die Alternative von gte ist> =
  • x ?? um die Existenz von x zu überprüfen
  • Sequenz? seqContains (x) überprüft die Existenz von x innerhalb einer Sequenz

Es ist sehr wichtig zu beachten, dass FreeMarker> = und> als Abschlusszeichen für ein FTL-Tag betrachtet. Die Lösung besteht darin, ihre Verwendung in Klammern zu setzen oder stattdessen gte oder gt zu verwenden.

Zusammenstellen für die folgende Vorlage:

${status.reason}

Missing status!

Am Ende erhalten wir den resultierenden HTML-Code:

404 Not Found

Missing status!

6. Container von Untervariablen

In FreeMarker gibt es drei Arten von Containern für Untervariablen:

  • Hashes sind eine Folge von Schlüssel-Wert-Paaren - der Schlüssel muss innerhalb des Hashs eindeutig sein und wir haben keine Reihenfolge
  • Sequenzen sind Listen, in denen jedem Wert ein Index zugeordnet ist. Bemerkenswert ist, dass Untervariablen unterschiedlichen Typs sein können
  • Sammlungen sind ein Sonderfall von Sequenzen, bei denen wir nicht auf die Größe zugreifen oder Werte nicht nach Index abrufen können - wir können sie jedoch trotzdem mit dem Listen- Tag iterieren !

6.1. Iterierende Elemente

Wir können einen Container auf zwei grundlegende Arten durchlaufen. Der erste ist, wo wir über jeden Wert iterieren und Logik für jeden von ihnen haben:

Oder wenn wir einen Hash iterieren möchten, indem wir sowohl auf den Schlüssel als auch auf den Wert zugreifen:

Die zweite Form ist leistungsfähiger, da wir damit auch die Logik definieren können, die in verschiedenen Schritten der Iteration erfolgen soll:

Das Element stellt den Namen der Schleifenvariablen dar, aber wir können es nach Belieben umbenennen. Der else- Zweig ist optional.

Definieren Sie für ein praktisches Beispiel eine Vorlage, in der einige Status aufgelistet sind:


    
  • ${status}

No statuses available

Dies gibt uns den folgenden HTML-Code zurück, wenn unser Container ["200 OK", "404 nicht gefunden", "500 interner Serverfehler"] lautet :


    
  • 200 OK
  • 404 Not Found
  • 500 Internal Server Error

6.2. Artikelhandhabung

Ein Hash ermöglicht uns zwei einfache Funktionen: Tasten zum Abrufen nur der enthaltenen Schlüssel und Werte zum Abrufen nur der Werte.

Eine Sequenz ist komplexer; Wir können die nützlichsten Funktionen gruppieren:

  • Chunk und Join , um eine Subsequenz zu erhalten oder zwei Sequenzen zu kombinieren
  • reverse , sort und sortBy zum Ändern der Reihenfolge der Elemente
  • first und last rufen das erste bzw. letzte Element ab
  • Größe gibt die Anzahl der Elemente in der Sequenz an
  • seqContains , seqIndexOf oder seqLastIndexOf , um nach einem Element zu suchen

7. Typ Handling

FreeMarker bietet eine Vielzahl von Funktionen (integrierten Funktionen) für die Arbeit mit Objekten. Sehen wir uns einige häufig verwendete Funktionen an.

7.1. String-Handling

  • url und urlPath entkommen der Zeichenfolge mit URL, mit der Ausnahme, dass urlPath dem Schrägstrich / nicht entgeht
  • jString , jsString und jsonString wenden die Escape- Regeln für Java, Javascript bzw. JSON an
  • capFirst , uncapFirst , UpperCase , LowerCase und Capitalize sind nützlich, um die Groß- und Kleinschreibung unserer Zeichenfolge zu ändern, wie dies durch ihre Namen impliziert wird
  • boolean , Datum , Zeit , Datumzeit und Anzahl sind Funktionen für die aus einem String zu anderen Typen konvertieren

Lassen Sie uns nun einige dieser Funktionen verwenden:

${'//myurl.com/?search=Hello World'?urlPath}

${'Using " in text'?jsString}

${'my value?upperCase}

${'2019-01-12'?date('yyyy-MM-dd')}

Die Ausgabe für die obige Vorlage lautet:

http%3A//myurl.com/%3Fsearch%3DHello%20World

MY VALUE

Using \" in text

12.01.2019

Bei Verwendung der Datumsfunktion haben wir auch das Muster übergeben, das zum Parsen des String-Objekts verwendet werden soll. FreeMarker verwendet das lokale Format, sofern nicht anders angegeben , beispielsweise in der für Datumsobjekte verfügbaren Zeichenfolgenfunktion .

7.2. Nummernverarbeitung

  • Rund , Boden und Decke können beim Runden von Zahlen helfen
  • abs gibt den absoluten Wert einer Zahl zurück
  • Zeichenfolge konvertiert die Zahl in eine Zeichenfolge. Wir können auch vier vordefinierte Zahlenformate übergeben: Computer , Währung , Zahl oder Prozent oder unser eigenes Format wie [“0. ###”] definieren.

Lassen Sie uns eine Kette einiger mathematischer Operationen durchführen:

${(7.3?round + 3.4?ceiling + 0.1234)?string('0.##')}

Und wie erwartet ist der resultierende Wert 11.12.

7.3. Datumsbehandlung

  • .now steht für das aktuelle Datum und die aktuelle Uhrzeit
  • Datum , Uhrzeit und Datum / Uhrzeit können die Datums- und Zeitabschnitte des Datums- / Uhrzeitobjekts zurückgeben
  • string konvertiert Datums- und Uhrzeitangaben in Zeichenfolgen - wir können auch das gewünschte Format übergeben oder ein vordefiniertes verwenden

Wir werden jetzt die aktuelle Zeit abrufen und die Ausgabe in eine Zeichenfolge formatieren, die nur die Stunden und Minuten enthält:

${.now?time?string('HH:mm')}

Der resultierende HTML-Code lautet:

15:39

8. Ausnahmebehandlung

Es gibt zwei Möglichkeiten, um Ausnahmen für eine FreeMarker-Vorlage zu behandeln.

Der erste Weg besteht darin, Try -Recovery- Tags zu verwenden, um zu definieren, was ausgeführt werden soll, und einen Codeblock, der im Fehlerfall ausgeführt werden soll.

Die Syntax lautet:

Sowohl Versuchs- als auch Wiederherstellungs- Tags sind obligatorisch. Im Fall eines Fehlers, rollt er den versuchten Block zurück und wird ausgeführt , nur den Code in der Wiederherstellung Abschnitt .

Unter Berücksichtigung dieser Syntax definieren wir unsere Vorlage wie folgt:

Preparing to evaluate

Attribute is ${attributeWithPossibleValue??}

Attribute is missing

Done with the evaluation

Wenn attributeWithPossibleValue fehlt, werden wir sehen:

Preparing to evaluate

Attribute is missing

Done with the evaluation

Die Ausgabe, wenn attributeWithPossibleValue vorhanden ist, lautet:

Preparing to evaluate

Attribute is 200 OK

Done with the evaluation

Die zweite Möglichkeit besteht darin, FreeMarker so zu konfigurieren, was im Falle von Ausnahmen geschehen soll.

Mit Spring Boot können wir dies einfach über die Eigenschaftendatei konfigurieren. Hier sind einige verfügbare Konfigurationen:

  • spring.freemarker.setting.template_exception_handler = rethrow löst die Ausnahme erneut aus
  • spring.freemarker.setting.template_exception_handler = debug gibt die Stack-Trace-Informationen an den Client aus und löst die Ausnahme erneut aus.
  • spring.freemarker.setting.template_exception_handler = html_debug gibt die Stack-Trace-Informationen an den Client aus, formatiert sie so, dass sie normalerweise im Browser gut lesbar sind, und löst dann die Ausnahme erneut aus.
  • spring.freemarker.setting.template_exception_handler = ignore überspringt die fehlgeschlagenen Anweisungen und lässt die Vorlage weiter ausgeführt werden.
  • spring.freemarker.setting.template_exception_handler = default

9. Methoden aufrufen

Manchmal möchten wir Java-Methoden aus unseren FreeMarker-Vorlagen aufrufen. Wir werden jetzt sehen, wie es geht.

9.1. Statische Mitglieder

So starten statische Mitglieder Zugriff, könnten wir entweder unsere globale Konfiguration Freemarker aktualisieren oder ein S hinzuzufügen taticModels type - Attribut auf dem Modell unter den Attributnamen Statik :

model.addAttribute("statics", new DefaultObjectWrapperBuilder(new Version("2.3.28")) .build().getStaticModels());

Der Zugriff auf statische Elemente ist unkompliziert.

Zuerst importieren wir die statischen Elemente unserer Klasse mit dem Assign-Tag, entscheiden uns dann für einen Namen und schließlich für den Java-Klassenpfad.

So importieren wir die Math- Klasse in unsere Vorlage, zeigen den Wert des statischen PI- Felds an und verwenden die statische pow- Methode:

PI value: ${MathUtils.PI}

2*10 is: ${MathUtils.pow(2, 10)}

Der resultierende HTML-Code lautet:

PI value: 3.142

2*10 is: 1,024

9.2. Bean-Mitglieder

Bean-Mitglieder sind sehr einfach zu erreichen: Verwenden Sie den Punkt (.) Und das war's!

In unserem nächsten Beispiel fügen wir unserem Modell ein zufälliges Objekt hinzu:

model.addAttribute("random", new Random());

Lassen Sie uns in unserer FreeMarker-Vorlage eine Zufallszahl generieren:

Random value: ${random.nextInt()}

Dies führt zu einer Ausgabe ähnlich der folgenden:

Random value: 1,329,970,768

9.3. Benutzerdefinierte Methoden

Der erste Schritt zum Hinzufügen einer benutzerdefinierten Methode besteht darin, eine Klasse zu haben, die die TemplateMethodModelEx- Schnittstelle von FreeMarker implementiert und unsere Logik innerhalb der exec- Methode definiert:

public class LastCharMethod implements TemplateMethodModelEx { public Object exec(List arguments) throws TemplateModelException  }

Wir werden dem Modell eine Instanz unserer neuen Klasse als Attribut hinzufügen:

model.addAttribute("lastChar", new LastCharMethod());

Der nächste Schritt ist die Verwendung unserer neuen Methode in unserer Vorlage:

Last char example: ${lastChar('mystring')}

Schließlich ist die resultierende Ausgabe:

Last char example: g

10. Schlussfolgerung

In diesem Artikel haben wir gesehen, wie die FreeMarker-Vorlagen-Engine in unserem Projekt verwendet wird. Wir haben uns auf gemeinsame Vorgänge, das Bearbeiten verschiedener Objekte und einige weiterführende Themen konzentriert.

Die Implementierung all dieser Snippets ist über GitHub verfügbar.