langqiao 2011-07-05
Apache官方网站Velocity Tools自带的例子(位置:\velocity-tools-1.4-src\examples\simple)。
新建一个Web Project,名称为Velocity。
在src下面实现一个ToyTool类,如下所示:
public class ToyTool
{
private String message = "Hello from ToyTool!";public String getMessage()
{
returnmessage;
}public void setMessage(String m)
{
message=m;
}/** To test exception handling in templates. */
publicbooleanwhine(){
thrownewIllegalArgumentException();
}}
这个类实现了一个简单的JavaBean,带setter和getter,操作的属性是message。
模板文件为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>在这个自带的例子中,并没有实际实现一个自己的Servlet,而是直接使用了org.apache.velocity.tools.view.servlet.VelocityViewServlet,该类位于\velocity-tools-1.4-src\src\java\org\apache\velocity\tools\view\servlet下面。
用到org.apache.velocity.tools.view.servlet.VelocityViewServlet,在该类中实现了对toolbox.xml的解析。可以在web.xml中对应的配置来了解到都配置了哪些项。
web.xml中配置如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<web-appversion="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<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>
其中,toolbox.xml的内容如下所示:
<toolbox>
<xhtml>true</xhtml>
<tool>
<key>toytool</key>
<class>ToyTool</class>
</tool>
<datatype="number">
<key>version</key>
<value>1.1</value>
</data>
<datatype="boolean">
<key>isSimple</key>
<value>true</value>
</data>
<datatype="string">
<key>foo</key>
<value>thisisfoo.</value>
</data>
<datatype="string">
<key>bar</key>
<value>thisisbar.</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>将对应的jar包文件加入到CLASSPATH中,启动Tomcat Web Server ,在浏览器地址栏中键入http://localhost:8080/Velocity/index.vm就可以看到这个简单的例子运行的效果了:
I'm a velocity template.
Hereweuseacustomtool:HellofromToyTool!
Here we get the date from the DateTool: 2008-4-19 21:23:50既然,web.xml中指定了初始化参数:key为org.apache.velocity.toolbox,value为/WEB-INF/toolbox.xml文件,那么,在Web Server(这里使用Tomcat)启动的时候,就要解析/WEB-INF/toolbox.xml。
其实,这里隐藏了很多细节,需要解析的不仅仅是/WEB-INF/toolbox.xml,在解析它之前还有很多工作要做。
可以在VelocityViewServlet的源代码中看到实际的过程。VelocityViewServlet继承了HttpServlet,表现出了它是有生命周期的。其中在init方法中可以看到初始化过程:
public void init(ServletConfig config) throws ServletException
{
super.init(config);// 根据config信息初始化Velocity,这时Web Server启动的时候要做的第一件事 initVelocity(config);
// 初始化toolbox initToolbox(config);
// 当Velocity已经初始化完成之后,下面要做的一些事情:设置ContentType和编码等等等
defaultContentType=
(String)getVelocityProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE);String encoding =
(String)getVelocityProperty(RuntimeConstants.OUTPUT_ENCODING,
DEFAULT_OUTPUT_ENCODING);// For non Latin-1 encodings, ensure that the charset is
//includedintheContent-Typeheader.
if(!DEFAULT_OUTPUT_ENCODING.equalsIgnoreCase(encoding))
{
intindex=defaultContentType.lastIndexOf("charset");
if(index<0)
{
//thecharsetspecifierisnotyetpresentinheader.
//appendcharacterencodingtodefaultcontent-type
defaultContentType+=";charset="+encoding;
}
else
{
//Theusermayhaveconfigurationissues.
velocity.warn("VelocityViewServlet:Charsetwasalready"+
"specifiedintheContent-Typeproperty."+
"Outputencodingpropertywillbeignored.");
}
}velocity.info("VelocityViewServlet: Default content-type is: " +
defaultContentType);
}上面代码中,第一件事是initVelocity,即窄initVelocity方法中注册Velocity引擎
protected void initVelocity(ServletConfig config) throws ServletException
{
velocity=newVelocityEngine();//实例化一个VelocityEngine
setVelocityEngine(velocity); // 将已经创建的VelocityEngine设置到当前Velocity上下文中// 注册 LogSystemCommonsLog.setVelocityEngine(velocity);
velocity.setApplicationAttribute(SERVLET_CONTEXT_KEY, getServletContext());
// 尝试读取VelocityTools 默认配置信息
try
{/** 这里要读取Velocity的默认配置文件了,即org/apache/velocity/tools/view/servlet/velocity.properties文件,该文件默认设置如下所示:
# default to servletlogger, which logs to the servlet engines logruntime.log.logsystem.class = org.apache.velocity.tools.view.servlet.ServletLogger
# by default, load resources with webapp resource loader
resource.loader=webapp
webapp.resource.loader.class = org.apache.velocity.tools.view.servlet.WebappLoader*/
ExtendedPropertiesdefaultProperties=loadDefaultProperties();
velocity.setExtendedProperties(defaultProperties);
}
catch(Exceptione)
{
log("VelocityViewServlet:UnabletoreadVelocityServletconfigurationfile:",e);
thrownewServletException(e);
}// velocity.properties文件是可以由用户自己根据需要配置的,如果用户自己重新设置了该文件,在这里解析
try
{
ExtendedPropertiesp=loadConfiguration(config);
velocity.setExtendedProperties(p);
}
catch(Exceptione)
{
log("VelocityViewServlet:UnabletoreadVelocityconfigurationfile:",e);
log("VelocityViewServlet:UsingdefaultVelocityconfiguration.");
}// 当velocity.properties文件加载完成,初始化VeloccityEngine
try
{
velocity.init();
}
catch(Exceptione)
{
log("VelocityViewServlet:PANIC!unabletoinit()",e);
thrownewServletException(e);
}
}接着就是initToolbox,开始解析/WEB-INF/toolbox.xml文件,initToolbox方法实现如下:
protected void initToolbox(ServletConfig config) throws ServletException
{
//获取在web.xml中设置的toolbox.xml
Stringfile=findInitParameter(config,TOOLBOX_KEY);
if(file==null)
{
//ok,lookinthedefaultlocation
file=DEFAULT_TOOLBOX_PATH;
velocity.debug("VelocityViewServlet:Notoolboxentryinconfiguration."
+"Lookingfor'"+DEFAULT_TOOLBOX_PATH+"'");
}// 获取一个管理toolbox.xml的管理toolboxManager
toolboxManager=
ServletToolboxManager.getInstance(getServletContext(),file);
}ToolboxManager是一个接口:
package org.apache.velocity.tools.view;
import java.util.Map;
publicinterfaceToolboxManager
{
voidaddTool(ToolInfoinfo);
voidaddData(ToolInfoinfo);
Map getToolbox(Object initData);}
它有一个实现子类XMLToolboxManager,可以完成对XML配置文件(比如toolbox.xml文件)的一些操作,其中,XMLToolboxManager类方法load实现了对XML文件的加载和解析:
public void load(InputStream input) throws Exception
{
LOG.trace("Loading toolbox...");Digester digester = new Digester();
digester.setValidating(false);
digester.setUseContextClassLoader(true);
digester.push(this);
digester.addRuleSet(getRuleSet());
digester.parse(input);LOG.trace("Toolbox loaded.");
}