1、循环中
#foreach($item in $detail.items) #set($name=$item.name) $!name #end
#foreach($item in $detail.items) #set($name=$item.name) $!name #end
假设$detail.items 有三个元素,第一个元素$item.name="餐巾", 第二个元素$item.name=null ,第三个元素$item.name="手帕"。那么这里会出现什么情况呢?
你可能希望打印的结果是 餐巾 手帕 ,不过,事实不是你想的那样,最终结果会是 餐巾 餐巾 手帕。因为velocity的一个特性就是如果后面的赋值表达式右边为空,那么左边的变量仍然是原来的值,不会被改变。
解决办法:
1. 使用之前将其给一个初始值
#foreach($item in $detail.items) #set($name="") #set($name=$item.name) $!name #end
#foreach($item in $detail.items) #set($name="") #set($name=$item.name) $!name #end
这种问题也经常发生在一些不正确使用#set的场合,例如
#if(......) #set($test=$xxx.xx) #end
#if(......) #set($test=$xxx.xx) #end
万一这个$test在前面本身就有某个值,那么这里的判断即使是true,如果$xxx.xx为空也会导致出现结果不正确,因此,在赋值之前给其一 个初始值就显得很有必要
#set($test=false) ## 首先初始化一下,防止出现其他不必要的值 #if(......) #set($test=$xxx.xx) #end
#set($test=false) ##首先初始化一下,防止出现其他不必要的值 #if(......) #set($test=$xxx.xx) #end
解决办法2: directive.set.null.allowed=true //这个设置允许#set的表达式右边不存在时将左边变量赋值为null.
2. 模板中使用了#parse,或者调用了#macro定义的宏
例如:testA.vm中有如下代码:
#macro (method1 $t)
#set($t=7)
#set($test2=8)
#end
#set($test=5)
#parse('testB.vm')
$test ##A
#set($test2=5)
#method1($test)
$test ##B
$test2 ##C
#macro (method1 $t) #set($t=7) #set($test2=8) #end #set($test=5) #parse('testB.vm') $test ##A #set($test2=5) #method1($test) $test ##B $test2 ##C
testB.vm中有如下代码
#set($test=6)
这里的输出结果多半会令你吃惊,##A处的应该打印出6 ,##B处应该打印出7,##C处应该打印出8.
why? 记住一点即可,在模板中或者宏中调用 #parse以及另外的宏时,他们都公用一套context上下文,无论你什么地方#set()其实都是改变了这个context中的变量值,因此,这就 要求在#parse或者调用别人的宏时要注意模板中本身的变量被别人给修改掉了,一但发生这个情况,那么杯具,问题很难找,只有一段一段debug.
另外提到一点,关于宏中为什么对$t进行修改,也会影响到外部的$test,这一点一定要和我们的函数调用区分开,宏并不是函数,这里$t只 是$test的一个别名而已,因此即使你对$t进行修改也会直接影响到$test。
解决办法:
1.对于#marco目前可以通过设置velocimacro.context.localscope=true,此时,#marco宏内部还是可以直接 无需参数直接使用全局变量,但是如果对全局变量直接进行#set, 即直接替换引用,此时相当于在内部申明了局部变量,#set不会影响到外部的变量。==注:即使设置了这个配置,也不能直接对宏的参数进行#set,否则 会一样会影响到外部,这个bug会在1.7beta1版本中得到解决。
2. 对#parse据了解没有,但可以通过修改#parse解析类的目的来达到同样的效果。
笔者注:
到了1.7beta1版本时,之前的有一些已经不推荐使用。
1. $velocityCount 推荐使用 $foreach.count or $foreach.index
2. $velocityHasNext 推荐使用 $foreach.hasNext, $foreach.first or $foreach.last
配置中velocimacro.context.localscope 叶不再推荐使用,因为1.7开始velocity提供了一系列的provide.scope.control,例如
template.provide.scope.control = true
evaluate.provide.scope.control = true
foreach.provide.scope.control = true
macro.provide.scope.control = true
define.provide.scope.control = false
<bodymacroname>.provide.scope.control = false
如果开启这些功能,那么在相应的指令中可以通过使 用$template,$macro等定义局部变量,如 #set($macro.test=true), 如果没有这些前缀,velcoity会当场全局变量来使用。
重要的2.0以后这些不推荐使用的配置将会被清除,不再支持。