Introduzione a Moustache

1. Panoramica

In questo articolo, ci concentreremo sui modelli Moustache e utilizzeremo una delle sue API Java per produrre contenuto HTML dinamico.

Moustache è un motore di modelli senza logica per la creazione di contenuti dinamici come HTML, file di configurazione tra le altre cose.

2. Introduzione

In poche parole, il motore è classificato come senza logica perché non ha costrutti che supportano istruzioni if-else e cicli for.

I modelli Moustache sono costituiti da nomi di tag circondati da {{}} (che assomigliano a baffi, da cui il nome) e sono supportati da un oggetto modello contenente i dati per il modello.

3. Dipendenza da Maven

La compilazione e l'esecuzione dei modelli sono supportate da più lingue, sia lato client che lato server.

Per poter elaborare i template da Java utilizziamo la sua libreria Java che può essere aggiunta come dipendenza Maven.

Java 8+:

 com.github.spullara.mustache.java compiler 0.9.4 

Java 6/7:

 com.github.spullara.mustache.java compiler 0.8.18 

Possiamo controllare le ultime versioni della libreria nel Central Maven Repository.

4. Utilizzo

Diamo un'occhiata a un semplice scenario che mostra come:

  1. Scrivi un semplice modello
  2. Compila il modello utilizzando l'API Java
  3. Eseguilo fornendo i dati necessari

4.1. Un semplice modello di baffi

Creeremo un semplice modello per visualizzare i dettagli di un'attività da fare:

{{title}}

Created on {{createdOn}}

{{text}}

Nel modello sopra i campi all'interno delle parentesi graffe ({{}}) possono essere:

  • metodi e proprietà di una classe Java
  • chiavi di un oggetto Map

4.2. Compilazione del modello di baffi

Possiamo compilare il modello come mostrato di seguito:

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

MoustacheFactory cerca il modello dato nel classpath. Nel nostro esempio, mettiamo todo.mustache in src / main / resources .

4.3. Esecuzione del modello di baffi

I dati forniti al modello saranno un'istanza della classe Todo la cui definizione è:

public class Todo { private String title; private String text; private boolean done; private Date createdOn; private Date completedOn; // constructors, getters and setters }

Il modello compilato può essere eseguito per ottenere HTML come mostrato di seguito:

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

5. Sezioni e iterazioni dei baffi

Diamo ora uno sguardo a come elencare le cose da fare. Per l'iterazione dei dati di una lista, utilizziamo le sezioni Moustache.

Una sezione è un blocco di codice che viene ripetuto una o più volte a seconda del valore della chiave nel contesto corrente.

Assomiglia a:

{{#todo}}  {{/todo}}

Una sezione inizia con un cancelletto (#) e termina con una barra (/), dove ciascuno dei segni è seguito dalla chiave il cui valore viene utilizzato come base per il rendering della sezione.

Di seguito sono riportati gli scenari che possono verificarsi a seconda del valore della chiave:

5.1. Sezione con elenco non vuoto o valore non falso

Creiamo un modello todo-section.mustache che utilizza una sezione:

{{#todo}} 

{{title}}

Created on {{createdOn}}

{{text}}

{{/todo}}

Diamo un'occhiata a questo modello in azione:

@Test public void givenTodoObject_whenGetHtml_thenSuccess() throws IOException { Todo todo = new Todo("Todo 1", "Todo description"); Mustache m = MustacheUtil.getMustacheFactory() .compile("todo.mustache"); Map context = new HashMap(); context.put("todo", todo); String expected = "

Todo 1

"; assertThat(executeTemplate(m, todo)).contains(expected); }

Creiamo un altro modello todos.mustache per elencare i todos:

{{#todos}} 

{{title}}

{{/todos}}

E crea un elenco di cose da fare usandolo:

@Test public void givenTodoList_whenGetHtml_thenSuccess() throws IOException { Mustache m = MustacheUtil.getMustacheFactory() .compile("todos.mustache"); List todos = Arrays.asList( new Todo("Todo 1", "Todo description"), new Todo("Todo 2", "Todo description another"), new Todo("Todo 3", "Todo description another") ); Map context = new HashMap(); context.put("todos", todos); assertThat(executeTemplate(m, context)) .contains("

Todo 1

") .contains("

Todo 2

") .contains("

Todo 3

"); }

5.2. Sezione Con Vuoto List o False o Null Valore

Testiamo la todo-section.mustache con un valore nullo :

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

And likewise, test todos.mustache with an empty list:

@Test public void givenEmptyList_whenGetHtml_thenEmptyHtml() throws IOException { Mustache m = MustacheUtil.getMustacheFactory() .compile("todos.mustache"); Map context = new HashMap(); assertThat(executeTemplate(m, context)).isEmpty();; }

6. Inverted Sections

Inverted sections are those which are rendered only once based on the non-existence of the key or false or null value or an empty list. In other words, these are rendered when a section is not rendered.

These start with a caret (^) and end with a slash (/) as shown below:

{{#todos}} 

{{title}}

{{/todos}} {{^todos}}

No todos!

{{/todos}}

The above template when provided with an empty list:

@Test public void givenEmptyList_whenGetHtmlUsingInvertedSection_thenHtml() throws IOException { Mustache m = MustacheUtil.getMustacheFactory() .compile("todos-inverted-section.mustache"); Map context = new HashMap(); assertThat(executeTemplate(m, context).trim()) .isEqualTo("

No todos!

"); }

7. Lambdas

The values for keys of a mustache section can be a function or a lambda expression. In such case, the complete lambda expression is invoked by passing in the text within the section as a parameter to the lambda expression.

Let's look at a template todos-lambda.mustache:

{{#todos}} 

{{title}}{{#handleDone}}{{doneSince}}{{/handleDone}}

{{/todos}}

La chiave handleDone si risolve in un'espressione lambda Java 8 come mostrato di seguito:

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

L'HTML generato eseguendo il modello sopra è:

Todo 1

Todo 2

Todo 3Done 5 minutes ago

8. Conclusione

In questo articolo introduttivo, abbiamo esaminato la creazione di modelli di baffi con sezioni, sezioni invertite e lambda. E abbiamo utilizzato l'API Java per compilare ed eseguire i modelli fornendo dati rilevanti.

Ci sono alcune funzionalità più avanzate di Moustache che vale la pena esplorare, come:

  • fornendo un callable come valore che si traduce in una valutazione simultanea
  • utilizzando DecoratedCollection per ottenere il primo, l'ultimo e l'indice degli elementi della raccolta
  • invert API che fornisce i dati forniti dal testo e dal modello

E, come sempre, il codice sorgente completo per questo è disponibile su Github.