jetbrick-template-2.x 已经发布,新版文档请看这里:http://subchen.github.io/jetbrick-template/2x/

这个是 jetbrick-template 模板语法参考手册。我们推荐的模板文件扩展名为 .jetx,嵌入式子模板的扩展名为 .inc.jetx

§值 Value

语法:

其中 expression 为任何合法的 Java 表达式,参考: 表达式

示例:

${user.name}
${user.book.available()}
$!{user.description}

注意

  • 如果 expressionnull,则不会输出任何东西,如果需要输出 null,可以使用如下的方法扩展:${expression.asString()}
  • 如果 expression 的返回类型为 void,那么也不会做任何输出动作。

§指令 Directive

§1. 变量类型声明 #define

jetbrick-template 为了提高性能,采用了强类型来编译模板,所以需要为每一个用到的变量定义变量类型。如下:

语法:

示例:

#define(String name)
#define(UserInfo user, List<UserInfo> userlist)

注意

  • 在相同作用域下面,不允许重复定义变量类型,变量只在当前作用域有效。
  • 对于没有定义变量类型,默认作用域为全局有效(Global)。
  • 对于没有定义变量类型,那么优先从上下文表达式中进行类型推导, 否则默认类型为 Object

§2. 赋值语句 #set

语法:

示例:

#set(int num = 1+2*3)
#set(color1 = "#ff0000", color2 = "#00ff00")

注意

  • 在相同作用域下面,不允许重复定义变量类型,变量只在当前作用域有效。
  • 影响当前模板,以及子模板的 JetContext 变量。
  • 不影响父模板的 JetContext 变量。

§3. 赋值语句 #put

将变量内容保存到当前模板以及所有父模板的 JetContext 中,方便父子模板间进行变量传递。

语法:

示例:

#put("num", 1 + 2 * 3)
#put("user", user, "name", "jetbrick")

注意

  • 可以传递多个 key-value 对
  • 参数 name 必须是 String 类型

§4. 条件语句 #if, #elseif, #else

如果 #if 条件表达式计算结果为 true 或非空,则输出指令所包含的块, 否则输出 #else 指令块。

语法:

示例:

#if (user.role == "admin")
    ...
#elseif (user.role == "vip")
    ...
#elseif (user.role == "guest")
    ...
#else
    ...
#end

注意

  • 对于 expression 为非 Boolean 值:非零数字,非空字串,非空集合,非 null 对象,即为 true
  • #elseif 允许出现多次。
  • 如果 #else 后面紧跟着其他文本,比如 #elseABC,那么可以通过添加一对空括号来分割,修改成 #else()ABC。这样可读性就能加强,模板解析也不会出现问题。所有的无参数指令,比如 #end#break#stop 都支持这样操作。() 前面和之间请不要插入任何空格。

§5. 循环语句 #for

循环重复输出指令所包含的块,如果是空的集合对象,那么输出 #else 块。

语法:

#for 支持以下类型的 expression

示例:

#for (book : user.books)
    ${for.index} // 内部循环计数器,从 1 开始计数
    ...
#end

循环变量 id 类型声明,用作强制转型,避免类型推导失败。

#for (Book book : user.books)
    ...
#end

指令 #else 可用于循环为空时的内容输出。

#for (Book book : user.books)
    ...
#else
    No books are found in here.
#end

§5.1 for 内部对象

§6. 循环中断或继续语句 #break, #continue

expressiontrue#break 中断当前循环,而 #continue 跳过余下的内容,跳到下一个循环。

语法:

示例:

#for (book : user.books)
    ...
    #break(book.price > 100)
    ...
#end
#for (book : user.books)
    ...
    #continue(book.price > 100)
    ...
#end

注意

  • 无参数格式代表 expression 永远为 true

§7. 停止解析语句 #stop

expression 为真或非空时,停止模板运行。

语法:

示例:

#stop(error != null)

注意

  • 无参数格式代表 expression 永远为 true

§8. 嵌套模板语句 #include

嵌入一个子模板,将子模板内容输出到当前位置。

语法:

示例:

