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等