Modèles avec guidons

1. Vue d'ensemble

Dans ce didacticiel, nous examinerons la bibliothèque Handlebars.java pour une gestion facile des modèles.

2. Dépendances de Maven

Commençons par ajouter la dépendance du guidon :

 com.github.jknack handlebars 4.1.2 

3. Un modèle simple

Un modèle Handlebars peut être n'importe quel type de fichier texte. Il se compose de balises telles que {{name}} et {{#each people}}.

Ensuite, nous remplissons ces balises en passant un objet de contexte, comme une carte ou un autre objet.

3.1. Utiliser ceci

Pour transmettre une seule valeur String à notre modèle, nous pouvons utiliser n'importe quel objet comme contexte. Nous devons également utiliser le {{ this}} t ag dans notre modèle.

Ensuite, Handlebars appelle la méthode toString sur l'objet de contexte et remplace la balise par le résultat:

@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!"); }

Dans l'exemple ci-dessus, nous créons d'abord une instance de Handlebars, notre point d'entrée API.

Ensuite, nous donnons à cette instance notre modèle. Ici, nous passons simplement le modèle en ligne, mais nous verrons dans un instant des moyens plus puissants.

Enfin, nous donnons au modèle compilé notre contexte. {{this}} va finir par appeler toString, c'est pourquoi nous voyons "Salut Baeldung!" .

3.2. Passer une carte comme objet de contexte

Nous venons de voir comment envoyer une chaîne pour notre contexte, essayons maintenant une carte :

@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!"); }

Semblable à l'exemple précédent, nous compilons notre modèle puis nous transmettons l'objet de contexte, mais cette fois sous forme de carte .

Notez également que nous utilisons {{name}} au lieu de {{this}} . Cela signifie que notre carte doit contenir la clé, le nom .

3.3. Passer un objet personnalisé comme objet de contexte

Nous pouvons également passer un objet personnalisé à notre modèle:

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; } }

En utilisant la classe Person , nous obtiendrons le même résultat que l'exemple précédent:

@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}} dans notre modèle explorera notre objet Person et obtiendra la valeur du champ de nom .

4. Chargeurs de modèles

Jusqu'à présent, nous avons utilisé des modèles définis dans le code. Cependant, ce n'est pas la seule option. Nous pouvons également lire des modèles à partir de fichiers texte.

Handlebars.java fournit une prise en charge spéciale pour la lecture de modèles à partir du chemin de classe, du système de fichiers ou du contexte de servlet. Par défaut, Handlebars analyse le chemin de classe pour charger le modèle donné:

@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!"); }

Donc, parce que nous avons appelé compile au lieu de compileInline, ceci est un conseil à Handlebars pour rechercher /greeting.hbs sur le chemin de classe .

Cependant, nous pouvons également configurer ces propriétés avec ClassPathTemplateLoader :

@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 }

Dans ce cas, nous demandons à Handlebars de rechercher le /handlebars/greeting.html sur le chemin de classe .

Enfin, nous pouvons chaîner plusieurs instances de TemplateLoader :

@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 }

Donc, ici, nous avons deux chargeurs, et cela signifie que Handlebars recherchera dans deux répertoires le modèle de salutation .

5. Assistants intégrés

Les helpers intégrés nous fournissent des fonctionnalités supplémentaires lors de l'écriture de nos modèles.

5.1. avec Helper

L' assistant with change le contexte actuel :

{{#with address}} 

I live in {{street}}

{{/with}}

Dans notre exemple de modèle, la balise {{#with address}} commence la section et la balise {{/ with}} la termine .

Essentiellement, nous explorons l'objet de contexte actuel - disons p erson - et définissons l' adresse comme contexte local pour la section with . Par la suite, chaque référence de champ dans cette section sera précédée de person.address .

Ainsi, la balise {{street}} contiendra la valeur de 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

"); }

Nous compilons notre modèle et assignons une instance Person comme objet de contexte. Notez que la classe Person a un champ Address . C'est le domaine nous fournir à la avec aide.

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

Enfin, l' assistant if fournit un rendu conditionnel .

{{#if busy}} 

{{name}} is busy.

{{else}}

{{name}} is not busy.

{{/if}}

Dans notre modèle, nous fournissons différents messages en fonction du champ occupé .

@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.

"); }

Après avoir compilé le modèle, nous définissons l'objet de contexte. Puisque le champ occupé est vrai , la sortie finale devient

Baeldung est occupé.

.

6. Aides aux modèles personnalisés

Nous pouvons également créer nos propres helpers personnalisés.

6.1. Assistant

L' interface Helper nous permet de créer un template helper.

Dans un premier temps, nous devons fournir une implémentation de Helper :

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.

Nous avons également étudié les assistants de modèles qui fournissent de nombreuses fonctionnalités. Enfin, nous avons examiné les différentes manières de réutiliser nos modèles.

Enfin, consultez le code source pour tous les exemples sur GitHub.