Spring中使用Velocity模板


使用Velocity模板

Velocity是一種針對Java應用的易用的模板語言。Velocity模板中沒有任何 Java代碼,這使得它能夠同時被非開發人員和開發人員輕松地理解。Velocity的用戶手冊上是這么說的:“Velocity將Java代碼從Web 頁面中分離出來,使用Web站點從長遠看更容易維護,並且提供了一種可行的JavaServer Pages替代解決方案。”

除了JSP,Velocity可能是用於Web應用的最流行的模板語言。因此很可能你會想采用Velocity作為視圖層技術開發基於Spring的應用。幸運地是,Spring支持將Velocity作為Spring MVC的視圖層模板語言。

讓我們通過基於Velocity重新實現Spring培訓應用中的視圖層來看一下如何在Spring MVC中使用Velocity。

9.1.1 定義Velocity視圖

假設你已經選擇使用Velocity而不是JSP來創建Spring培訓應用的視圖。你需要 使用Velocity模板編寫的頁面之一是顯示可用課程列表的頁面。程序清單 9.1 顯示了courseList.vm,一個和courseList.jsp等價的用於顯示課程列表的Velocity模板。

 程序清單9.1 基於Velocity的課程列表

<html>

    <head>

      <title>Course List</title>

    </head>

    <body>

      <h2>COURSE LIST</h2>

      <table width="600" border="1" cellspacing="1" cellpadding="1">

        <tr bgcolor="#999999">

          <td>Course ID</td>

          <td>Name</td>

          <td>Instructor</td>

          <td>Start</td>

          <td>End</td>

        </tr>

#foreach($course in $courses)

        <tr>

          <td>

            <a href="displayCourse.htm?id=${course.id}">

              ${course.id}

            </a>

          </td>

          <td>${course.name}</td>

          <td>${course.instructor.lastName}</td>

          <td>${course.startDate}</td>

          <td>${course.endDate}</td>

        </tr>

#end // 在所有課程中循環

      </table>

    </body>

</html>

可能你首先注意到的是這個模板中沒有任何模板標簽。這是因為Velocity不是基於與 JSP類似的標簽的,而是采用了它自己的語言——稱為Velocity模板語言(VTL)——用於流程控制和其他指令。在courseList.vm 中,#foreach指令用於循環處理一個課程列表,顯示每個課程的明細。除了這個Velocity和JSP的基本區別之外,你會發現Velocity的 表達式語言和JSP很相似。事實上,當JSP使用${}作為它自己的表達式語言時,它不過是模仿Velocity的做法而已。這個模板僅僅演示了很少一部 分你可以使用Velocity所做的事情。

如果想知道更多,可以訪問Velocity位於http://jakarta.apache.org/velocity的主頁。注意當完成模板之后,你需要配置Spring使它可以在MVC應用中使用Velocity模板作為視圖。

9.1.2 配置Velocity引擎

首先需要配置的是Velocity引擎自己。要做到這點,可以通過以下方式在Spring配置文件中聲明一個VelocityConfigurer Bean:

<bean id="velocityConfigurer" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">

    <property name="resourceLoaderPath">

      <value>WEB-INF/velocity/</value>

    </property>

    </bean>

VelocityConfigurer負責在Spring中設置Velocity引擎。這 里,我們通過屬性resourceLoaderPath告訴Velocity到哪里尋找它的模板。我們建議將模板放到WEB-INF的某個子目錄下面,這 樣可以保證這些模板不能被直接訪問。也可以通過velocityProperties屬性來設置其他Velocity的配置細節。例如下面的 VelocityConfigurer配置:

<bean id="velocityConfigurer" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">

    <property name="resourceLoaderPath">

      <value>WEB-INF/velocity/</value>

    </property>

    <property name="velocityProperties">

      <props>

        <prop key="directive.foreach.counter.name">loopCounter</prop>

        <prop key="directive.foreach.counter.initial.value">0</prop>

      </props>

    </property>

</bean>

