`
netfork
  • 浏览: 488085 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

在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文件
<#assign yearlist=[]>
<#assign monthlist=1..12>
<#assign daylist=1..31>

<#macro year start=1910 end=2008>
    <#list end..start as item>
        <#assign yearlist = yearlist + [item]>
    </#list>
</#macro>
<#-- 网站Hash -->
<#assign homepageMap={"ipcat.cn":"IP猫", 
                        "ourbooks.cn":"我们的书", 
                        "hulian56.com":"互联物流",
                        "qilu56.com":"齐鲁物流"
                     }>



然后,在实际业务的ftl文件中,象下面一样引用。
<#import "*/common/util.ftl" as util>
<html>
	<head>
		<title>注册</title>
	</head>

	<body>
        <p>
            <label class="f-label" for="user.occupation">网站</label>
            <@s.select cssClass="f-select" id="user.homepage" 
                name="user.homepage" 
                list=util.homepageMap
                required="true" />
        </p>
	</body>
</html>


代码区加不了颜色,请大家直接注意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类的上半部分源代码(没有变更过的)。
/*
 * $Id: ListUIBean.java 651946 2008-04-27 13:41:38Z apetrelli $
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.struts2.components;

import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.views.annotations.StrutsTagAttribute;
import org.apache.struts2.util.ContainUtil;
import org.apache.struts2.util.MakeIterator;

import com.opensymphony.xwork2.util.ValueStack;

/**
 * DoubleListUIBean is the standard superclass of all Struts list handling components.
 *
 * <p/>
 *
 * <!-- START SNIPPET: javadoc -->
 *
 * Note that the listkey and listvalue attribute will default to "key" and "value"
 * respectively only when the list attribute is evaluated to a Map or its decendant.
 * Other thing else, will result in listkey and listvalue to be null and not used.
 *
 * <!-- END SNIPPET: javadoc -->
 *
 */
public abstract class ListUIBean extends UIBean {
    protected Object list;
    protected String listKey;
    protected String listValue;

    // indicate if an exception is to be thrown when value attribute is null
    protected boolean throwExceptionOnNullValueAttribute = false;

    protected ListUIBean(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
        super(stack, request, response);
    }

    public void evaluateExtraParams() {
        Object value = null;

        if (list == null) {
            list = parameters.get("list");
        }

        if (list instanceof String) {
            value = findValue((String) list);
        } else if (list instanceof Collection) {
            value = list;
        } else if (MakeIterator.isIterable(list)) {
            value = MakeIterator.convert(list);
        }
        if (value == null) {
            if (throwExceptionOnNullValueAttribute) {
                // will throw an exception if not found
                value = findValue((list == null) ? (String) list : list.toString(), "list",
                    "The requested list key '" + list + "' could not be resolved as a collection/array/map/enumeration/iterator type. " +
                    "Example: people or people.{name}");
            }
            else {
                // ww-1010, allows value with null value to be compatible with ww
                // 2.1.7 behaviour
                value = findValue((list == null)?(String) list:list.toString());
            }
        }

        if (value instanceof Collection) {
            addParameter("list", value);
        } else {
            addParameter("list", MakeIterator.convert(value));
        }

        if (value instanceof Collection) {
            addParameter("listSize", Integer.valueOf(((Collection) value).size()));
        } else if (value instanceof Map) {
            addParameter("listSize", Integer.valueOf(((Map) value).size()));
        } else if (value != null && value.getClass().isArray()) {
            addParameter("listSize", Integer.valueOf(Array.getLength(value)));
        }

        if (listKey != null) {
            addParameter("listKey", listKey);
        } else if (value instanceof Map) {
            addParameter("listKey", "key");
        }

        if (listValue != null) {
            if (altSyntax()) {
                // the same logic as with findValue(String)
                // if value start with %{ and end with }, just cut it off!
                if (listValue.startsWith("%{") && listValue.endsWith("}")) {
                    listValue = listValue.substring(2, listValue.length() - 1);
                }
            }
            addParameter("listValue", listValue);
        } else if (value instanceof Map) {
            addParameter("listValue", "value");
        }
    }



  • 大小: 9.1 KB
  • 大小: 4.7 KB
分享到:
评论
2 楼 dodomail 2008-11-29  
好贴啊!!!!!!
1 楼 helloworld365 2008-11-28  
好贴,顶起来!

相关推荐

    在struts2中使用freemarker模版

    这样做是为了确保Struts2在服务器启动时能优先加载这个servlet,以便支持FreeMarker模板中使用Struts2的标签。 在`struts.xml`配置文件中,定义一个action,比如`test`,并指定其结果类型为`freemarker`,这样当...

    struts2中使用freeMarker

    在Struts2中使用FreeMarker,主要涉及以下几个核心概念和步骤: 1. **配置FreeMarker**: - 在Struts2的配置文件(通常为struts.xml)中,你需要指定FreeMarker作为默认的视图技术。 - 配置FreeMarker的路径,...

    Struts2 与Freemarker 的配置方法

    - 将struts-tags.tld复制到工程的WEB-INF目录下,这将使Struts2的标签能在JSP或Freemarker模板中使用。 - 配置web.xml,添加Struts2的过滤器和过滤器映射,确保所有请求都经过Struts2处理。同时,为在Freemarker中...

    使用freemarker扩展struts标签

    6. **在模板中使用标签**: 最后,在你的FreeMarker模板文件中,你可以像使用其他内置标签一样使用你的自定义标签。 通过这种方式,开发者可以创建出高度定制的UI组件,提高代码的可读性和可维护性。自定义标签使得...

    struts2和freemarker整合

    6. **模板编写**:在FreeMarker模板中使用 `${}` 或 `#set()` 等语法访问和操作Action传入的数据。 **Web项目实例** `freemarker.rar`可能是一个包含运行示例的压缩包,其中包括: 1. **源代码**:Struts2 Action类...

    Struts2与Freemarker的配置方法

    7. **Freemarker的变量和表达式**:Freemarker允许在模板中使用`&lt;#if&gt;`, `&lt;#foreach&gt;`, `${variable}`等指令进行条件判断、循环和数据输出。同时,可以通过`&lt;@s.action&gt;`调用Struts2的标签库,实现更复杂的交互。 8...

    struts2+hibernate+freemarker项目实例

    Struts2、Hibernate和FreeMarker是Java开发领域中常见的三个开源框架,它们分别在MVC(Model-View-Controller)架构的不同层面发挥着关键作用。这个"struts2+hibernate+freemarker"项目实例是将这三个框架集成到一起...

    Struts2、Spring、Freemarker自定义标签

    Struts2、Spring和Freemarker是Java Web开发中的三个重要框架,它们分别在MVC模式的不同层面提供了功能支持。Struts2是一个基于MVC设计模式的Web应用框架,Spring是一个全面的后端应用程序框架,而Freemarker则是一...

    在struts2的freemarker模板中扩展struts标签

    众所周知,struts2宣称freemarker模板中不再支持自定义标签,但如果工程UI仅用freemarker模板可以通过扩展struts标签简单实现,不是采用官方不推荐的配置JspSupportServlet实现的!内付详细说明及范例,此方法仅为团队...

    freemarker与struts2详细配置

    在`struts.xml`中,为动作类的`execute`方法配置结果映射,指向Freemarker模板。 ```xml &lt;result type="freemarker"&gt;/WEB-INF/templates/index.ftl ``` ### 6. 运行与测试 完成上述配置后,启动服务器,访问...

    Struts2整合Freemarker生成静态页面

    6. **Struts2的OGNL表达式**:在Freemarker模板中,可以利用Struts2的OGNL(Object-Graph Navigation Language)表达式来访问复杂的对象结构和方法。例如,`${user.address.city}`可以访问User对象的嵌套属性address...

    Struts2+FreeMarker部署

    在Struts2中使用FreeMarker作为视图技术,需要进行以下步骤: 1. **配置依赖**:在项目的`pom.xml`或`build.gradle`文件中,添加FreeMarker的依赖库。 2. **配置Struts2**:在`struts.xml`配置文件中,指定使用...

    struts2中jsp和freemarker模板视图的案例

    在这个“struts2中jsp和freemarker模板视图的案例”中,我们将深入理解如何使用这两种不同的视图技术与Struts2框架进行集成。 首先,我们来看JSP(JavaServer Pages)作为视图的实现。JSP是Java中的动态网页技术,...

    struts2+freemarker

    开发者可以定义变量和方法,在模板中使用这些变量来动态地生成页面内容。 结合使用Struts2和Freemarker,开发者可以实现以下关键点: 1. **分离关注点**:通过Struts2处理业务逻辑和控制流程,Freemarker处理视图...

    struts2-freemarker

    3. **国际化与本地化**:Struts2支持国际化,可以在模板中使用`#messages`指令显示不同语言的消息。 4. **模板继承与宏**:FreeMarker支持模板继承,子模板可以继承父模板的部分内容,提高代码复用。宏可以封装常用...

    Struts2零配置+FreeMarker用户管理系统(UMS)

    Struts2和FreeMarker是Java Web开发中两个重要的框架,它们在构建动态、高效的应用程序时发挥着关键作用。这个名为"Struts2零配置+FreeMarker用户管理系统(UMS)"的项目,旨在通过注解的方式展示如何在不编写XML配置...

    freemarker 自定义freeMarker标签

    这通常是通过`Configuration`对象的`setSharedVariable`方法完成的,将你的自定义指令类实例绑定到一个特定的名字,这个名字就是你在模板中使用的标签名。 3. 使用自定义标签:在模板文件中,你可以像使用内置标签...

    Struts2与FreeMarker模板

    在Struts2中使用FreeMarker之前,首先需要进行相应的配置。通常的做法是在项目的`struts.properties`文件中添加如下配置: ```properties struts.ui.theme=none struts.views.freemarker.enabled=true ``` 其中`...

    Struts2与Freemarker生成xml文本详细步骤

    在Struts2中结合使用Freemarker,可以方便地生成XML文本,这对于数据交换或XML配置文件的生成非常有用。以下将详细介绍如何在Struts2中利用Freemarker生成XML文本的步骤。 1. **环境配置** 首先,确保你已经安装并...

    freemarker项目(从入门到与struts2结合)

    2. **整合Struts2**:搭建一个Struts2项目,配置FreeMarker,编写Action,然后在模板中使用从Action传递的数据。 3. **构建复杂页面**:通过模板继承、宏和指令,构建具有导航、头部和内容区的复杂页面。 4. **错误...

Global site tag (gtag.js) - Google Analytics