背景:在velocity模版文件中为一个java类生成toString()方法。

原来的做法:

@Override    
public String toString(){
    StringBuilder sb = new StringBuilder();       
    #foreach( $field in ${response.fields} )
    sb.append("${field.name}=").append(this.$field.name).append(",");
    #end       
    String s = sb.toString();
    if (s.endsWith(",")) {
        s = s.substring(0, s.length() - 1);
    }       
    return s;
}

liuhe看了之后,说不好,不要用subString,性能不好。直接判断是否是最后一个特殊处理一下就可以了。于是Google了一下,发现Velocity的foreach其实已经很强大了,支持很多判断:

#foreach ($foo in $bar)    
    hasNext: $foreach.hasNext
    count: $foreach.count
    index: $foreach.index
    first: $foreach.first 
    last:  $foreach.last
#end

使用$foreach.hasNext$foreach.last可以做到对for循环的最后一个元素特殊处理的效果。

在StackOverFlow上也有人提出这个问题了:velocity: do something except in last loop iteration。而且还指出了需要注意的版本问题:

$foreach variable is only available in velocity 1.7, if you’re using an earlier version you can use the $velocityHasNext.

看了一下pom文件,我们使用的是:

<dependency>
     <groupId>velocity</groupId>
     <artifactId>velocity</artifactId>
     <version>1.4</version>
</dependency>

于是使用$velocityHasNext。但是一直不生效,直接打印$velocityHasNext,显示的是空值。

很奇怪,将pom中的版本改成1.7发现下载失败,说找不到。最后发现原来velocity在mvnrepository中有两个位置。就是groupId不一样,应该使用后者。

<dependency>
     <groupId>velocity</groupId>
     <artifactId>velocity</artifactId>
     <version>1.5</version>
</dependency>

<dependency>
     <groupId>org.apache.velocity</groupId>
     <artifactId>velocity</artifactId>
     <version>1.7</version>
</dependency>       

改成后者就可以直接使用$foreach.hasNext了:

@Override   
public String toString(){
    StringBuilder sb = new StringBuilder();

    sb.append("${response.className}[");       
    #foreach( $field in ${response.fields} )
    sb.append("${field.name}=").append(this.$field.name)#if( $foreach.hasNext ).append(", ")#end;
    #end

    sb.append(']');       
    return sb.toString();
}