Mustache要點總結

蝴蝶飛啊飛發表於2019-11-04

1. 概述

Mustache 屬於無邏輯模板引擎,因為其不支援 if-else for 語句,主要是有 {{}} 括起來的模板變數及包含模板資料的模型物件組成,因為雙括號看起來像鬍子,因此得名 mustache

模板支援多種語言的客戶端和伺服器,當然也可以使用java 庫解析模板,需要引入相應依賴:

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>

2. 實戰使用

示例需求如下:

寫個簡單模板

使用Java Api 編譯模板

提供必要的資料生成動態內容

2.1. 簡單模板

下面模板用於顯示任務資訊,命名為todo.mustache

<h2>{{title}}</h2>

<small>Created on {{createdOn}}</small>

<p>{{text}}</p>

{{}} 中的模板變數可以是 Java 類的方法和屬性,也是 Map 物件的 key

2.2. 編譯模板

編譯模板程式碼:

MustacheFactory mf = new DefaultMustacheFactory();

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

MustacheFactory 在類路徑下搜尋經紀商動態http://www.fx61.com/news模板檔案,我們的模板檔案在 src/main/resources 路徑下。

2.3. 執行模板

提供模板資料是Todo 類的例項:

public class Todo {

    private String title;

    private String text;

    private boolean done;

    private Date createdOn;

    private Date completedOn;

     

    // constructors, getters and setters

}

執行模板生成HTML 內容的程式碼為:

Todo todo = new Todo("Todo 1", "Description");

StringWriter writer = new StringWriter();

m.execute(writer, todo).flush();

String html = writer.toString();

3. Mustache 的節 (Section) 和迭代

下面看如何列出所有事項,即迭代列表資料。這需要使用Mustache 的節 (Section) ,節是根據上下文中 key 的值決定重複一次貨多次的程式碼塊。

示例如下:

{{#todo}}

<!-- Other code -->

{{/todo}}

節以# 號開頭, / 結尾,其中的變數會被解析用於渲染實際內容。下面介紹依據鍵的值可能遇到的場景。

3.1. 非空列表或非假值

首先定義 todo-section.mustache 模板:

{{#todo}}

<h2>{{title}}</h2>

<small>Created on {{createdOn}}</small>

<p>{{text}}</p>

{{/todo}}

來看看解析動作:

@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);

}

我們在看看另一個模板:

{{#todos}}

<h2>{{title}}</h2>

{{/todos}}

使用列表資料進行測試:

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

}

3.2. 空列表、假值或 Null

首先測試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();

}

同樣使用空列表測試todos.mustache

@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();;

}

3.3. 條件表示式

else (inverted section) 用於當上下文變數值為 false null 或空列表時渲染一次,類似於 if...else..., else 部分只執行一次。

使用^ 符號開始, / 結束:

{{#todos}}

<h2>{{title}}</h2>

{{/todos}}

{{^todos}}

<p>No todos!</p>

{{/todos}}

使用空列表進行測試:

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

}

3.4. lambda 表示式

模板中變數的值可以來自函式或lambda 表示式。下面示例傳入 lambda 表示式:

首先定義todos-lambda.mustache 模板:

{{#todos}}

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

{{/todos}}

然後再Todo 類中增加一個函式:

public Function<Object, Object> handleDone() {

    return (obj) -> done ?

      String.format("<small>Done %s minutes ago<small>", obj) : "";

}

最終生成內容為:

<h2>Todo 1</h2>

<h2>Todo 2</h2>

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

完整測試程式碼為:

import com.github.mustachejava.Mustache;

import org.junit.Test;

import java.io.IOException;

import java.io.StringWriter;

import java.time.Instant;

import java.util.*;

import static org.assertj.core.api.Assertions.assertThat;

class MustacheTest {

    private String executeTemplate(Mustache m, Map<String, Object> context) throws IOException {

        StringWriter writer = new StringWriter();

        m.execute(writer, context).flush();

        return writer.toString();

    }

    @Test

    public void givenTodoList_whenGetHtmlUsingLamdba_thenHtml() throws IOException {

        Mustache m = MustacheUtil.getMustacheFactory().compile("todos-lambda.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")

        );

        todos.get(2).setDone(true);

        todos.get(2).setCompletedOn(Date.from(Instant.now().plusSeconds(300)));

        Map<String, Object> context = new HashMap<>();

        context.put("todos", todos);

        assertThat(executeTemplate(m, context).trim()).contains("Done 5 minutes ago");

    }

}

工具類MustacheUtil 程式碼:

public class MustacheUtil {

    private MustacheUtil(){}

    private static final MustacheFactory MF = new DefaultMustacheFactory();

    public static MustacheFactory getMustacheFactory(){

        return MF;

    }

}

本文介紹瞭如何使用mustache 模板引擎,包括條件語法和 lambda 表示式,以及如何使用 Java Api 編譯、渲染模板並生成目標內容


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69946279/viewspace-2662517/,如需轉載,請註明出處,否則將追究法律責任。

相關文章