【译】编写自定义的Velocity指令

本文将使用Apache Velocity API来编写自己的行内指令和块指令。以实现truncate()为例,即实现一个velocity的展示工具方法,用来对长字符串做截断。

在velocity中有两种指令:行内指令和块指令。行内指令在模板中仅有一行vm代码,而块指令有一段代码块同时以#end标签结尾。如下面所示的,第一个为行内指令,第二个为块指令:

编写行指令

为了声明你自定义的指令,你需要在velocity配置文件(比如:velocity.properties)中指定userdirective参数值,如果有多个自定义指令,则需要使用逗号来分割多个自定义指令类的全名。类似下面这样:

下面来创建行内指令#truncate,该指令有4个参数,如下:

第一个参数是需要被截断的字符串,而且是为一个必须的参数。其他几个参数都是用来对截断进行设置的可选参数。具体指令代码如下:

在Apache中所有的指令都继承自Directive 类,它有三个抽象方法需要我们来实现:getName()getType()render()

  • 第一个方法getName() 应该返回指令的名称,该名称将在模板中使用,即#后面的指令名称。
  • 第二个方法getType() 返回 BLOCK 或者 LINE,由你所实现的指令类型决定。
  • 第三个方法render(InternalContextAdapter context, Writer writer, Node node) 是真正起到作用的代码。Writer 是用来写入结果对象的;Node 对象包含了我们的指令信息(指令参数和属性);InternalContextAdapter 包含了Velocity渲染模板所需要的所有的信息。

指令参数(准确的说node就是指令的参数)可以通过调用node.jjtGetChild(i)获得,i是参数的序号(序号从0开始)。你可以调用node.jjtGetNumChildren().获得所有的参数。

jjtGetChild(i) 返回的是一个Node 类型的对象,通过这个对象你可以调用node.jjtGetChild(i).value() 方法来获得已经渲染后的变量的值;你也可以通过调用node.jjtGetChild(i).literal()方法来获得字面值。可以通过下面的代码来解释变量的值和字面值的区别:

(String)node.jjtGetChild(0).value() 的结果是 "This is Test Value", 但(String)node.jjtGetChild(0).literal() 的结果是 "This is $test". 当然大多数情况下,你都是需要变量渲染后的值。

要想测试我们新编写的指令,就得先在配置文件中配置如下的内容:

这样就可以运行模板了:

结果是:

编写块指令

现在我们把刚才编写的行内指令改成块指令,就像这样:

上面的代码和前面行内指令的效果一样,参数也是可选的,来看看指令的代码:

有一点不同是:我们额外的实现了Directive 的init() 方法,该方法可以让我们通过访问RuntimeServices 对象来获取logger实例和配置文件中的指令配置。所以我们的指令配置文件可能是这样的:

在配置文件中设置默认值是可选择的,你可以不设置,因为如果在模板中使用指令时没有传可选参数,我们仍然可以在代码中硬编码默认值。比如下面的代码,设置maxLength 的值为配置文件userdirective.truncateBlock.maxLength 的值,如果没有配置文件没有这个配置,则设置默认值为10。

尽管没有配置参数命名的官方推荐,但是使用userdirective.{directive}.{param} 方式可能会比较好。

render() 方法好像有点不太一样了,原因是块指令中的内容在指令节点的最后一个孩子节点上,但是因为所有参数都是可选的,我们需要某种方式来区分指令的参数和指令块的内容。一个办法是检查孩子节点的类型,如果是指令块的内容,则节点类型为ASTBlock,该类型正好与指令的参数不同。为了渲染ASTBlock 节点的内容,我们需要使用

总结

本文讲解了如何编写Apache Velocity自定义的指令,但是在编写自定义指令前,最好先看看考虑一下往模板中设置工具类的方式,因为编写自己的指令需要预留扩展核心模板语言和支持多参数的能力。例如:如果velocity的展示工具集中没有“truncate”方法,一个合适的方法是创建一个新的工具,并把它添加到velocity工具集中,而不是实现一个指令。(即实现指令的成本比较高)

自定义指令不太复杂,但是没有什么文档和教程支持。如果你需要更多的例子,可以参考velocity tool的源码。你也可以check out我的开源项目htmlcompressor,里面有一些块指令。

Reference

Creating Custom Directives for Apache Velocity

http://www.ibm.com/developerworks/cn/java/j-lo-velocity/

原创文章:【译】编写自定义的Velocity指令,转载请注明:转载自戎码一生

Post Footer automatically generated by wp-posturl plugin for wordpress.