Vorlage mit Lenker

1. Übersicht

In diesem Tutorial sehen wir uns die Bibliothek Handlebars.java an, um die Vorlagenverwaltung zu vereinfachen.

2. Maven-Abhängigkeiten

Beginnen wir mit dem Hinzufügen der Lenkerabhängigkeit :

 com.github.jknack handlebars 4.1.2 

3. Eine einfache Vorlage

Eine Lenkervorlage kann eine beliebige Textdatei sein. Es besteht aus Tags wie {{name}} und {{#each people}}.

Dann füllen wir diese Tags aus, indem wir ein Kontextobjekt wie eine Karte oder ein anderes Objekt übergeben.

3.1. Verwenden Sie dies

Um einen einzelnen String- Wert an unsere Vorlage zu übergeben, können wir jedes Objekt als Kontext verwenden. Wir müssen auch die {{ this}} t ag in unserer Vorlage verwenden.

Anschließend ruft Handlebars die toString- Methode für das Kontextobjekt auf und ersetzt das Tag durch das Ergebnis:

@Test public void whenThereIsNoTemplateFile_ThenCompilesInline() throws IOException { Handlebars handlebars = new Handlebars(); Template template = handlebars.compileInline("Hi {{this}}!"); String templateString = template.apply("Baeldung"); assertThat(templateString).isEqualTo("Hi Baeldung!"); }

Im obigen Beispiel erstellen wir zuerst eine Instanz von Handlebars, unserem API-Einstiegspunkt.

Dann geben wir dieser Instanz unsere Vorlage. Hier übergeben wir die Vorlage nur inline, aber wir werden gleich einige leistungsfähigere Möglichkeiten sehen.

Schließlich geben wir der kompilierten Vorlage unseren Kontext. {{this}} wird am Ende nur noch String anrufen , weshalb wir "Hi Baeldung!" sehen. .

3.2. Übergeben einer Karte als Kontextobjekt

Wir haben gerade gesehen, wie man einen String für unseren Kontext sendet. Versuchen wir jetzt eine Map :

@Test public void whenParameterMapIsSupplied_thenDisplays() throws IOException { Handlebars handlebars = new Handlebars(); Template template = handlebars.compileInline("Hi {{name}}!"); Map parameterMap = new HashMap(); parameterMap.put("name", "Baeldung"); String templateString = template.apply(parameterMap); assertThat(templateString).isEqualTo("Hi Baeldung!"); }

Ähnlich wie im vorherigen Beispiel kompilieren wir unsere Vorlage und übergeben dann das Kontextobjekt, diesmal jedoch als Map .

Beachten Sie auch, dass wir {{name}} anstelle von {{this}} verwenden . Dies bedeutet, dass unsere Karte den Schlüssel Namen enthalten muss .

3.3. Übergeben eines benutzerdefinierten Objekts als Kontextobjekt

Wir können auch ein benutzerdefiniertes Objekt an unsere Vorlage übergeben:

public class Person { private String name; private boolean busy; private Address address = new Address(); private List friends = new ArrayList(); public static class Address { private String street; } }

Mit der Person- Klasse erzielen wir das gleiche Ergebnis wie im vorherigen Beispiel:

@Test public void whenParameterObjectIsSupplied_ThenDisplays() throws IOException { Handlebars handlebars = new Handlebars(); Template template = handlebars.compileInline("Hi {{name}}!"); Person person = new Person(); person.setName("Baeldung"); String templateString = template.apply(person); assertThat(templateString).isEqualTo("Hi Baeldung!"); }

{{name}} in unserer Vorlage wird in unserem bohren Person Objekt und den Wert des bekommen Name Feld .

4. Vorlagenlader

Bisher haben wir Vorlagen verwendet, die im Code definiert sind. Dies ist jedoch nicht die einzige Option. Wir können auch Vorlagen aus Textdateien lesen.

Handlebars.java bietet spezielle Unterstützung für das Lesen von Vorlagen aus dem Klassenpfad, dem Dateisystem oder dem Servlet-Kontext. Standardmäßig durchsucht Handlebars den Klassenpfad, um die angegebene Vorlage zu laden:

@Test public void whenNoLoaderIsGiven_ThenSearchesClasspath() throws IOException { Handlebars handlebars = new Handlebars(); Template template = handlebars.compile("greeting"); Person person = getPerson("Baeldung"); String templateString = template.apply(person); assertThat(templateString).isEqualTo("Hi Baeldung!"); }

Da wir also compile anstelle von compileInline aufgerufen haben, ist dies ein Hinweis für Handlebars, im Klassenpfad nach /greeting.hbs zu suchen .

Wir können diese Eigenschaften jedoch auch mit ClassPathTemplateLoader konfigurieren :

@Test public void whenClasspathTemplateLoaderIsGiven_ThenSearchesClasspathWithPrefixSuffix() throws IOException { TemplateLoader loader = new ClassPathTemplateLoader("/handlebars", ".html"); Handlebars handlebars = new Handlebars(loader); Template template = handlebars.compile("greeting"); // ... same as before }

In diesem Fall weisen wir Handlebars an, im Klassenpfad nach /handlebars/greeting.html zu suchen .

Schließlich können wir mehrere TemplateLoader- Instanzen verketten :

@Test public void whenMultipleLoadersAreGiven_ThenSearchesSequentially() throws IOException { TemplateLoader firstLoader = new ClassPathTemplateLoader("/handlebars", ".html"); TemplateLoader secondLoader = new ClassPathTemplateLoader("/templates", ".html"); Handlebars handlebars = new Handlebars().with(firstLoader, secondLoader); // ... same as before }

Hier haben wir also zwei Lader, und das bedeutet, dass Lenker zwei Verzeichnisse nach der Begrüßungsvorlage durchsuchen .

5. Eingebaute Helfer

Integrierte Helfer bieten uns zusätzliche Funktionen beim Schreiben unserer Vorlagen.

5.1. mit Helfer

Der with- Helfer ändert den aktuellen Kontext :

{{#with address}} 

I live in {{street}}

{{/with}}

In unserer Beispielvorlage startet das Tag {{#with address}} den Abschnitt und das Tag {{/ with}} beendet ihn .

Im Wesentlichen sind wir Bohrungen in den aktuellen Kontext - Objekt - sagen wir mal p erson - und Einstellungs Adresse als den lokalen Kontext für die mit Abschnitt . Danach wird jeder Feldreferenz in diesem Abschnitt die person.address vorangestellt .

Das Tag {{street}} enthält also den Wert von person.address.street :

@Test public void whenUsedWith_ThenContextChanges() throws IOException { Handlebars handlebars = new Handlebars(templateLoader); Template template = handlebars.compile("with"); Person person = getPerson("Baeldung"); person.getAddress().setStreet("World"); String templateString = template.apply(person); assertThat(templateString).contains("

I live in World

"); }

Wir kompilieren unsere Vorlage und weisen eine Personeninstanz als Kontextobjekt zu. Beachten Sie, dass die Person- Klasse ein Adressfeld hat. Dies ist das Feld wir die Versorgung sind mit Helfern.

Though we went one level into our context object, it is perfectly fine to go deeper if the context object has several nested levels.

5.2. each Helper

The each helper iterates over a collection:

{{#each friends}} {{name}} is my friend. {{/each}}

As a result of starting and closing the iteration section with {{#each friends}} and {{/each}} tags, Handlebars will iterate over the friends field of the context object.

@Test public void whenUsedEach_ThenIterates() throws IOException { Handlebars handlebars = new Handlebars(templateLoader); Template template = handlebars.compile("each"); Person person = getPerson("Baeldung"); Person friend1 = getPerson("Java"); Person friend2 = getPerson("Spring"); person.getFriends().add(friend1); person.getFriends().add(friend2); String templateString = template.apply(person); assertThat(templateString) .contains("Java is my friend.", "Spring is my friend."); }

In the example, we're assigning two Person instances to the friends field of the context object. So, Handlebars repeats the HTML part two times in the final output.

5.3. if Helper

Schließlich bietet der if- Helfer ein bedingtes Rendern .

{{#if busy}} 

{{name}} is busy.

{{else}}

{{name}} is not busy.

{{/if}}

In unserer Vorlage stellen wir je nach Besetztfeld unterschiedliche Nachrichten bereit .

@Test public void whenUsedIf_ThenPutsCondition() throws IOException { Handlebars handlebars = new Handlebars(templateLoader); Template template = handlebars.compile("if"); Person person = getPerson("Baeldung"); person.setBusy(true); String templateString = template.apply(person); assertThat(templateString).contains("

Baeldung is busy.

"); }

Nach dem Kompilieren der Vorlage legen wir das Kontextobjekt fest. Da das beschäftigt Feld ist wahr , wird die endgültige Ausgabe

Baeldung ist beschäftigt.

.

6. Benutzerdefinierte Vorlagenhelfer

Wir können auch unsere eigenen benutzerdefinierten Helfer erstellen.

6.1. Helfer

Über die Helper- Oberfläche können wir einen Template-Helfer erstellen.

Als ersten Schritt müssen wir eine Implementierung von Helper bereitstellen :

new Helper() { @Override public Object apply(Person context, Options options) throws IOException { String busyString = context.isBusy() ? "busy" : "available"; return context.getName() + " - " + busyString; } }

As we can see, the Helper interface has only one method which accepts the context and options objects. For our purposes, we'll output the name and busy fields of Person.

After creating the helper, we must also register our custom helper with Handlebars:

@Test public void whenHelperIsCreated_ThenCanRegister() throws IOException { Handlebars handlebars = new Handlebars(templateLoader); handlebars.registerHelper("isBusy", new Helper() { @Override public Object apply(Person context, Options options) throws IOException { String busyString = context.isBusy() ? "busy" : "available"; return context.getName() + " - " + busyString; } }); // implementation details }

In our example, we're registering our helper under the name of isBusy using the Handlebars.registerHelper() method.

As the last step, we must define a tag in our template using the name of the helper:

{{#isBusy this}}{{/isBusy}}

Notice that each helper has a starting and ending tag.

6.2. Helper Methods

When we use the Helper interface, we can only create only one helper. In contrast, a helper source class enables us to define multiple template helpers.

Moreover, we don't need to implement any specific interface. We just write our helper methods in a class then HandleBars extracts helper definitions using reflection:

public class HelperSource { public String isBusy(Person context) { String busyString = context.isBusy() ? "busy" : "available"; return context.getName() + " - " + busyString; } // Other helper methods }

Since a helper source can contain multiple helper implementations, registration is different than the single helper registration:

@Test public void whenHelperSourceIsCreated_ThenCanRegister() throws IOException { Handlebars handlebars = new Handlebars(templateLoader); handlebars.registerHelpers(new HelperSource()); // Implementation details }

We're registering our helpers using the Handlebars.registerHelpers() method. Moreover, the name of the helper method becomes the name of the helper tag.

7. Template Reuse

The Handlebars library provides several ways to reuse our existing templates.

7.1. Template Inclusion

Template inclusion is one of the approaches for reusing templates. It favors the composition of the templates.

Hi {{name}}!

This is the content of the header template – header.html.

In order to use it in another template, we must refer to the header template.

{{>header}} 

This is the page {{name}}

We have the page template – page.html – which includes the header template using {{>header}}.

When Handlebars.java processes the template, the final output will also contain the contents of header:

@Test public void whenOtherTemplateIsReferenced_ThenCanReuse() throws IOException { Handlebars handlebars = new Handlebars(templateLoader); Template template = handlebars.compile("page"); Person person = new Person(); person.setName("Baeldung"); String templateString = template.apply(person); assertThat(templateString) .contains("

Hi Baeldung!

", "

This is the page Baeldung

"); }

7.2. Template Inheritance

Alternatively to composition, Handlebars provides the template inheritance.

We can achieve inheritance relationships using the {{#block}} and {{#partial}} tags:

  {{#block "intro"}} This is the intro {{/block}} {{#block "message"}} {{/block}}  

By doing so, the messagebase template has two blocks – intro and message.

To apply inheritance, we need to override these blocks in other templates using {{#partial}}:

{{#partial "message" }} Hi there! {{/partial}} {{> messagebase}}

This is the simplemessage template. Notice that we're including the messagebase template and also overriding the message block.

8. Summary

In this tutorial, we've looked at Handlebars.java to create and manage templates.

We started with the basic tag usage and then looked at the different options to load the Handlebars templates.

Wir haben auch die Vorlagenhelfer untersucht, die viele Funktionen bieten. Zuletzt haben wir uns die verschiedenen Möglichkeiten angesehen, unsere Vorlagen wiederzuverwenden.

Überprüfen Sie abschließend den Quellcode für alle Beispiele auf GitHub.