编写自定义的 Velocity 指令
Velocity 允许您对指令系统进行扩展,在 Velocity 引擎初始化的时候会加载系统内置指令和用户的自定义指令。系统的内置指令已经在 Velocity 的 Jar 包中的 directive.properties 文件中定义,不建议直接修改该文件。而自定义的指令要求用户在 velocity.properties 文件中定义的,例如:userdirective=net.oschina.toolbox.CacheDirective。如果是多个自定义指令则使用逗号隔开。
所有的自定义指令要求扩展 org.apache.velocity.runtime.directive.Directive 这个类。为了更加形象直观的表现 Velocity 自定义指令的优点,接下来我们将以一个实际的应用场景进行讲解。
在该应用场景中,所有的页面请求直接指向 vm 文件,中间没经过任何的控制器。数据是通过 Velocity 的 toolbox 直接读取并显示在页面上。如果数据是来自数据库的,而且访问量非常大的时候,我们就需要对这些数据进行缓存以便快速响应用户请求和降低系统负载。一种方法是直接在 toolbox 的读取数据的方法中进行数据的缓存;另外一种就是我们接下来要介绍的,通过编写自定义的缓存指令来缓存页面上的某个 HTML 片段。
首先我们定义一个这样的块指令:#cache( “ CacheRegion ” , ” Key ” ) ,其中第一个参数为缓存区域、第二个参数为对应缓存数据的键值。该指令自动将包含在指令内部的脚本执行后的结构缓存起来,当第一次请求时检查缓存中是否存在此 HTML 片段数据,如果存在就直接输出到页面,否则执行块指令中的脚本,执行后的结果输出到页面同时保存到缓存中以便下次使用。使用方法如下所示:
-
#cache("News","home")
-
## 读取数据库中最新新闻并显示
-
<ul>
-
#foreach($news in $NewsTool.ListTopNews(10))
-
<li>
-
<span class='date'>
-
$date.format("yyyy-MM-dd",${news.pub_time})
-
</span>
-
<span class='title'>${news.title}</span>
-
</li>
-
#end
-
</ul>
-
#end
其中 $NewsTool.ListTopNews(10)
是用来从数据库中读取最新发布的 10 条新闻信息。
接下来我们来看 #cache
这个指令对应的源码:
-
-
-
-
-
-
public class CacheDirective extends Directive {
-
-
final static Hashtable<String,String> body_tpls = new Hashtable<String, String>();
-
-
@Override
-
public String getName() { return "cache"; }
-
-
@Override
-
public int getType() { return BLOCK; }
-
-
-
-
-
@Override
-
public boolean render(InternalContextAdapter context, Writer writer, Node node)
-
throws IOException, ResourceNotFoundException, ParseErrorException,
-
MethodInvocationException
-
{
-
-
SimpleNode sn_region = (SimpleNode) node.jjtGetChild(0);
-
String region = (String)sn_region.value(context);
-
SimpleNode sn_key = (SimpleNode) node.jjtGetChild(1);
-
Serializable key = (Serializable)sn_key.value(context);
-
-
Node body = node.jjtGetChild(2);
-
-
String tpl_key = key+"@"+region;
-
String body_tpl = body.literal();
-
String old_body_tpl = body_tpls.get(tpl_key);
-
String cache_html = CacheHelper.get(String.class, region, key);
-
if(cache_html == null || !StringUtils.equals(body_tpl, old_body_tpl)){
-
StringWriter sw = new StringWriter();
-
body.render(context, sw);
-
cache_html = sw.toString();
-
CacheHelper.set(region, key, cache_html);
-
body_tpls.put(tpl_key, body_tpl);
-
}
-
writer.write(cache_html);
-
return true;
-
}
-
}
Directive 是所有指令的基类,Directive 是一个抽象类,它有三个方法必须实现的,分别是:
getName:返回指令的名称
getType:返回指令的类型,行指令:LINE、块指令:BLOCK
render:指令执行的入口
其中 render 方法的最后一个参数 node 表示为该指定对应在 Velocity 模板中的节点对象,通过调用 node 的 jjtGetChild 方法可以获取到传递给该指令的参数以及包含在该指令的脚本内容。
上面的代码中,首先获取传递给指令的参数,也就是缓存的区域名和对应缓存数据的键值。接着判断距上次数据被缓存时,指令所包含的脚本代码是否有更改(以便页面开发人员修改了 vm 脚本时自动刷新缓存数据),然后判断缓存中是否已有数据。当缓存中无数据或者页面代码被修改时,重新执行块指令中的脚本并将执行的结果置入缓存,否则直接将缓存中的数据输出到页面。
上述例子中,传递给 #cache 指令的参数也可以是某个变量,例如
#set($region = "news")
#set($key = "home")
#cache("CACHE_$region",$key)
如此,便以很小的代码侵入,来实现页面的缓存。
分享到:
相关推荐
用springMVC+velocity时,当使用自定义标签,发现自定义标签无法注入spring的其它服务类,归根源码发现,velocity的源码中有一段,有一段代码永远获取的是新实例。所以,把这个地方的源码改了,所以使用这个的时候,...
4. **宏**:Velocity 支持宏定义,类似于 HTML 中的自定义标签,可以复用和封装代码,增强模板的模块化。 5. **指令集**:Velocity 提供了多种内置指令,如 #if, #foreach, #set 等,用于控制流程和处理数据。 ** ...
这可能涉及到自定义 Velocity工具或者中间件,使得Velocity引擎能够识别并处理SSI标签,然后将其转换为Velocity语法执行。 例如,我们可以创建一个 VelocityContext 对象,将SSI所需的变量添加进去,然后通过...
JSP的核心概念包括JSP指令、脚本元素、表达式和自定义标签等,这些元素帮助开发者创建动态网页。 **Velocity** 是Apache软件基金会的一个开源项目,它提供了一个简单易用的模板语言,用于分离业务逻辑和表现层。...
例如,可以使用Velocity的内置宏或者自定义函数来自动转义HTML特殊字符,如 `、`>`、`&` 和 `'`。 `EscapeRequestReference`可能是一个类,用于处理HTTP请求中的引用,并确保它们在被插入到Velocity模板中之前得到...
Shiro 会获取当前登录用户的所有权限字符串,并在页面上通过自定义标签来控制内容的展示。例如,使用 `<shiro:hasPermission>` 标签,如果用户具有指定的权限(如 "货运管理"),则显示相应的内容。这使得你能根据...
可以通过`<velocity>`标签在Struts2配置文件中自定义模板路径。 3. **Velocity模板语法**:Velocity模板语言是一种非侵入性的脚本语言,其语法简洁。例如,`$variable`用于引用Java对象,`#if`, `#else`, `#end`...
Velocity通过模板语言,允许开发者用简单的指令来控制页面元素的生成,这些指令可以与Java对象直接交互,无需繁琐的JSP标签或脚本。 二、核心概念 1. 模板(Template):模板是 Velocity 的灵魂,它是静态页面的...
1. 引入依赖:在HTML文件中添加`<script>`标签引入`leaflet.js`、`leaflet-velocity.js`和`leaflet-velocity.css`。 2. 创建地图:使用Leaflet的`L.map`方法创建地图实例,并设置地图的中心点和初始缩放级别。 3. ...
5. **扩展性和灵活性**:模板引擎是否支持自定义标签、函数,以及与其他库的集成程度。 通过对《业务逻辑编译改造-模板技术分析.doc》和“httl-performance-test”文件的深入研究,我们可以获取更多关于这些模板...
手册通常会涵盖变量引用、条件语句、循环结构、函数调用、自定义标签等内容,帮助开发者充分利用Velocity的特性。 此外,压缩包中的"Struts 与 Velocity 的集成.htm"文件可能是对这个主题的深入讲解,而".files...
这两个模板引擎都支持自定义标签,可以根据项目需求扩展功能。 总的来说,Java Web中的这些标签库为开发者提供了丰富的工具,使他们能够更专注于业务逻辑,而不是页面的呈现细节。合理利用这些标签,可以显著提高...
**标签**:“Velocity”标签进一步强调了该文档是关于Velocity的。 **部分内容**:从提供的部分文档内容来看,这是一个详细的介绍如何使用Velocity来渲染DocBook文档的框架。文档包含了前言、简介、如何使用框架、...
3. **可扩展性**:用户可以通过自定义宏(macro)和指令(directive)来扩展 Velocity 的功能,满足不同的开发需求。 4. **易于集成**:Velocity 可以轻松地与其他 Java 应用程序框架集成,如 Struts、Spring 等。 ...
【标签】"velocity-dvsl-1.0.zip" 同样强调了文件的主要内容,即Velocity的DVSL组件,版本1.0。 【压缩包子文件的文件名称列表】:velocity-dvsl-1.0 从这个列表我们可以推测,压缩包内可能包含以下内容: 1. **源...
比如,可以使用条件语句控制内容的显示,使用循环结构生成动态列表,或者通过调用自定义方法来呈现特定的动态内容。 总的来说,Velocity为Web开发提供了一种简洁、高效的模板解决方案,让静态页面内容与动态数据的...
而对于“工具”标签,我们将讨论如何整合自定义模板到Hibernate Tools的构建流程中,使其无缝集成到开发环境中。 【正文】: 1. **理解模板引擎**: - Velocity:Hibernate Tools默认采用Velocity作为模板语言,...
4. **宏库**: 宏是NVelocity中的可重用代码块,类似于HTML中的自定义标签。它们可以提高代码复用性和可维护性。 5. **指令(Control Directives)**: NVelocity提供了一系列的控制指令,如`#foreach`, `#if`, `#else`...
内置对象如request、response、session等可以直接在页面中使用,指令标签如page、include、taglib用于配置页面属性或引入自定义标签库,动作标签如jsp:include、jsp:forward用于控制页面流程。 2. JSTL(JavaServer...
Struts提供了拦截器、自定义标签库等功能,增强了应用的可扩展性和灵活性。 **JDBC(Java Database Connectivity)** 是Java中用于连接数据库的标准API。开发者使用JDBC可以执行SQL语句,进行数据查询、插入、更新...