Introduction à Moustache

1. Vue d’ensemble

Dans cet article, nous allons nous concentrer sur les modèles Mustache et utiliser l’un de ses API https://github.com/spullara/mustache.java ]pour générer du contenu HTML dynamique. .

Moustache est un moteur de template sans logique pour créer du contenu dynamique comme le HTML, des fichiers de configuration, entre autres.

2. Introduction

En termes simples, le moteur est classé dans la catégorie logicless car il n’a pas de constructions prenant en charge les instructions if-else et les boucles for.

Les modèles Mustache sont composés de noms de balises entourés de \ {\ {}} (qui ressemblent à des moustaches - d’où leur nom) et sont protégés par un objet de modèle contenant les données du modèle.

3. Dépendance Maven

La compilation et l’exécution des modèles sont prises en charge par plusieurs langues - côté client et côté serveur.

Pour pouvoir traiter les modèles à partir de Java, nous utilisons sa bibliothèque Java, qui peut être ajoutée en tant que dépendance Maven.

Java 8:

<dependency>
    <groupId>com.github.spullara.mustache.java</groupId>
    <artifactId>compiler</artifactId>
    <version>0.9.4</version>
</dependency>

Java 6/7:

<dependency>
    <groupId>com.github.spullara.mustache.java</groupId>
    <artifactId>compiler</artifactId>
    <version>0.8.18</version>
</dependency>

Nous pouvons vérifier les dernières versions de la bibliothèque dans https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22com.github.spullara.mustache.java%22%20AND%20a% 3A% 22compilateur% 22[Référentiel Maven central].

4. Usage

Examinons un scénario simple qui montre comment:

  1. Écrire un modèle simple

  2. Compiler le modèle à l’aide de l’API Java

  3. Exécutez-le en fournissant les données nécessaires

4.1. Un modèle de moustache simple

Nous allons créer un modèle simple pour afficher les détails d’une tâche à exécuter:

<h2>{{title}}</h2>
<small>Created on {{createdOn}}</small>
<p>{{text}}</p>

Dans le modèle ci-dessus, les champs situés entre les accolades (\ {\ {}}) peuvent être:

  • méthodes et propriétés d’une classe Java

  • clés d’un objet Map

4.2. Compiler le modèle Moustache

Nous pouvons compiler le modèle comme indiqué ci-dessous:

MustacheFactory mf = new DefaultMustacheFactory();
Mustache m = mf.compile("todo.mustache");

MustacheFactory recherche le modèle donné dans le chemin de classe. Dans notre exemple, nous plaçons todo.mustache sous src/main/resources .

4.3. Exécution du modèle Moustache

Les données fournies au modèle seront une instance de la classe Todo dont la définition est:

public class Todo {
    private String title;
    private String text;
    private boolean done;
    private Date createdOn;
    private Date completedOn;

   //constructors, getters and setters
}

Le modèle compilé peut être exécuté pour obtenir du HTML comme indiqué ci-dessous:

Todo todo = new Todo("Todo 1", "Description");
StringWriter writer = new StringWriter();
m.execute(writer, todo).flush();
String html = writer.toString();

5. Sections de moustache et itérations

Voyons maintenant comment lister les tâches. Pour parcourir une liste de données, nous utilisons les sections de Moustache.

Une section est un bloc de code qui est répété une ou plusieurs fois en fonction de la valeur de la clé dans le contexte actuel.

Cela ressemble à quelque chose comme:

