原文名称《Web Application Guide》,副标题为基于Web的应用技术和VelocityViewServlet入门,地址为此处链接。文章分为四部分,第一部分,通览使用Velocity创建Web应用的好处,第二部分,讲述需要使用的具体框架,第三部分,主要探讨使用Velocity时的问题,第四部分,讲解一个入门实例。
使用Velocity创建Web应用
Velocity通常被用来生成web页面,可以直接替代JSP,以下是使用Velocity的好处:
- 简单 - 不懂技术的网页设计者可以直接使用和维护。
- 易于维护 - 不包含脚本语言?
- 直接访问方法和属性 - 网页设计者也可以访问对象的方法和属性。
- 一致性 - Velocity不仅可以生成网页,也可以完成其他文本生成任务(如邮件发送)。
配合使用的具体框架
Velocity引擎的主要目的仅仅是为了生成文本,而且在模板基础上生成。因此,Velocity自己不包含任何web相关的功能,所以,我们还是需要一个框架来响应HTTP请求、来处理用户认证、来形成业务逻辑调用、以至形成响应,以下列出几个好的选择:
1. Velocity工具之一:VelocityViewServlet(Velocity视图服务器小程序) - 最简单的开始使用 Velocity的方法是下载 Velocity Tools 并使用 VelocityViewServlet。这个服务器端小程序非常容易配置和安装。方法如下:服务器目录下创建模板文件夹-->编辑XML文件列上各种“工具”(放在页面中的)-->完工。
2. Velocity 工具之二:VelocityStruts (Velocity支撑程序)-- 我们可能比较熟悉流行的 Struts 框架,它原来是设计为JSP提供丰富功能的。而使用 VelocityStruts,你就可以让 Velocity 完全替代 JSP啦,VelocityStruts可以让你充分利用 Struts框架的优势。
3. 第三方框架 -- 在Wiki页面还列出了很多第三方框架,查看 PoweredByVelocity 页面。其中,Spring 可能是最知名的一个。Apache Turbine 也有很多特色且用处不小,Turbine 将 Velocity 作为主要的页面语言,Turbine 本身就是那些开发 Velocity 的程序员创建的。更为简单的框架还包括 Click 或者 Maverick ,他们提供了简单的控制器框架,能与Velocity完美整合。
4. 自己动手 -- 我们还可以自己创建框架。我们可以创建小程序来调度、从文件或数据库获取模板、整合业务逻辑并发送结果给用户。通常,从现有的框架开始进一步修改它是个不错的选择。特别的,你可以通过创建子类的方式向 VelocityViewServlet 添加新的功能。
最后声明,VelocityServlet 再也不会被维护,而被 VelocityViewServlet 替代。
Web相关棘手问题
Web应用开发涉及到很多问题,以下列出一些最常遇到的:
令人头疼的资源载入问题
默认的 Velocity 引擎设置中使用 FileResourceLoader,这个配置对于那些不使用 servlet 引擎的应用来是很棒的。但一旦你决定使用 war 文件部署web应用,那么 FileResourceLoader 可能成为你的敌人。所以,我们明确建议你不要使用 FileResourceLoader。
事实上,还有很多 ResourceLoader 实现,但这些 ResourceLoader 在和 Velocity引擎配合使用时将要求我们将模板存放在标准文件系统之外(如classpath、数据库、远程服务器等)。我们说,如果运行起来,那很好。但我们承认对大多数来说,这个部署方式很不方便。
最简单的替代方案实际已经存在于 VelocityTools 中,即 WebappResourceLoader,这个 ResourceLoader 是特别设计来像FileResourceLoader一样工作的,但 WebappResourceLoader 知道 servlet 上下文,允许我们配置servlet root 相关的资源路径,而不是本地文件系统。
如果你正使用 VelocityViewServlet,那么 VelocityViewServlet 会自动被配置去使用 WebappResourceLoader。所以,如果你想改变配置路径,你需要添加一行到 velocity.properties 中。
webapp.resource.loader.path=/WEB-INF/mytemplates/
如果你需要设置完全属于自己的 WebappResourceLoader,那么你需要做如下配置:
resource.loader=webapp
webapp.resource.loader.class=org.apache.velocity.tools.view.WebappResourceLoader
webapp.resource.loader.path=/WEB-INF/mytemplates/
下一步在初始化引擎时,你也需要把 ServletContext 放入 Velocity引擎的应用属性中,这使得 WebappResourceLoader 知道如何找到模板。
myVelocityEngine.setApplicationAttribute("javax.servlet.ServletContext", servletContext);
改变对象状态?--不要!
Velocity 提供了以引用方式调用对象方法的能力,这在页面上显示信息时很有用,但当对象或应用状态改变时却很危险。
例如,下面的代码安全地调用了 列表的 size() 方法,用以显示结果:
There are $users.size() currently logged in.
而不安全的例子如下面的,一个财务页面,存在一个对象,逐年计算数据。calculateNextYear()方法用于计算下一年数据,并提高内部计数器。
2005 data: $table.data
$table.calculateNextYear()
2006 data: $table.data
这一方法的问题在于 此段代码不能在当前页面中重复使用。你可能也不想这样做,但你很容易忘记,特别是当你需要剪切、复制控制语句时(如 #if 或者 #foreach),这在处理应用或会话层状态时所带来很多问题。
我们建议的实践方式是仅使用 Velocity 显示信息,方法的调用仅用于获取信息,而不要改变对象状态,因为这样改变对象或应用状态很危险。
如果你觉得你确实需要改变对象状态,尝试在控制器中计算所需要的值,然后将他们放进 List或Map中,记住使用控制器。
另外,补充一点,你应该习惯将 List 或 Set 放入页面上下文,而不要使用 Iterator 或 Enumeration,这很明显,List 或 Set可以被多次使用,而 另外两个却不行。
HTML/XML实体转义
用户输入的文本中可能包含 HTML或XML实体,如 < > &,这些需要提交时被转义。这是必须的,因为要保证文本可以被正确显示,同时为阻止跨站脚本攻击。哦。。。。不像 JSTL,Velocity默认不提供转义。。。。
然后,Velocity 提供了 ReferenceInsertionEventHandler 来处理这个问题。你可以配置 EscapeHtmlReference 处理器进到 velocity.properties 文件,以正则表达式方式指定匹配内容。下面的例子将转义 以 msg开头的HTML实体,如 $msgText。
eventhandler.referenceinsertion.class = org.apache.velocity.app.event.implement.EscapeHtmlReference eventhandler.escape.html.match = /msg.*/
注意:其他的转义有时也是必须的,比如在样式表中 @ 字符需要被转义,JS字符串中单引号也需要转义。
增强应用安全
因为 web应用运行在服务器上,拥有很多用户和需要保密的资源,因此必须加强应用安全。Velocity引入了安全机制。具体见《 Building Secure Applications with Velocity 》(涉及系统配置、跨站脚本、方法自省)。另外,你可以指定 SecureUberspector 来防止页面设计者犯错误。
runtime.introspector.uberspect = org.apache.velocity.util.introspection.SecureUberspector
日志文件
A minor point is that (in some circumstances) 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. This is due to the default use of the Avalon Log Kit when present in the classpath. Typically this occurs when Velocity is used within a web application outside of web page generation (e.g. for sending email). To solve this problem, remove any file labeled "avalon-logkit" from the classpath or properly configure the log file location.
最后一小点,Velocity 在没有任何日志配置时,会在当前文件夹创建日志文件。当前文件夹一般是应用服务器启动时的目录。
入门实例
下面是使用 VelocityViewServlet 创建 web应用的入门实例。注意:我们建议您从源代码编译 VelocityViewServlet。而实际上,这不是必须的,我们推荐这样只是为了让我们有机会查看源代码并随后编译例子文件。
前提包括安装 JDK 和 Apache Ant.
了解更多,请参考 Velocity Tools 文档。
- 下载 Velocity Tools 项目源代码(特别是他包含例子代码),地址:download page
- 编译 Velocity Tools jar,编译 simple例子:
ant example.simple
- 查看 examples 文件夹,你会找到 index.vm 文件,如下:
<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>
<tools> <data type="boolean" key="xhtml" value="true"/> <data type="boolean" key="isSimple" value="true"/> <data type="number" key="version" value="2.0"/> <data key="foo">this is foo</data> <data key="bar">this is bar.</data> <toolbox scope="request"> <tool key="toytool" class="ToyTool" restrictTo="index*"/> </toolbox> <toolbox scope="session"> <tool key="map" class="java.util.HashMap"/> </toolbox> </tools>
<web-app> <servlet> <servlet-name>velocity</servlet-name> <servlet-class>org.apache.velocity.tools.view.VelocityViewServlet</servlet-class> </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 文件。这样你就可以访问这个单页面应用了,如下:
http://localhost:8080/simple/index.vm
- 增加新的页面,进一步体验吧。注意:访问不同页面可以通过改变URL地址来实现。进一步查看 Velocity Tools 文档。
来源:oschina
链接:https://my.oschina.net/u/32037/blog/97938