#include("/include/header.jetx") // 绝对路径
#include("../userinfo.jetx") // 相对路径
#include(file) // 动态路径
#include("/include/header.jetx", {role: "admin"}) // 传递参数

注意

  • 子模板自动共享父模板 JetContext 变量,同时还可以另外传递一些参数给子模板。
  • 子模板可以用 #put 指令修改父模板的 JetContext,然后在父模板中用 context["name"] 获取变量值。

具体用法请查考: 在 jetbrick-template 中如何使用 #include?

§9. 宏定义 #macro

定义一个代码片段,然后可以重复使用。(New from 1.1.0)

语法:

注意: 每个宏可以定义 0~N 个参数。

示例:

#macro header(String name)
    Hello ${name}!
#end

${header("张三")}
${header("李四")}

输出结果:

    Hello 张三!
    Hello 李四!

注意

  • 宏的调用就和函数调用一样。(如果和函数存在名称冲突,那么宏定义优先)
  • 宏的调用返回值是 Void,所以不支持对返回值进行计算。

§10. 自定义标签 #tag

jetbrick-template 支持自定义 Tag,类似于 JSP Taglib,但是要比 JSP Taglib 更简单更好用。(New from 1.1.0)

语法:

注意

  • 需要在 Java 端先定义 Tag 标签的实现。
  • Tag 调用的参数必须和定义的一致。

示例:

#tag layout("layout.jetx")
    Hello ${name}!
#end

具体用法请查考: 在 jetbrick-template 中如何自定义 Tag?

§文本 Text

普通文本内容将会被直接进行输出。

§11. 不解析文本块

原样输出模板内容,用于输出纯文本内容,或批量转义块中的特殊字符。类似于 XML 中的 CDATA。

语法:

示例:

#[[
    Source code will be displayed in here.
    Hello ${user.name}  
]]#

§12. 特殊字符转义

原样输出指令特殊字符,转义字符由 \ 进行转义。

语法:

示例:

\#if
\${user.name}
\\${user.name}

注意

  • 如果遇到类似 #ff0000 类似于指令的内容,但又不是系统定义的指令,那么也会原样输出,并不需要进行转义。
  • \ 后面跟的字符不是 #$,也不需要进行转义,直接输出。

§注释 Comment

§13. 行注释

隐藏行注释的内容,以换行符结束,用于注解过程,或屏蔽指令内容。

语法:

示例:

${user.name} ## This is a line comment.

§14. 块注释

隐藏块注释内容,可包含换行符,用于注解过程,或屏蔽指令内容。

语法:

示例:

#--
    This is a block comment.
--#

§表达式 Expression

支持所有 Java 表达式,并对其进行了一些有用的扩展。

§14.1 与 Java 相同的地方 (运算符优先级和 Java 保存一致)

§14.2 与 Java 不同的地方

§15. 变量名 Variable

可以是任意合法的 Java 变量名:

如:user, user_name, userName

2 个内置的特殊变量:

§16. List 常量

语法:

示例:

[] // empty List
[1, 2, 3, 4, 5]
["abc", 123, new Date(), 1+2*3]

取值:

${list[index]}
${list.get(index)}

// 安全调用
${list?[index]}
${list?.get(index)}

§17. Map 常量

语法:

示例:

{} // empty Map {"name" : "Jason", "statue" : 0} 

取值:

${map.key}
${map["key"]}
${map.get("key")}

// 安全调用
${map?.key}
${map?["key"]}
${map?.get("key")}

§18. Bean 属性调用 bean.property

Bean 属性会解析成 getter 方法调用。

属性查找顺序,以 ${obj.foo} 为例:

  1. 查找 obj.getFoo() 方法
  2. 查找 obj.isFoo() 方法
  3. 查找 obj class 的 foo 字段
  4. 查找 obj.get(name) 方法 (如果是 Map 或者 JetContext)

以上查找过程会在第一次编译的时候完成,不影响性能。
支持对属性返回值的类型推导。

注意jetbrick-template 支持属性的安全调用,和 Groovy 相同,你可以使用 ?. 来代替 .,以避免出现 NullPointerException

§19. Bean 方法调用 bean.method(...)

示例:

