在Struts2的select或radio标签中使用FreeMarker的Hash的方法
在Struts2的radio或select标签中无法使用FreeMarker定义的Hash(散列)变量,这个问题让初学Struts2的我头痛了好长时间,遍查资料,也得不到解决之法。
昨晚下载了Struts2的源码,调试了一下,找到原因所在,应该是Struts2的一个Bug,修改了Struts2的一个类,问题解决。
因为解决了这个问题,对我来说,意义非常大,所以,我认为对其他朋友肯定也有意义,下文公开这个方法,希望能对大家起到帮助。
1、背景
做一个util.ftl文件,在里面定义一些常用Hash变量,如性别、分类、职业等,
然后在实际业务的ftl文件中,import这个util.ftl文件,将Hash变量赋值给Struts2的标签。
类似下面的代码:util.ftl文件
代码区加不了颜色,请大家直接注意homepageMap这个变量吧。
2、问题
如果象以上那样来使用FreeMarker的Hash(散列),在目前的情况下,势必出现下面样的问题:
也就是大家会看到FreeMarker的Hash变成了一串如freemarker.ext.beans.HashAdapter$1$1$1@6e90fb8e样的东东。
3、问题分析及解决之法
通过对Struts2源码的Debug,发现了问题所在,大家可以找到Struts2的如下类:
org.apache.struts2.components.ListUIBean 。
当FreeMarker的Hash被传入后,类型是FreeMarker的HashAdapter类,当执行到ListUIBean类的第74行时,MakeIterator.isIterable(list)是true,这样传入的HashAdapter类型的list被MakeIterator类转换为Iterator类对象了,但是不幸的是第75行直接把转换后的Iterator对象赋给了value,这样的结果是导致后面一系统对Map类型变量进行的处理均无法对value对象进行处理了,因为此时的value已经不是Map,而是Iterator了。
虽然第94行,通过MakeIterator.convert处理时,不会对Iterator类型的value再次进行转换,但,接下来针对value的任何应该的处理都没了。这个错恰恰因为第75行的严重败笔!
正是因为这一行的失败处理,作为FreeMarker传入的Hash被搞成了个Iterator型的变量,在接下来的向值栈存储内容时,也会存放错误的内容(向值栈存放信息部分我没看,但是根据推测,肯定由于listKey和listValue没有正确设定,所以值栈中存放的格式肯定有问题),输出的时候也显示的是错误的内容。
经过上面的分析,相信大家已经明白如何改了,对,就是直接将75行这句改一下就可以了。
原来:value = MakeIterator.convert(list);
改为:value = list;
可以在工程的src目录下建立该类的包:org.apache.struts2.components,
将改后的ListUIBean类改后,拷贝进去,编译后,运行系统,大家会发现FreeMarker的Hash终于正常工作了。
至于为什么定义为OGNL格式的Hash可以正常工作,大家可以Debug下源代码,其实对于OGNL的Hash到ListUIBean类时,还只是一个字符串,只是经过findValue后,OGNL会自动转为Hash,所以可以正常工作,这样,实际上走的是ListUIBean类的第70和71行,而不会执行第75行,所以不会有问题。
正常工作后的载图:
希望以上的分析和解决之法对大家能有所帮助,写的不对之处,还请批评。
jar包的版本:Struts 2.12
FreeMarker 2.3.14
我是在以述版本上分析的,但实际上struts-2.0.14上也不行。
下附org.apache.struts2.components.ListUIBean类的上半部分源代码(没有变更过的)。
1 楼 helloworld365 2008-11-28 好贴,顶起来! 2 楼 dodomail 2008-11-29 好贴啊!!!!!!