Velocity Tools及VelocityViewServlet源代碼解析


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()
{
        return message;
}

    public void setMessage(String m)
    {
        message = m;
    }

    /** To test exception handling in templates. */
    public boolean whine() {
        throw new IllegalArgumentException();
    }

}

這個類實現了一個簡單的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-app version="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>
<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>

將對應的jar包文件加入到CLASSPATH中,啟動Tomcat Web Server ,在瀏覽器地址欄中鍵入http://localhost:8080/Velocity/index.vm就可以看到這個簡單的例子運行的效果了:

I'm a velocity template.

Here we use a custom tool: Hello from ToyTool!

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
        // included in the Content-Type header.
        if (!DEFAULT_OUTPUT_ENCODING.equalsIgnoreCase(encoding))
        {
            int index = defaultContentType.lastIndexOf("charset");
            if (index < 0)
            {
                // the charset specifier is not yet present in header.
                // append character encoding to default content-type
                defaultContentType += "; charset=" + encoding;
            }
            else
            {
                // The user may have configuration issues.
                velocity.warn("VelocityViewServlet: Charset was already " +
                              "specified in the Content-Type property. " +
                              "Output encoding property will be ignored.");
            }
        }

        velocity.info("VelocityViewServlet: Default content-type is: " +
                      defaultContentType);
    }

上面代碼中,第一件事是initVelocity,即窄initVelocity方法中注冊Velocity引擎

   protected void initVelocity(ServletConfig config) throws ServletException
    {
        velocity = new VelocityEngine();    // 實例化一個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 log
runtime.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

*/
            ExtendedProperties defaultProperties = loadDefaultProperties();
            velocity.setExtendedProperties(defaultProperties);
        }
        catch(Exception e)
        {
            log("VelocityViewServlet: Unable to read Velocity Servlet configuration file: ", e);
            throw new ServletException(e);
        }

        // velocity.properties文件是可以由用戶自己根據需要配置的,如果用戶自己重新設置了該文件,在這里解析
        try
        {
            ExtendedProperties p = loadConfiguration(config);
            velocity.setExtendedProperties(p);
        }
        catch(Exception e)
        {
            log("VelocityViewServlet: Unable to read Velocity configuration file: ", e);
            log("VelocityViewServlet: Using default Velocity configuration.");
        }

       // 當velocity.properties文件加載完成,初始化VeloccityEngine
        try
        {
            velocity.init();
        }
        catch(Exception e)
        {
            log("VelocityViewServlet: PANIC! unable to init()", e);
            throw new ServletException(e);
        }
    }

接着就是initToolbox,開始解析/WEB-INF/toolbox.xml文件,initToolbox方法實現如下:

    protected void initToolbox(ServletConfig config) throws ServletException
    {
        // 獲取在web.xml中設置的toolbox.xml
        String file = findInitParameter(config, TOOLBOX_KEY);
        if (file == null)
        {
            // ok, look in the default location
            file = DEFAULT_TOOLBOX_PATH;
            velocity.debug("VelocityViewServlet: No toolbox entry in configuration."
                           + " Looking for '" + DEFAULT_TOOLBOX_PATH + "'");
        }

        // 獲取一個管理toolbox.xml的管理toolboxManager
        toolboxManager =
            ServletToolboxManager.getInstance(getServletContext(), file);
    }

ToolboxManager是一個接口:

package org.apache.velocity.tools.view;

import java.util.Map;
public interface ToolboxManager
{
    void addTool(ToolInfo info);
    void addData(ToolInfo info);
    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.");
    }

原文轉自:http://chenpingtai2008.iteye.com/blog/752187


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM