同样也是看Dropwizard才知道这个东西的,以前一直是知道诸如freemarker这样的模板引擎,这个是头一次听说,但是听周围的朋友说最早这个东西是出自于JS的,Dropwizard推荐使用这个东西,而且到mustache官网看了一下,发现十几种语言已经支持这个模板引擎技术,火热程度甚至超过了freemarker,看来到了不得不学的地步了, 先来看看mustache是什么意思,我们都有一个不好的缺点,就是每次看到一个新鲜的东西就想知道他的中文名字叫什么,那么mustache的中文意思是什么?一定头疼?,它的英文是“胡子”,“胡须”的意思,好了不纠结这些东西了,我们先来了解一下mustache的基本知识,以及如何使用吧。
mustache官方给出的是Logic-less templates.翻译过来就是逻辑很少的模板,到底是不是呢?我们在学习的过程中慢慢去体会吧.
Hello {{name}}
You have just won {{value}} dollars!
{{#in_ca}}
Well, {{taxed_value}} dollars, after taxes.
{{/in_ca}}
{
"name": "wangwenjun",
"value": 10000,
"taxed_value": 10000 - (10000 * 0.4),
"in_ca": true
}
Hello wangwenjun
You have just won 10000 dollars!
Well, 6000.0 dollars, after taxes.
Tag本地两对花括号标示出来,例如{{person}},当然{{#person}}也是一个Tag,这两个简单的例子中,我们使用了person作为tag的关键字,至于两种写法的区别在哪里,我们接下来慢慢的讨论。
标签最主要的作用就是当作一个变量来使用,{{name}}标签在模板中会尝试查找name这个关键字在当前的上下文中,如果上下文中不存在name,父上下文将会通过递归的方式去查找,如果最顶级的上下文中依然找不到,name标签将不会被渲染,否则name标签会被替换渲染。
所有的变量在HTML中将会被过滤掉,如果你想返回没有经过转义的HTML元素,你可以使用三个花括号{{{name}}}.
当然你也可以使用&告诉上下文不要进行转义,如:{{&name}},这种方式非常有用,可以在下文中的设置分隔符中看到它的进一步用法,好了看一个简单的例子吧
mustache模板:
* {{name}}
* {{age}}
* {{company}}
* {{{company}}}
Hash 上下文:
{
"name": "Chris",
"company": "GitHub"
}
输出:
* Chris
*
* <b>GitHub</b>
* GitHub
我们一起分析一下模板的输出过程,其中第一个标签被替换为Chris,第二个标签中在整个上下文中不存在,因此不作渲染,第三个我们说过了会被转义,因为有html元素,最后一个如果你想保留html元素就使用三个花括号的形式,这样会被完整的输出。
{{#person}}同样也是一个标签,但是他的作用是块的意思,如果写成{{person}}那么就是一个变量,像前文所说的那样,在本节中,我们来学习一下块的用法,也就是标签的第二个类型
所谓块就是渲染一个区域的文本一次或者多次,当然需要依赖当前上下文中person所代表的内容,块的开始和结束是这样的形式
{{#person}}
balabalabala.
{{/person}}
同样一个块的所有行为也取决于person这个关键字在上下文中的值。
在上面的例子中,如果person这个key存在,并且有一个值是false或者一个空的列表,包含在块之间的元素不会做任何显示的.
模板代码:
Shown.
{{#person}}
Never shown!
{{/person}}
hash 上下文数据:
{
"person": false
}
输出:
Shown.
同样如果person是一个列表,如果它为空,标签内部的内容也是不会被显示出来的.
模板文件:
{{#repo}}
{{name}}
{{/repo}}
Hash 上下文数据:
{
"repo": [
{ "name": "resque" },
{ "name": "hub" },
{ "name": "rip" }
]
}
输出信息:
resque
hub
rip
模板:wrapped是一个标签,准确的讲是一个section标签.
{{#wrapped}}
{{name}} is awesome.
{{/wrapped}}
Hash 上下文数据:
{
"name": "Willy",
"wrapped": function() {
return function(text) {
return "" + text + ""
}
}
}
输出:
Willy is awesome.
在这个例子中我们看到wrapped是一个可以被调用的函数他当标签使用的时候会被再次调用,并且包在其中的其他标签也会被转义执行,这个特性其实非常酷,可以用来做很多很多的事情.
其实就是判断该key是否存在,如果存在则会执行section中的内容,不存在则不会执行.看一下下面的例子吧.
模板:
{{#person?}}
Hi {{name}}!
{{/person?}}
Hash 数据上下文:
{
"person?": { "name": "Jon" }
}
输出结果:
Hi Jon!
Inverted sections使用这样的格式 {{^person}}balabalabala{{/person}}有点类似于if else这样的逻辑语句.
模板文件内容:
{{#repo}}
{{name}}
{{/repo}}
{{^repo}}
No repos :(
{{/repo}}
Hash 上下文:
{
"repo": []
}
输出结果为:
No repos :(
Today{{! ignore me }}.
可以看到在key的前面加一个!操作符号就可以将其过滤不作显示.
Today.
Partials 标签开始是以一个大于号开始,像这样{{> box}}
.
Partials在运行期被渲染 (相对于编译期渲染而言),因此可以使用它来做一些递归,可以避免无限的循环.
它也可以继承上下文的模板.你可以在wiki page [ERB](http://en.wikipedia.org/wiki/ERuby) 中看到如下的信息:
<%= partial :next_more, :start => start, :size => size %>
mustache则只需要如下短短几个字符就可以搞定:
{{> next_more}}
为什么呢? 因为 next_more.mustache
文件将会继承start和size.
这种方式你也许会联想到partials的作用相当于includes或者模板扩展,尽管这不是完全正确的,但是有时候的确可以这样认为.
举一个例子,教你如何使用mustache的特性(说真的,看官方文档,在这部分我起初没明白,最后仔细阅读,才理解它的意思):
base.mustache文件:
Names
{{#names}}
{{> user}}
{{/names}}
user.mustache文件:
{{name}}
上面是两个mustache的模板文件,在运行的过程中base.mustache使用了user.mustache,上面的效果等同于下面的一个模板文件,有时候我们这么写是为了让功能更集中,提高模板的重用率.
Names
{{#names}}
{{name}}
{{/names}}
有些时候我们的确是想修改一下mustache默认的标签分割符号{{}},但是值得庆幸的是,mustache允许我们这样做,而且方法非常简单,我们看一个例子吧
* {{default_tags}}
{{=<% %>=}}
* <% erb_style_tags %>
<%={{ }}=%>
* {{ default_tags_again }}
这里有三个标签,第一个采用默认的分隔符号,然后修改成<%%>这样的风格的风格符号,比关切输出标签内容,接下来又还原回{{}}这样的风格然后输出另外一个标签内容.
好了,截止目前,关于mustache的用法基本上都已经介绍完毕了,最起码官方文档涵盖的东西我全部翻译了过来,应该没有什么遗漏的东西了,在本章节中我们来学习一下如何在Java中使用mustache,并且演示一个综合的应用.
IDEA:intellij IDEA
Maven :3.0.4
websocket
websocket
1.0-SNAPSHOT
4.0.0
mustache
com.github.spullara.mustache.java
compiler
0.7.0
{{#items}}
Name: {{name}}
Price: {{price}}
{{#features}}
Feature: {{description}}
{{/features}}
{{/items}}
package com.wangwenjun.mustache;
import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
public class MustacheExample {
public List- items() {
return Arrays.asList(
new Item("Item 1", "$19.99", Arrays.asList(new Feature("New!"), new Feature("Awesome!"))),
new Item("Item 2", "$29.99", Arrays.asList(new Feature("Old."), new Feature("Ugly.")))
);
}
public static void main(String[] args) throws IOException {
MustacheFactory mf = new DefaultMustacheFactory();
Mustache mustache = mf.compile("template.mustache");
mustache.execute(new PrintWriter(System.out), new MustacheExample()).flush();
}
static class Feature {
private String description;
public Feature(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
public static class Item {
private String name, price;
private List
features;
public Item(String name, String price, List features) {
this.name = name;
this.price = price;
this.features = features;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public List getFeatures() {
return features;
}
public void setFeatures(List features) {
this.features = features;
}
}
}
Name:Item 1
Price:$19.99
New!
Awesome!
Name:Item 2
Price:$29.99
Old.
Ugly.
很多热门的框架,Spring都会对其支持很好的支持,当然这不是spring官方发布的支持版本,而是在github上别人写的封装,我们知道spring mvc不仅提供了jsp,freemarker等视图技术,究其原因就是spring灵活的扩展性,可以很方便增多一种新的视图技术支持.
spring mustache github项目地址为:
https://github.com/sps/mustache-spring-view
pom
com.github.sps.mustache
mustache-spring-view
1.3
com.samskivert
jmustache
${jmustache.version}
com.github.spullara.mustache.java
compiler
${mustache.java.version}