用Velocity构建一个Web应用
Velocity在应用中通常用于生成页面,来直接代替JSP。一些使用Velocity来生成Web页面的好处如下:Velocity is often used to generate web pages in applications, usually as a direct replacement for JSP. Some of the benefits of using Velocity to generate web pages are:
- 简单Simplicity -没有多少技术的Web设计者就能书写这些页面。 The pages can be written and maintained by non-technical web designers.
- 容易维护Ease of maintainance - 使用推荐的MVC开发模式,小程序(script)不再出现在Web页面中。Scripting is removed from web pages with the recommended MVC approach.
- 对方法和属性的访问Access both methods and properties - Web设计者可以访问上下文中一个对象的属性和方法。Web designers can reference methods as well as properties of objects in a context.
- 一致性Consistency -Velocity可以被用作其他的文本生成工作(比如发送email),并提供了一致的标记语言。 Velocity can be used for other text generation tasks (such as sending email) providing a consistent way to mark up text.
这篇文档中提供了一些将Velocity用于Web应用中的基本信息。This document provides some basic info on getting started with Velocity in a web application.
使用一个框架
Velocity引擎的主要功能是基于一个模版生成文本。因此,Velocity并没有包含任何与Web相关的功能。The primary purpose of the Velocity engine is simply to generate text based on a template. Consequently, Velocity does not contain any web-related functionality in and of itself. 要创建一个Web应用,你需要一个框架来响应HTTP请求,处理用户认证,调用业务逻辑,并且返回响应。To make a web application, you will need a framework to respond to HTTP requests, handle user authentication, make business logic calls, and generate a response. 下面是一些非常强大的提供者。There are several strong contenders.
- Velocity Tools / VelocityViewServlet - 最简单的开始的方法是下载Velocity Tools子项目,使用VelocityViewServlet。这个servlet的配置和安装都很简单。The easiest way to get started is to download the companion Velocity Tools subproject and use the VelocityViewServlet . This servlet is easy to configure and install.你需要在web服务器上创建一个模版的目录,并编辑一个包含了需要放置在上下文中的"Tools"的列表的XML文件就行了。具体的细节请参见下面的指南。 You create a directory of templates on your web server, edit an XML file that lists various "Tools" to place in the context and you are off. More details can be found in the tutorial below.
- Velocity Tools / VelocityStruts - 也许你对流行的Struts框架比较熟悉。Struts最开始是为了设计一个为JSP提供更多有用的功能的应用。You may be familiar with the popular Struts framework, originally designed to provide much needed application functionality to JSP.在Velocity Tools 的VelocityStruts模块的帮助下,你可以用Velocity代替JSP作为页面的模版语言。这允许你使用Struts强大的基础设施的好处的同时,使用Velocity设计页面。 With the VelocityStruts module of Velocity Tools you can substitute Velocity for JSP as the page template language. This allows you to take advantage of the large base of Struts infrastructure while designing pages using Velocity.
- 第三方框架Third party frameworks - 还有许多的第三方框架在PoweredByVelocity wiki 页面上。There are a number of third party frameworks listed on the PoweredByVelocity wiki page. 在其中,Spring可能是被公认的最先进的框架了。Of these, Spring is probably the most sophisticated and well known. Jakarta Turbine 有许多特点并且也很有用,它基于Velocity并使用Velocity作为主要的页面语言,这并不奇怪,因为有许多Velocity的早期开发者在开发和维护它。Jakarta Turbine has many features and can also be very useful. It was built with Velocity as the primary page language, which is not surprising since many of the original Velocity developers were involved in creating it.一个更简单的选择是Maverick框架,Maverick提供了一个很好的集成了Velocity的简单的控制器结构,但仅此而已。 A simpler alternative is the Maverick framework which provides a simple Controller architecture that integrates nicely with Velocity but has no bells or whistles.
- 构建你自己的Build your own - 最后的一个选择是创建你自己的框架。A final alternative is to build your own framework.建立一个转发servlet(Dispatcher servlet),从一个文件或者数据库中检索出模版,集成你自己的商务逻辑,并返回结果给用户。 Create a dispatcher servlet, retrieve templates from a file or database, integate with your business logic and send the results back to the user. 从一个已有的框架出发并扩展它通常是一更简单的方法。特别的,你只需要为VelocityViewServlet创建一个子类,既能向其中添加新的功能。Often you'll have an easier time starting with one of the existing frameworks and customizing it. In particular you can add new functionality to the VelocityViewServlet simply by creating a subclass.
顺便一提,你可能偶然发现VelocityServlet这个类,该对象是一个在Velocity 1.4版本中不提倡使用的servlet。VelocityServlet已经不再维护,所以,我们强烈建议你使用Velocity Tools中的VelocityViewServlet。As a side note, you may also come across references to VelocityServlet, which is a deprecated servlet that was included in the Velocity Engine up to version 1.4. Since VelocityServlet is no longer being maintained we strongly recommend you use VelocityViewServlet in Velocity Tools instead.
Web方面的问题Web-Specific Issues
对于Velocity在web的应用,有一些问题需要讨论。这些都是经常遇到的问题中的一些简单的讨论。There are a few issues with Velocity that are specific to web applications. Here is a brief discussion of the most commonly encountered issues.
不要改变对象的状态Changing Object State - Don't!
在Velocity中,如果将一个对象作为一个引用,那么Velocity提供了访问该对象的任何方法的能力。在页面中显示信息的时候,这个功能很有用,但是同时如果对象或者应用的状态被改变了,这样做也是很危险的。Velocity provides the ability to call any method of an object acting as a reference. This can be useful when displaying information into the page but is dangerous when object or application state is modified.
举个例子,下面的代码安全的调用了一个list的size()方法并显示结果。For example, the following code safely calls the size() method of a list and displays the result.
There are $users.size() currently logged in.
一个不安全调用的例子:在一个财务web页面上,在上下文中的一个对象能计算每一年的数据。方法calculateNextYear()方法能计算下一年的数据并将一个内部的计数器做增加操作。An example of an unsafe operation concerns a financial web page with an object in the context that calculates data year by year. The method calculateNextYear() calculates data for the next year and advances an internal counter:
2005 data: $table.data
$table.calculateNextYear()
2006 data: $table.data
The problem with this approach is that the code cannot be repeated in multiple parts of the page. You may not intend to do so, but it's easy to forget this when cutting and pasting or writing control statements (such as #if or #foreach). This becomes more of an issue when you are dealing with application or session-level state.
我们强烈建议的实践是只使用Velocity向文本中插入信息。方法调用会是得到信息的一个有效的方法,但一般说来使用一个方法调用来改变对象的状态是一个不良的观念,来改变应用的状态一定是一个错误的想法。The (strongly) recommended practice is to only use Velocity for inserting information into text. Method calls can be useful to retrieve information. However, it's generally a bad idea to use a method call to change object state, and it's always a bad idea to change application state.
如果你必需要改变对象的状态(比如前面的例子),可以预先计算出所有可能的值并放入一个List或则Map对象中。所有的要改变应用的状态的动作应该总是放在控制器中。If you find yourself needing to change object state (as in the previous example) try precalculating all the possible values in the controller and putting them in a List or Map. Any changes to application state should always be done by the controller.
一个相关的注意,你应该在上下文对象中放入一个List或者一个Set对象,而不是放入一个Iterator或者Enumeration。这样允许集合对象在没有改变时重复使用。On a related note, you should always put a List or Set into the context instead of an Iterator or Enumeration. This allows the collection to be used more than once in the page with no change in behavior.
去掉HTML/XML标记Escaping HTML/XML Entities
任何用户添加的带有HTML或者XML标记(比如<,>,&)的文本都应该在填到web页面之前被去掉。为了确保页面正确显示和避免危险的跨站点脚本(cross-site scripting一种攻击手段,在页面中包含另一个带有木马的页面)。不象JSTL(Java标准标记语言),Velocity不包含去除HTML标记的功能,但是你可以通过三种方法来达到目的。Any user-entered text that contains special HTML or XML entities (such as <, >, or &) needs to be escaped before included in the web page. This is required, both to ensure the text is visible, and also to prevent dangerous cross-site scripting. Unlike, for example, JSTL (the Java Standard Tag Language found in Java Server Pages), Velocity does not contain any HTML-specific escaping functionality. However, you have three options:
- 创建一个"Tool",并且包含一个能去掉HTML标记的方法。比如 $escape.html($usertext)。这是最简单的解决问题的方法。Create a special "Tool" (an object in the context) with a method that performs escaping, for example $escape.html($usertext). This is conceptually the easiest way to solve this problem.
- 创建一个自定义的ReferenceInsertionEventHandler ,能自动的去掉所有引用中的HTML标签。如果所有的引用中的内容都需要被检查并去掉HTML标签,那么这样做是最省事的。Create a custom ReferenceInsertionEventHandler that automatically escapes every reference. If all references need to be escaped, this is the most painless method.
- 创建一个自定义的标识,比如#escape,来去掉在该标识对里面的所有引用中的HMTL标签。Create a custom directive (e.g. #escape) that escapes all text within the directive block.
注意,有时候其他的标记也需要被去掉。比如在CSS里面,@需要被去掉,在Javascript,单独的'符号需要从字符串中去掉或替换。Note that other kinds of escaping are sometimes required. For example, in style sheets the @ character needs to be escaped, and in Javascript strings the single apostrophe ' needs to be escaped.
应用的安全Securing the Application
当一个web应用在服务器上开始运行了,有了若干的用户和一些受保护的资源,这时候,应用的安全性方面的要求就显现出来了。Velocity中已经涵盖了大多数标准的web安全性标准。一些特别的问题(比如系统配置,跨站点脚本,或者方法自省)等都在Building Secure Applications with Velocity 这篇文章上有所介绍。Since a web application is running on a central server, that typically has multiple users and confidential resources, care must be taken to make certain that the web application is secure. Most standard web security principles apply to a web application built with Velocity. A few specific issues (such as system configuration, more on cross-site scripting, and method introspection) are written up in this article on Building Secure Applications with Velocity.
日志文件Log Files
还有一点就是Velocity在日志方面的配置比较缺乏。他总是在当前文件夹中创建一个日志文件。当Velocity用在Web应用中的时候,当前文件夹指的是应用开始的那个文件夹。如果你发现"velocity.log"这个文件出现在你文件系统的不固定位置,请检查你的Velocity 日志的配置。一般情况下,出现这个问题的原因是在除了页面生成之外的其他地方还使用了Velocity(比如发送邮件)。A minor point is that Velocity, in the absence of any log-related configuration, creates a log file in the current directory. When Velocity is used in a web application the "current directory" is usually the current directory from which the application server is started. If you start seeing the file "velocity.log" files in random places on your server filesystem, check the Velocity log configuration. Typically this occurs when Velocity is used within a web application outside of web page generation (e.g. for sending email).
指南Tutorial
下面是一个介绍使用VelocityViewServlet来建立一个简单的web应用的简要教程。更多的信息请参见Velocity Tools 的文档。What follows is a brief tutorial on building a simple web app with VelocityViewServlet. For more information, consult the Velocity Tools documentation.
- 从 download page 下载Velocity Tools项目的源代码。里面包含了下面介绍的这个例子的代码。Download the Velocity Tools project source (you need the source for the examples) from download page .
- 请确保你的 Apache Ant 环境安装正确。If you haven't already installed Apache Ant . do so now.
- 使用下面的指令来构建VelocityTools的jar包和"simple"示例。Build the Velocity Tools jar and the "simple" example by typing: ant example.simple
- 察看"examples"文件夹,在里面你会发现一个叫"index.vm"的文件,下面是这个文件的摘录:Take a look at the "examples" directory. You will see a file "index.vm". Here's an excerpt: <html> <body> I'm a velocity template.
#if( $XHTML )
#set( $br = "<br />" )
#else
#set( $br = "<br>" )
#end
$br $br
Here we use a custom tool: $toytool.message
$br $br
Here we get the date from the DateTool: $date.medium
</body>
</html>
你可以复制其他的velocity模版文件到这个文件夹里面。在examples/WEB-INF文件夹下,你会发现一个"toolbox.xml"文件,在这个文件里面就定义了自动放在Velocity上下文中的对象的列表。You can copy any additional velocity files into this same directory. In examples/WEB-INF you will see a file "toolbox.xml". This specifies a list of "Tools" that are automatically included in the context. <toolbox> <xhtml>true</xhtml>
<tool>
<key>toytool</key>
<class>ToyTool</class>
</tool>
<data type="number">
<key>version</key> <value>1.1</value>
</data>
<data type="boolean">
<key>isSimple</key> <value>true</value>
</data>
<data type="string">
<key>foo</key> <value>this is foo.</value>
</data>
<data type="string">
<key>bar</key> <value>this is bar.</value>
</data>
<tool>
<key>map</key>
<class>java.util.HashMap</class>
</tool>
<tool>
<key>date</key>
<scope>application</scope> <class>org.apache.velocity.tools.generic.DateTool</class> </tool>
</toolbox>
最后,应用的web.xml文件里面定义了接受请求的servlet和toolbox的配置文件位置。And finally the web.xml file specifies the name of the servlet and location of toolbox.properties. <web-app> <servlet>
<servlet-name>velocity</servlet-name>
<servlet-class> org.apache.velocity.tools.view.servlet.VelocityViewServlet </servlet-class>
<init-param>
<param-name>org.apache.velocity.toolbox</param-name>
<param-value>/WEB-INF/toolbox.xml</param-value> </init-param>
<load-on-startup>10</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>velocity</servlet-name>
<url-pattern>*.vm</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.vm</welcome-file>
</welcome-file-list>
</web-app>
- 将这个文件夹拷贝到你Tomcat的webapps文件夹下,请拷贝整个文件夹(而不光是simple.war)会让你更容易通过改变或者添加一些东西来做些实验。现在,你可以通过下面的地址来访问页面了。(地址随着你的项目的名字改变)Copy this directory into your "webapps" directory on Tomcat. You could also copy "simple.war", but copying in the entire directory will let you experiment with changes. You should now be able to access your simple one-page webapp with this URL. (or something similar): http://localhost:8080/simple/index.vm
- 尝试添加一些新的Velocity页面。注意,你只需要改变访问的URL地址就可以访问新的页面了。尝试改变toolbox.xml中的一些内容,或者向其中添加你自己的Tools。察看examples/WEB-INF的文档,或者Wiki 来得到更多的工具的使用信息。Experiment with adding new Velocity pages. Note that you can access any velocity page just by changing the URL. Try changing the entries in toolbox.xml or creating your own tools. Consult the Velocity Tools documentation and the Wiki for more info on the wide variety of tools available.