velocity是一個基於Java的模板引擎,它能夠實現完全的先後端,前端不容許像jsp那樣出現Java代碼,而是利用context容器傳遞變量,在java代碼裏面咱們能夠往容器中存值,而後在vm文件中使用特定的語法獲取(不知道和ajax+restful實現的先後端分離有沒有差異,有時間看下底層代碼)。velocity除了做爲mvc的展示層之外,還能夠實現一些特殊的功能,好比源代碼生成,自動email和轉換xml等,詳情見使用 Velocity 模板引擎快速生成代碼,velocity最新版本是17年發佈的2.0版本html
在pom文件中引入依賴前端
<dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>x.x.x</version> </dependency>
若是想將velocity與Logging,SLF4J,log4j以及服務器logger日誌集成,能夠再pom文件中繼續加入下面這些依賴java
<dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-commons-logging</artifactId> <version>x.x.x</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-slf4j</artifactId> <version>x.x.x</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-log4j</artifactId> <version>x.x.x</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-servlet</artifactId> <version>x.x.x</version> </dependency>
非maven工程咱們須要把jar包直接放入到工程的classpath中(lib文件夾下)web
引入jar包後,咱們就可使用velocity實現咱們的先後端分離了。ajax
前面咱們說過,velocity容許咱們在後臺把數據放入到context容器裏面,從而實現從在前端直接取出。編寫VelocityTest.java以下spring
package pers.marscheng.spring.test; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.runtime.RuntimeConstants; import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; /** * velocity測試類 * * @author: marscheng * @date: 2018-04-02 下午3:47 */ public class VelocityTest { public static void main(String[] args){ // 初始化模板引擎 VelocityEngine ve = new VelocityEngine(); ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); ve.init(); // 獲取模板文件 Template t = ve.getTemplate("test.vm"); // 將變量放入context容器 VelocityContext ctx = new VelocityContext(); ctx.put("name", "MarsCheng"); List list = new ArrayList(); list.add("1"); list.add("2"); ctx.put("list", list); // 輸出 StringWriter sw = new StringWriter(); t.merge(ctx,sw); System.out.println(sw.toString()); } }
test.vm文件以下:apache
#set($greet = 'hello') $greet $name #foreach($i in $list) $i #end
注意要把文件放在classpath目錄下。如何肯定classpath路徑?能夠調用如下命令打印出來後端
System.out.println(ClassLoader.getSystemResource(""));

執行VelocityTest.main,控制檯會打印出:數組
velocity與spring集成時候還要加上velocity-tools的jar包,不然在加載bean的時候會報錯安全
<dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-tools</artifactId> <version>2.0</version> </dependency>
配置視圖解析器,這麼配置系統只能解析vm文件,能夠配置多視圖解析器(待研究,初步嘗試了用order,可是貌似沒有生效)
<!-- 視圖模式配置,velocity配置文件--> <bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"> <property name="resourceLoaderPath" value="/WEB-INF/views" /> <property name="configLocation" value="classpath:properties/velocity.properties" /> </bean> <!-- 配置後綴 --> <bean id="velocityViewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> <property name="suffix" value=".vm" /> </bean>
配置properties文件
#encoding input.encoding=UTF-8 output.encoding=UTF-8 #autoreload when vm changed file.resource.loader.cache=false file.resource.loader.modificationCheckInterval=2 velocimacro.library.autoreload=false
在/WEB-INF/views路勁下寫vm文件showUser.vm
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" pageEncoding="UTF-8"> <title>User Index</title> </head> <body> <h3>hello ${user.name}</h3> </body> </html>
其對應的controller層代碼以下UserControllerImpl.java,這裏的User是咱們定義的一個用戶javabean
package pers.marscheng.spring.controller.impl; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import pers.marscheng.spring.controller.UserController; import pers.marscheng.spring.dto.User; import javax.servlet.http.HttpServletRequest; /** * @author: marscheng * @date: 2018-04-03 下午3:05 */ @Controller @RequestMapping("/user") public class UserControllerImpl implements UserController { @Override @RequestMapping("/showUser") public String showUser(HttpServletRequest request, Model model) { User user = new User(); user.setName("Mars"); //存vm須要的參數 model.addAttribute("user",user); return "showUser"; } }
而後咱們訪問http://localhost:8080/user/showUser,就能夠看到對應的頁面了
Velocity使用模板語言——VTL,用於前端的開發,接下來就來總結下常見的一些VTL語法。具體能夠參考官方的翻譯文檔
velocity中的變量用$做爲前綴,它能夠獲取你在後臺用Java定義的變量值,也能夠在前端定義,而後使用。在vtl語法中用set表達式來定義(注意在表達式前面會有個#,這是velocity命令的寫法,後面你會看到更多的如#if等)
##velocity的變量是弱類型,能夠寫成$a或者${a},右邊能夠是(變量引用,字面字符串,屬性引用,方法引用,字面數字,數組列表) #set( $a = "Velocity" )
velocity的循環結構以下所示,$list是個集合,$item表示遍歷的每一項,$velocityCount是velocity的默認的變量,用來統計循環的次數
#foreach($item in $list) $item $velocityCount #end
條件控制的結構以下所示
#if(condition) ...dosonmething... #elseif(condition) ...dosomething... #else ...dosomething... #end
循環語句內能夠嵌套循環語句,也能夠嵌套條件語句#if
#foreach ($element in $list) #foreach ($element in $list) This is $element. $velocityCount <br>inner<br> #end ## inner foreach 內循環結束 ## outer foreach This is $element. $velocityCount <br>outer<br> #end
velocity的註釋用##表示
velocity 也有表示與或非的操做符,和Java同樣,都是&& || !,用法也同Java,以下面非的用法
##logical NOT #if( !$foo ) <strong>NOT that</strong> #end
velocity的宏至關於Java的函數
#macro(宏的名稱 $參數1 $參數2 …) 語句體(即函數體) #end
##參數用空格隔開 #宏的名稱($參數1 $參數2 …)
這個命令能夠中止執行模板引擎並返回,能夠用來debug
#include和#parse的做用都是引入本地文件, 爲了安全的緣由,被引入的本地文件只能在TEMPLATE_ROOT目錄下。
區別在於:
1.#include能夠引入多個文件,#parse只能引入一個,如
#include ("one.gif", "two.txt", "three.htm" ) ##也可使用變量名 #include ( 「greetings.txt」, $seasonalstock )
2.#include引入的內容不會被模板引擎解析,而#parse引入的內容會被解析
velocity和jsp同樣,內置了一些對象,能夠在vm模板中調用,如:$request、$response、$session等