可以注意到velocityProperties屬性使用一個<props>元 素來設置多個屬性。在這里可以設置的屬性與一個典型的Velocity應用中通過“velocity.properties”文件設置的屬性是一樣的。缺 省地,Velocity的#foreach循環維護一個名為$velocityCount的循環計數器,該計數器在第一輪循環開始時從1開始計數。但這里 我們設置屬性directive.foreach.counter.name為loopCounter,因此將使用$loopCounter來引用循環計 數器。我們也通過設置屬性directive.foreach.counter.initial.value為0使循環計數器由零開始計數。(想知道關於 Velocity配置屬性的信息,請參考Velocity開發者指南http://jakarta.apache.org/velocity/developer-guide.html。)

9.1.3 解析Velocity視圖

要使用Velocity模板視圖,你必須做的最后一件事情是配置一個視圖解析器。具體地說,需要以如下方式在Spring上下文配置中聲明一個VelocityViewResolver Bean:

<bean id="viewResolver" class="org.springframework.

          web.servlet.view.velocity.VelocityViewResolver">

    <property name="suffix"><value>.vm</value></property>

</bean>

VelocityViewResolver和Velocity的關系與 InternalResourceViewResolver和JSP的關系相似。正如InternalResourceViewResolver,它使用 prefix屬性和suffix屬性由視圖的邏輯名構造出模板文件的路徑。這里我們僅僅設置suffix屬性為“.vm”擴展名。由於模板目錄的路徑已經 通過VelocityConfigurer的resourceLoaderPath屬性配置好了,因此這里不需要設置前綴。

注意:這里把Bean的ID設置為viewResolver。這一點很重要,因為我們並沒有 配置DispatcherServlet檢測所有的視圖解析器。如果要同時使用多個視圖解析器,則你很可能需要將這個ID改成某個更合適的名字(並且是惟 一的),比如velocityViewResolver。

現在,你的應用系統已經可以渲染基於Velocity模板的視圖了。你只需要在返回的ModelAndView對象中通過邏輯名引用所需的視圖。以ListCourseController為例,不需要做其他事情,因為它已經返回如下的ModelAndView對象:

return new ModelAndView("courseList", "courses", allCourses);

視圖的邏輯名為“courseList”。當解析這個視圖時,“courseList”加上后綴“.vm”構成了一個模板名“courseList.vm”。VelocityViewResolver會在WEB-INF/velocity路徑下尋找這個模板。

至於“courses”模型對象,它會作為一個Velocity屬性暴露給Velocity模板使用。在程序清單9.1中,它就是在#foreach指令中使用的集合對象。

9.1.4 格式化日期和數字

盡管應用已經配置成可以渲染Velocity視圖了,但我們還有一些雜七雜八的問題需要解 決。當你比較程序清單9.1中的couseList.vm和courseList.jsp時,會注意到courseList.vm沒有像 courseList.jsp一樣對課程的ID、開始日期和結束日期進行格式化。在courseList.jsp中,課程ID顯示為一個6位定長的前面以 零補齊的數字,而所有的日期以完整格式顯示。為了完成courseList.vm,你需要對它作進一步的調整,對ID和日期屬性進行格式化。

VTL並不直接支持日期和數字的格式化,而是通過提供日期和時間的工具類來支持格式化。為了 允許使用這些工具,你需要告訴VelocityViewResolver在模板中暴露它們時使用的屬性名。這些屬性名是通過 VelocityViewResolver的dateToolAttribute和numberToolAttribute屬性來規定的:

<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">

    <property name="dateToolAttribute">

      <value>dateTool</value>

    </property>

    <property name="numberToolAttribute">

      <value>numberTool</value>

    </property>

</bean>

在這里,我們規定數字工具通過numberTool屬性暴露給Velocity使用。因此,要格式化課程ID,你只需要通過數字工具的format()方法來處理課程ID即可,如下:

$numberTool.format("000000", course.id)

方法format()的第一個參數是模式字符串,在這里我們規定課程ID顯示為6個數字的 域,必要時在前面補零。模式字符串的語法和java.text.DecimalFormat一致。請參考Velocity關於NumberTool的文檔 來獲取更多關於該工具功能的信息。

類似地,我們分配日期工具使用dateTool屬性。為了格式化課程的開始和結束日期,只需使用日期工具的format()方法:

$dateTool.format("FULL", course.startDate)

$dateTool.format("FULL", course.endDate)

與數字工具的format()方法一樣,第一個參數也是模式字符串。模式字符串的語法與 java.text.SimpleDateFormat一致。另外,也可以設置模式字符串為FULL、LONG、MEDIUM、SHORT或 DEFAULT中的一個,以使用標准的java.text.DateFormat模式。這里我們設置模式字符串為FULL來表示完整的日期格式。請參考 Velocity關於DateTool的文檔來獲得更多關於該工具功能的信息。

9.1.5 暴露請求和會話屬性

盡管需要在Velocity模板中顯示的大多數數據都可以通過ModelAndView對象的模型Map傳遞給視圖,有時候也會需要顯示servlet請求或會話中的屬性。比如,當用戶登錄到應用系統時,用戶的信息可能存放在servlet會話中。

如果在每一個控制器中都將請求或會話的屬性復制到模型Map中,這會是非常笨拙的。幸運的 是,VelocityViewResolver會幫你將這些屬性復制到模型中。屬性exposeRequestAttributes和 exposeSessionAttributes告訴VelocityViewResolver是否需要將servlet請求和會話中的屬性復制到模型 中。比如:

<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">

    <property name="exposeRequestAttributes">

      <value>true</value>

    </property>

    <property name="exposeSessionAttributes">

      <value>true</value>

    </property>

</bean>

這兩個屬性的默認值都為false。但在這里我們把這兩個屬性都設置為true,從而請求和會話的屬性都會被復制到模型中,並且在Velocity模板中可見。

9.1.6 在Velocity中綁定表單域

在第8章中,我們看到如何使用Spring的<spring:bind>JSP標簽將表單域綁定到一個命令對象中。這個標簽在向用戶顯示表單域相關的錯誤時也是非常有用的。

幸運的是,當你使用Velocity而不是JSP時,不必放棄<spring:bind>提供的功能。Spring提供了若干個Velocity宏來模仿<spring:bind>標簽的功能。

例如,假設Spring培訓應用的學生注冊表單是用Velocity模板編寫的。程序清單9.2顯示了registerStudent.vm中的一段,演示如何使用#springBind宏:

 程序清單9.2 在Velocity模板中使用#springBind

#springBind("command.phone")

phone: <input type="text"

      name="${status.expression}"

      value="http://www.blog.edu.cn/$!status.value">

<font color="#FF0000">${status.errorMessage}</font><br>

#springBind("command.email")

email: <input type="text"

      name="${status.expression}"

      value="http://www.blog.edu.cn/$!status.value">

<font color="#FF0000">${status.errorMessage}</font><br>

#springBind宏的參數是被綁定表單域的引用路徑。它在模板中設置了一個名為status的變量用於保存表單域的名稱、值以及可能出現的任何錯誤信息(可能來自一個驗證器)。

如果錯誤信息中包含在HTML中有特殊意義的字符(比如:<,>,&),你可能需要對錯誤信息進行轉義以正確顯示在Web瀏覽器中。在這種情況下,你需要使用宏#springBindEscaped而不是#springBind:

#springBindEscaped("command.email", true)

除了域的引用路徑之外,#springBindEscaped宏接受一個boolean參 數,表明是否需要對錯誤信息中的HTML特殊字符進行轉義。如果該參數為false,則宏#springBindEscaped和#springBind 的行為完全一樣,HTML特殊字符不會被轉義。

為了在模板中使用Spring的宏,你需要通過VelocityViewResolver的exposeSpringMacroHelpers來使用這些宏:

<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">

    <property name="exposeSpringMacroHelpers">

      <value>true</value>

    </property>

</bean>

通過把exposeSpringMacroHelpers屬性設為true,你就能在Velocity模板中使用#springBind和#springBindEscaped宏。

盡管Velocity是一種廣泛使用的JSP的替代技術,它不是惟一可以使用的替代模板技術。FreeMarker是另一種廣為人知的用於在MVC應用的視圖層中替代JSP的模板語


免責聲明!

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



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