## 方法重载 Overload
${"Hello".substring(2)}
${"Hello".substring(2, 3)}

注意jetbrick-template 支持方法的安全调用,和 Groovy 相同,你可以使用 ?. 来代替 .,以避免出现 NullPointerException

§20. 函数调用 function

jetbrick-template 还支持函数调用,如 ${now()}, ${include("tag.jetx")}

具体参考:扩展函数调用

§21. 静态字段调用 @Class.Field

(New from 1.1.0)

语法:

示例:

${@Long.MAX_VALUE}
${@(java.lang.Long).MAX_VALUE}

§22. 静态方法调用 @Class.method

(New from 1.1.0)

语法:

示例:

${@Collections.emptyList()}
${@(java.lang.Long).valueOf("123")}

§默认的方法扩展 Methods

所有方法扩展定义在 jetbrick.template.runtime.JetMethods

§23. 基本数据类型转换 Cast

§24. 集合类型转换 Cast

§25. 数据格式化 Format

§26. 数据 Escape/Unescape

§27. 默认值输出

§28. JSON 输出

§29. 字符串转换

§30. 算术计算

§默认的函数扩展 Functions

所有函数扩展定义在 jetbrick.template.runtime.JetFunctions

§31. 常用函数

§32. 循环计数生成器

生成一个用于循环的数组,主要用于 #for 的循环迭代。

@Deprecated from 1.2.6

New added from 1.2.6

范例:

#for (int i : iterator(1,100))
    ${i}
#end

§33. 嵌入子模板 include(...)

嵌入一个子模板。和 #include 指令的区别,此函数对子模板的输出进行了缓存,可以处理返回的内容,但是效率没有 #include 指令高。

§34. 嵌入纯文本文件 read(...)

§35. 调试专用函数 debug(...)

§36. Web 路径获取 ctxpath() / webroot()

§默认的自定义标签 Tags

所有 Tags 定义在 jetbrick.template.runtime.JetTags

§和 Velocity 的比较

§37. 语法差异

§38. 指令差异

velocity jetbrick-template 异同 功能 变化
${foo.bar}
$foo.bar
${foo.bar} 相同 输出占位符 jetbrick-template 大括号必需
$!{foo.bar}
$!foo.bar
$!{foo.bar} 不同 空值不显示源码 velocity 为空值不显示源码
jetbrick-template 改为HTML过滤输出
## ...
#* ... *#
## ...
#-- ... --#
相似 注释 块注释格式不一样
#[[ ... ]]# #[[ ... ]]# 相同 不解析文本块
\# \$ \\ \# \$ \\ 相同 特殊字符转义
n/a #define(Type foo = bar) 新增 给变量声明类型
#set($foo = $bar) #set(foo = bar)
#set(Type foo = bar)
相同 给变量赋值 可带类型声明
n/a #put(name, value) 新增 保存变量到全局 支持父子模板参数的全局传递
#if($foo == $bar) #if(foo == bar) 相同 条件判断
#elseif($foo == $bar) #elseif(foo == bar) 相同 否定条件判断
#else #else 相同 否定判断
#end #end 相同 结束指令
#foreach($item in $list) #for(item : list)
#for(Type item : list)
相似 循环指令 改为Java格式,可以带类型声明
#break #break
#break(foo == bar)
相同 中断循环 可以直接带条件
n/a #continue
#continue(foo == bar)
新增 继续下一个循环 可以直接带条件
#stop #stop
#stop(foo == bar)
相同 停止模板解析 可以直接带条件
#macro($foo) #macro foo(...) 相似 可复用模板片段宏 velocity 将宏作为指令执行
jetbrick-template 作为函数执行
n/a #tag foo(...) 新增 自定义标签 jetbrick-template 允许自定义标签
#include("foo.txt") read("foo.txt") 相似 读取文本文件内容 jetbrick-template 用扩展函数实现
#parse("foo.vm") #include("foo.jetx")
#include("foo.jetx", args)
相同 包含另一模板输出 jetbrick-template 支持私有参数传递
#evaluate("${1 + 2}") n/a 不同 模板求值 jetbrick-tempate 暂不支持