`
gstarwd
  • 浏览: 1526889 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Introduction to Velocity(2)

阅读更多
Velocity 是一个高效、简洁的 Java 模板引擎,而且有很好的可扩展性,这使之特别适合在 Web 项目中使用。本文通过一个实际应用例子对 Velocity 的模板语言中的指令系统进行了介绍,并演示了如何通过编写自定义的指令来扩展 Velocity 的功能。

< include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters >

Velocity 及其指令简介

Velocity 是一个基于 Java 的模板引擎,它允许用户使用简单的模板语言来引用由 Java 代码定义的对象。当 Velocity 应用于 Web 开发时,界面设计人员可以和 Java 程序开发人员同步开发一个遵循 MVC 架构的 Web 站点。也就是说,页面设计人员可以只关注页面的显示效果,而 Java 程序开发人员关注后台业务逻辑的编码。 Velocity 将 Java 代码从 Web 页面中分离出来,这样为 Web 站点的长期维护提供了便利,同时也为我们在 JSP 和 PHP 之外又提供了一种可选的方案。

Velocity 的能力不仅仅用于 Web 开发领域,它也可以被当作一个独立工具来产生源代码和报告(例如,可以产生 SQL 和 PostScript、XML 等),或者作为其他系统的集成组件使用。

下面是一个简单的用 Velocity 编写的网页代码:

 

<html> 
 <head> 
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
  <meta http-equiv="Content-Language" content="zh-CN"/> 
  <title>$page_title</title> 
  <link rel="stylesheet" href="osc-global.css" type="text/css" /> 
 </head> 
 <body> 
 <div id="OSC_top"> 
	 #parse("header.vm") 
 </div> 
 <div id="OSC_content"> 
 <table> 
	 #foreach($idx in [1..20]) 
	 <tr> 
		 <td>$velocityCount</td> 
		 <td>Now is $date.now()</td> 
	 </tr> 
	 #end 
 </table> 
 </div> 
 <div id="OSC_bottom"> 
	 #include("bottom.vm") 
 </div> 
 </body> 
 </html>
   

在 Velocity 模板语言的语法中,以美元符 $ 开头的为变量的声明或者引用,而以井号 # 开头的语句则为 Velocity 的指令(Directive)。其中 Velocity 的指令又分为内置指令、自定义宏和自定义指令。 Velocity 包含下列这些内置指令:

#set 赋值指令
#if/#elseif/#end if 条件判断指令
#foreach 循环指令
#include 嵌入静态内容
#parse 嵌入动态内容
#stop 停止执行下面代码
#evaluate 执行指令
#define 定义脚本
#marco 宏定义

 

另外也可以通过宏来扩展指令,例如,请看下面这个宏的定义:

#macro(invoke $__p_page) 
    #if($__p_page.startsWith("/")) 
        #parse($__p_page) 
    #else 
        #set($__uri = $resource.this_vm()) 
        #set($__path = $__uri.substring(0, $__uri.lastIndexOf("/"))) 
        #parse("$__path/$__p_page") 
    #end 
 #end
 

 

上面这个名为 invoke 的宏的作用是以相对路径的方式嵌入某个动态的页面。使用的方法是 #invoke( “ hello.vm ” ) 。尽管 Velocity 的自定义宏可以用来扩展指令,但是宏有一个不足的地方,它更适合用来执行一些比较通用的代码嵌入和简单的功能处理。

由此引出来的问题是,我如何来编写一个类似于 #foreach 的指令呢,并具有逻辑判断的功能?

Velocity 的指令类型简介

在 Velocity 的指令定义上,有两种指令类型分别是行指令和块指令。行指令例如 #set($name= ” Winter Lau ” ) 赋值指令,只有一行,中间没有任何的代码;而块指令例如循环指令 #foreach($idx in [1..20]) $idx #end ,块指令需要用 #end 来结束。在 Velocity 自带的指令中块指令包括有:#if #elseif #foreach #define#macro 这几个指令,除此之外都是行指令。

编写自定义的 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 这个指令对应的源码:

/**
 * Velocity模板上用于控制缓存的指令
 * @author Winter Lau
 * @date 2009-3-16 下午04:40:19
 */
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; } //指定指令类型为块指令

    /* (non-Javadoc)
    * @see org.apache.velocity.runtime.directive.Directive#render()
    */
    @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)

 

如此,便以很小的代码侵入,来实现页面的缓存。

自定义指令在 Veloeclipse 插件中的使用事项

Veloeclipse 是一个在 Eclipse 开发环境中编辑 Velocity 模板和 HTML 代码的插件,具有语法着色、自动代码完成以及错误提示等功能。如果在编辑 Velocity 模板时使用了自定义插件,则该插件会提示错误,我们可以通过下面的界面添加自定义的指令来使 Veloeclipse 支持这些指令。

点击菜单 Windows - Preferences - Veloeclipse ,通过如下的界面来添加自定义指令。


图 1. 添加自定义指令的界面
添加自定义指令的界面

总结

Velocity 是一个非常高效、简洁的 Java 模板引擎,而且其强大的扩展性,使之特别适合在 Web 项目中使用。本文通过一个实际应用中的例子对 Velocity 的指令系统进行了介绍,欢迎大家跟我一起深入探讨 Velocity 的相关扩展问题。

分享到:
评论

相关推荐

    An_introduction_to_computational_fluid_dynamics.pdf

    Basic introduction to computational fluid dynamics, using the finite volume method. Table of Contents Preface Acknowledgements 1 Introduction 1 2 Conservation Laws of Fluid Motion and ...

    Introduction to MATLAB for Engineers

    This guide offers an introduction to MATLAB, focusing on applications relevant to engineers. #### Chapter One: Basics - **1.1–1 Volume of a Circular Cylinder**: This section introduces basic ...

    A Mathematical Introduction to Robotic Manipulation_Murray

    - **刚体速度**(Velocity of a RigidBody): - 分析了刚体线速度和角速度的关系。 - 讨论了如何通过坐标变换来求解不同参考系下的速度问题。 - **力和逆螺线**(Wrenches and Reciprocal Screws): - 定义了力...

    Introduction to Scientific Computing and Data Analysis.pdf

    这些数据集通常具有三个主要特征:大量(Volume)、高速(Velocity)和多样(Variety)。本书可能涉及如何使用科学计算和数据分析技术来处理大数据集,以获取有价值的信息和洞见。 ### 部分内容解析 这部分内容提供...

    Velocity使用指南 删除掉多余表格

    4. Velocity 模版语言(VTL):入门 Velocity Template Language (VTL): An Introduction VTL 提供了一系列的指令(Directives)和引用机制,如变量(Variables)、属性(Properties)和方法(Methods),使得模板...

    Game physics

    INTRODUCTION 1.1 a brief history of the world 1.2 a summary of the topics 1.3 Examples and Exercises Basic Concepts from Physics 2.1 Rigid body Classification 2.2 Rigid body Kinematics 2.2.1 ...

    OpenStack.Trove.1484212223

    and data analysts looking to improve velocity by being able to quickly provision and release database capacity. Table of Contents Chapter 1 An introduction to Database-as-a-Service Chapter 2 ...

    Sams.Teach.Yourself.Big.Data.Analytics.with.Microsoft.HDInsight

    Introduction to Hadoop, Architecture, Ecosystem and Microsoft HDInsight Getting to know Hadoop 2.0 and the innovations it provides like HDFS2 and YARN Quickly installing, configuring, and monitoring ...

    Big Data Made Easy - A Working Guide To The Complete Hadoop Toolset

    #### Introduction to Big Data and Hadoop In today's digital era, the volume and variety of data generated by businesses and organizations have grown exponentially. Traditional data processing methods...

    Big Data Fundamentals(PrenticeHall,2016)

    Big Data Fundamentals provides a pragmatic, no-nonsense introduction to Big Data. Best-selling IT author Thomas Erl and his team clearly explain key Big Data concepts, theory and terminology, as well ...

    基于多机器人协作的未知环境下路径探索研究

    Chapter 2 Local Obstacle Avoidance based on Velocity Space Method………25 2.1 Introduction…………………………………………………………………………25 2.2 Velocity Space Method………………………………...

    Introduction-to-Big-Data:CIND119-使用SAS,SQLiteStudio,MongoDB的大数据简介

    本课程“Introduction-to-Big-Data:CIND119”旨在为初学者提供一个全面的大数据介绍,主要通过SAS、SQLiteStudio和MongoDB这三种工具来教授大数据的处理、分析和存储。这三个工具在大数据领域各具特色,SAS以其强大...

    Plasmonics : Fundamentals and Applications

    - **Dispersion of the Free Electron Gas and Volume Plasmons:** Dispersion refers to the change in wave velocity with frequency. In metals, volume plasmons (bulk plasmons) are excited when the ...

    Who's the DMO coverage

    events have long been overcome by the introduction of the dip-moveout (DMO) correction. However, the concept of coverage has not yet satisfactorily been updated to a `DMO coverage' consistent with DMO...

    Signal Integrity - Simplified(Eric Bogatin).pdf

    Introduction to Modeling Section 3.11. The Bottom Line Chapter 4. The Physical Basis of Resistance Section 4.1. Translating Physical Design into Electrical Performance Section 4.2. The Only Good ...

Global site tag (gtag.js) - Google Analytics