VTL语法

Velocity模板使用的语法被称为VTL(Velocity Template Language),这里我们介绍这种语法。

注释

VTL中单行注释为 ##,多行注释为#* *#,被注释的内容不会被模板引擎解析,这和JSP注释效果相同,注意应和HTML注释加以区分,除此之外VTL还有文档注释。

#**
*@author xxx
*@version 5
*#

VTL的文档注释和Java的标准JavaDoc注释比较类似。

变量、属性、方法的引用

VTL可以对变量、属性、方法进行引用。输出一个变量时,实际上会调用它的toString()方法,这和System.out.println()类似。输出一个属性时,该属性必须是可访问的或其Get方法是可访问的,引用一个方法则会显示该方法的输出结果。

这里我们定义一个叫做User的JavaBean,输出的例子如下。

package com.gacfox.domain;

public class User {
    private String username;
    private String password;

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String sayHello() {
        return "Hello, I am " + this.username + ".";
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

下面我们分别输出该对象的实例、属性和sayHello()方法。

<!DOCTYPE html>
<html lang="zh">
<head>
   <meta charset="UTF-8">
   <title>Test Velocity</title>
</head>

<body>
   <p>$user</p>
   <p>$user.password</p>
   <p>$user.sayHello()</p>
</body>
</html>

浏览器内分别输出了user.toString()user.passworduser.sayHello()

#set()的用法

除了可以像$user这样引用一个对象实例,还可以用#set()在模板上下文中设置一个对象。

#set($person = "Tom")
$person

此外还可以设置一个List或Map对象,我们还可以调用其get()isEmpty()等方法。

#set($l=["a", "b", "c"])
#set($s={"a":"aaa", "b":"bbb", "c":"ccc"})
<p>$l.get(1)</p>
<p>$l.isEmpty()</p>
<p>$s.get("a")</p>

输出结果如下图所示。

此外也可以通过以下方式对List和Map进行访问。

#set($l=["a", "b", "c"])
#set($s={"a":"aaa", "b":"bbb", "c":"ccc"})
<p>$l[1]</p>
<p>#set($l[1]="d")</p>
<p>$l[1]</p>
<p>$s["a"]</p>

对于$user.password这种形式的写法,也可能是从一个叫做user的Map中取出一个键为password的对象,Velocity引擎会自动进行判断,例子如下。

Map<String, User> userMap = new HashMap<>();
userMap.put("tom", new User("Tom", "456"));
request.setAttribute("userMap", userMap);
<p>$userMap.tom</p>

输出结果如下图所示。

引用方法时也可以传入参数,参数可以是另一个对象。这里我们从Servlet传入一个叫BobUser对象,然后把名字改为Hello,例子代码如下。

<p>$user</p>
<p>#set($name = "Hello")</p>
<p>$user.setUsername($name)</p>
<p>$user.sayHello()</p>

输出结果如下图所示。

对于传入的基本类型如int等Velocity会自动进行隐式类型转换。

有时候$xxx需要和其他的字符连在一起,比如$xxxyyy,我们要输出的变量是xxx,但此时和后面的内容连在了一起,此时在待输出的变量套上一个大括号即可,例子代码如下。

#set($x="xxx")
<p>${x}yyy</p>

对于方法调用或属性引用也是一样。

#set($x=["xxx"])
<p>${x.get(0)}yyy</p>

Velocity中如果输出一个上下文中不存在的变量如$name,模板引擎会直接原样输出$name,这通常不是我们想要的,$!name则表示如果name不存在就什么都不显示,下面是一个例子。

#set($name1="Tom")
<p>$name1</p>
<p>$!name1</p>
<p>$name2</p>
<p>$!name2</p>

如果模板原文需要输出可能因其歧义的关键字符如$,我们加上转义字符即可,例子如下。

#set($a="aaa")
<p>$a</p>
<p>\$a</p>
<p>\\$a</p>
<p>\\\$a</p>
<p>\\\\$a</p>

最后还有一点要尤其注意,Velocity中如果一个变量被设置为null,原来的值并没有被null覆盖。例子如下,其中setNull()返回null

#set($a="aaa")
#set($a=$nullMethod.setNull())
<p>$a</p>

这在执行判断逻辑时尤其容易犯错,应注意避免。

判断逻辑#if()...elseif()...else...#end的用法

判断逻辑比较简单,它和Java的判断比较类似,判断成功则输出相应内容,我们直接看一个例子。

#set($a = 10)

#if($a > 0)
   <p>bigger than 0</p>
#elseif($a > 5)
   <p>bigger than 5</p>
#elseif($a == 10)
   <p>equals to 10</p>
#elseif($a > 100)
   <p>bigger than 100</p>
#else
   <p>others</p>
#end

输出结果如下图所示。

判断只能比较相同类型的变量,如果==两端变量类型不同,则直接返回false。对于字符串类型,字符串内容相同则返回true。对于由自定义的复合类型比如一个叫做User的JavaBean,Velocity比较实际上是调用其equals()方法,所以可以通过重写Userequals()hashCode()方法改变该判断的行为。

#set($a="aaa")
#set($b="aaa")
#if($a==$b)
   <p>true</p>
#end

判断逻辑同样可以使用Java中的&& || !进行逻辑的组合。

循环逻辑#foreach($xxx in $xxxList)...#end的用法

和Java相同,Velocity中循环可以使用foreach迭代输出List和Map。

#set($list = ["a", "b", "c"])
#set($map = {"a":"aaa", "b":"bbb", "c":"ccc"})

<ul>
   #foreach($l in $list)
      <li>$l</li>
   #end
</ul>

<ul>
   #foreach($m in $map)
      <li>$m</li>
   #end
</ul>

<ul>
   #foreach($m in $map.keySet())
      <li>$m : $map.get($m)</li>
   #end
</ul>

结果如下图所示。

迭代的过程中,Velocity给定了一个变量velocityCount来记录迭代次数,当然你也可以自己定义一个变量进行记录。同时还有一个velocityHasNext可以用来判定迭代是否完成,例子代码如下。

#set($list = ["a", "b", "c"])

<ul>
   #foreach($l in $list)
      <li>$velocityCount</li>
      <li>$l</li>
      <li>$velocityHasNext</li>
   #end
</ul>

我们可以利用velocityCount产生格行变色的效果。

<table border="1">
   #foreach($user in $userList)
      <tr style="background-color:

      #if($velocityCount%2==0)
         #c3f3c3
      #else
         #f3c3f3
      #end

      ;">
         <td>$user.username</td>
         <td>$user.password</td>
      </tr>
   #end
</table>

效果如下图所示。

注意:以上代码仅作演示,通常建议由CSS和JS进行布局外观的控制。

#include()#parse()

#include()#parse()都是用于引入一段文本文件,但#include()引入的文本不会被模板引擎渲染,#parse()则引入一段可以被渲染的文本。

WEB-INF/views/module.vm

#set($list=["aaa", "bbb", "ccc"])
<ul>
   #foreach($l in $list)
      <li>$l</li>
   #end
</ul>

/WEB-INF/views/test.vm

#include("/WEB-INF/views/module.vm")
#parse("/WEB-INF/views/module.vm")

结果如下图所示。

#include()#parse()的参数是包含资源文件路径的字符串,它可以有不止一个参数,例如#include(“module1.vm”, “module2.vm”)

#stop停止解析

该指令可以停止模板引擎,主要用于调试。模板引擎停止后,不会输出任何后面的内容,下面是一个例子。

#set($list=["aaa", "bbb", "ccc"])
<ul>
   #foreach($l in $list)
      <li>$l</li>
      #stop
      <li>$l</li>
   #end
</ul>
<p>test</p>

宏定义

熟悉C语言就应该知道宏定义的用途,C语言中宏定义就是文本的替换,它可以用来设定常量甚至将一些函数封装到宏定义。Velocity的宏定义也是文本替换,但写法则更类似于直接定义函数,下面是一个例子。

#macro(show_table $list)
   <table border="1">
      #foreach($l in $list)
         <tr>
            <td>$l</td>
         </tr>
      #end
   </table>
#end

#set($list = ["aaa", "bbb", "ccc", "ddd"])
#show_table($list)

结果如下图所示。

通过宏定义,我们可以把一些公用的部分抽取出来进行封装和重复利用。宏定义声明的参数可以是变量、List、Map,基本Java类型和字符串。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap