Mustache简介

1.概述

在本文中,我们将关注Mustache模板,并使用它的一个JavaAPI来生成动态HTML内容。Mustache是一个无逻辑的模板引擎,用于创建动态内容,如HTML、配置文件等。

2.介绍

简单地说,引擎被归类为无逻辑的,因为它没有支持if-else语句和for循环的构造。Mustache模板由 {{}} 包围的标签名称组成(类似于胡子,因此得名)。

3.Maven依赖

模板的编译和执行可由多种语言支持,包括客户端和服务器端。为了能够处理Java中的模板,我们使用了它的Java库,该库可以作为Maven依赖项添加。 Java 8+:

xml 复制代码
<dependency>
    <groupId>com.github.spullara.mustache.java</groupId>
    <artifactId>compiler</artifactId>
    <version>0.9.4</version>
</dependency>

Java 6/7:

xml 复制代码
<dependency>
    <groupId>com.github.spullara.mustache.java</groupId>
    <artifactId>compiler</artifactId>
    <version>0.8.18</version>
</dependency>

4.用法

让我们看看一个简单的场景,它展示了如何:

  1. 编写一个简单的模板;
  2. 使用Java API编译模板;
  3. 通过提供必要的数据来执行。

4.1一个简单的Mustache模板

我们将创建一个简单的模板来显示待办事项任务的详细信息:

html 复制代码
<h2>{{title}}</h2>
<small>Created on {{createdOn}}</small>
<p>{{text}}</p>

在上面的模板中,卷曲括号({{}})中的字段可以是:

  1. Java类的方法和属性;
  2. Map对象的key

4.2编译Mustache模板

我们可以编译如下所示的模板:

java 复制代码
MustacheFactory mf = new DefaultMustacheFactory();
Mustache m = mf.compile("todo.mustache");

MustacheFactory在类路径中搜索给定的模板。在我们的示例中,我们将todo.mustache放在src/main/resources下。

4.3执行Mustache模板

提供给模板的数据将是Todo类的一个实例,其定义为:

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

可以执行编译后的模板来获得HTML,如下所示:

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

Mustache Sections and Iterations

现在让我们看看如何列出待办事项,为了迭代列表数据,我们使用Mustache sections。section是一个代码块,根据当前上下文中键的值重复一次或多次。 它看起来像:

js 复制代码
{{#todo}}
<!-- Other code -->
{{/todo}}

节以(#)开始,以斜线(/)结束,其中这两个符号后面都跟着一个key,该键的value是渲染section的基础。 以下是根据key的值可能的情况:

5.1具有非空列表或非假值的Section

创建一个模板todo-section.mustache,它使用一个section:

js 复制代码
{{#todo}}
<h2>{{title}}</h2>
<small>Created on {{createdOn}}</small>
<p>{{text}}</p>
{{/todo}}

让我们看看这个模板的作用:

java 复制代码
@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.mustache来列出todos

js 复制代码
{{#todos}}
<h2>{{title}}</h2>
{{/todos}}

并使用它创建一个待办事项列表:

java 复制代码
@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列表为空或值为False或Null的Section

让我们用一个null值测试todo-section.mustache:

java 复制代码
@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();
}

同样,用一个空list测试todos.mustache:

java 复制代码
@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.Inverted Sections

倒置Sections是指基于不存在的key、或者key为false或null值或空列表时,仅渲染一次的部分。换言之,倒置Sections在未渲染Sections时进行渲染。 它们以插入符号(^)开头,以斜线(/)结束,如下所示:

js 复制代码
{{#todos}}
<h2>{{title}}</h2>
{{/todos}}
{{^todos}}
<p>No todos!</p>
{{/todos}}

以上模板在提供空list时:

java 复制代码
@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

mustache section的key的值可以是函数或lambda表达式。在这种情况下,通过将section中的文本作为参数传递给lambda表达式来调用完整的lambda表达式。

让我们来看一个模板todos-lambda.mustache:

js 复制代码
{{#todos}}
<h2>{{title}}{{#handleDone}}{{doneSince}}{{/handleDone}}</h2>
{{/todos}}

handleDone的key解析为Java 8 lambda表达式,如下所示:

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

通过执行上述模板生成的HTML是:

js 复制代码
<h2>Todo 1</h2>
<h2>Todo 2</h2>
<h2>Todo 3<small>Done 5 minutes ago<small></h2>

8.结论

在这篇介绍性文章中,我们研究了创建带有section、inverted section和Lambda的mustache模板。我们使用Java API通过提供相关数据来编译和执行模板。 Mustache的一些更高级的功能值得探索,例如:

  1. 提供一个callable作为value,从而产生并发评估;
  2. 使用DecoratedCollection获取集合元素的第一个、最后一个和索引;
  3. 反转API,在给定文本和模板的情况下提供数据。
相关推荐
_oP_i32 分钟前
Pinpoint 是一个开源的分布式追踪系统
java·分布式·开源
mmsx34 分钟前
android sqlite 数据库简单封装示例(java)
android·java·数据库
武子康1 小时前
大数据-258 离线数仓 - Griffin架构 配置安装 Livy 架构设计 解压配置 Hadoop Hive
java·大数据·数据仓库·hive·hadoop·架构
豪宇刘2 小时前
MyBatis的面试题以及详细解答二
java·servlet·tomcat
秋恬意2 小时前
Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别
java·数据库·mybatis
FF在路上3 小时前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
真的很上进3 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
众拾达人4 小时前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
皓木.4 小时前
Mybatis-Plus
java·开发语言
不良人天码星4 小时前
lombok插件不生效
java·开发语言·intellij-idea