{{#todo}}
<!-- Other code -->
{{/todo}}

Une section commence par un dièse (#) et se termine par une barre oblique (/), où chaque signe est suivi de la clé dont la valeur est utilisée comme base pour le rendu de la section.

Voici les scénarios qui peuvent survenir en fonction de la valeur de la clé:

5.1. Section avec liste non vide ou valeur non fausse

Créons un modèle todo-section.mustache qui utilise une section:

{{#todo}}
<h2>{{title}}</h2>
<small>Created on {{createdOn}}</small>
<p>{{text}}</p>
{{/todo}}

Voyons ce modèle en action:

@Test
public void givenTodoObject__whenGetHtml__thenSuccess()
  throws IOException {

    Todo todo = new Todo("Todo 1", "Todo description");
    Mustache m = MustacheUtil.getMustacheFactory()
      .compile("todo.mustache");
    Map<String, Object> context = new HashMap<>();
    context.put("todo", todo);

    String expected = "<h2>Todo 1</h2>";
    assertThat(executeTemplate(m, todo)).contains(expected);
}

Créons un autre modèle todos.mustache pour répertorier les tâches:

{{#todos}}
<h2>{{title}}</h2>
{{/todos}}

Et créez une liste de tâches en utilisant:

@Test
public void givenTodoList__whenGetHtml__thenSuccess()
  throws IOException {

    Mustache m = MustacheUtil.getMustacheFactory()
      .compile("todos.mustache");

    List<Todo> todos = Arrays.asList(
      new Todo("Todo 1", "Todo description"),
      new Todo("Todo 2", "Todo description another"),
      new Todo("Todo 3", "Todo description another")
    );
    Map<String, Object> context = new HashMap<>();
    context.put("todos", todos);

    assertThat(executeTemplate(m, context))
      .contains("<h2>Todo 1</h2>")
      .contains("<h2>Todo 2</h2>")
      .contains("<h2>Todo 3</h2>");
}

5.2. Section avec List ou False ou Null valeur vide

Testons le todo-section.mustache avec une valeur null :

@Test
public void givenNullTodoObject__whenGetHtml__thenEmptyHtml()
  throws IOException {
    Mustache m = MustacheUtil.getMustacheFactory()
      .compile("todo-section.mustache");
    Map<String, Object> context = new HashMap<>();
    assertThat(executeTemplate(m, context)).isEmpty();
}

Et de même, testez todos.mustache avec une liste vide:

@Test
public void givenEmptyList__whenGetHtml__thenEmptyHtml()
  throws IOException {
    Mustache m = MustacheUtil.getMustacheFactory()
      .compile("todos.mustache");

    Map<String, Object> context = new HashMap<>();
    assertThat(executeTemplate(m, context)).isEmpty();;
}

6. Sections Inversées

  • Les sections inversées sont celles qui sont rendues une seule fois en fonction de la non-existence ** de la clé ou de la valeur false ou null ou d’une liste vide.

En d’autres termes, ils sont rendus lorsqu’une section n’est pas rendue.

Celles-ci commencent par un signe (^) et se terminent par une barre oblique (/) comme indiqué ci-dessous:

{{#todos}}
<h2>{{title}}</h2>
{{/todos}}
{{^todos}}
<p>No todos!</p>
{{/todos}}

Le modèle ci-dessus est fourni avec une liste vide:

@Test
public void givenEmptyList__whenGetHtmlUsingInvertedSection__thenHtml()
  throws IOException {

    Mustache m = MustacheUtil.getMustacheFactory()
      .compile("todos-inverted-section.mustache");

    Map<String, Object> context = new HashMap<>();
    assertThat(executeTemplate(m, context).trim())
      .isEqualTo("<p>No todos!</p>");
}

7. Lambdas

Les valeurs pour les clés d’une section moustache peuvent être une fonction ou une expression lambda . Dans ce cas, l’expression lambda complète est appelée en transmettant le texte de la section en tant que paramètre à l’expression lambda.

Regardons un modèle todos-lambda.mustache :

{{#todos}}
<h2>{{title}}{{#handleDone}}{{doneSince}}{{/handleDone}}</h2>
{{/todos}}

La clé handleDone résout une expression lambda Java 8 comme indiqué ci-dessous:

public Function<Object, Object> handleDone() {
    return (obj) -> done ?
      String.format("<small>Done %s minutes ago<small>", obj) : "";
}

Le code HTML généré en exécutant le modèle ci-dessus est:

<h2>Todo 1</h2>
<h2>Todo 2</h2>
<h2>Todo 3<small>Done 5 minutes ago<small></h2>

8. Conclusion

Dans cet article d’introduction, nous avons examiné la création de modèles de moustache avec des sections, des sections inversées et des lambdas. Et nous avons utilisé l’API Java pour compiler et exécuter les modèles en fournissant des données pertinentes.

Il existe quelques fonctionnalités plus avancées de Moustache qui méritent d’être explorées - telles que:

  • fournir un callable en tant que valeur qui entraîne un concurrent

évaluation ** utiliser DecoratedCollection pour obtenir le premier, le dernier et l’index de la collection

éléments ** invert API qui donne les données à partir du texte et du modèle

Et, comme toujours, le code source complet est disponible à l’adresse over sur Github .