Struts2参数传递

本篇主要通过实例来讲述Struts2中各种各样的参数传递。这个参数传递的过程主要指数据从View层传递到Control层时Struts2的工作方式。根据前两篇文章的知识,我们知道,Struts2完成参数传递处理工作的基础是OGNL和ValueStack。而在这个过程中,我也把Struts2所要做的工作大致归纳为两个方面:

1. 对OGNL操作进行封装,完成OGNL表达式所表示的值到Java对象的值传递机制

2. 在参数传递的过程中,做恰当的类型转化,保证页面上的字符串能够转化成各式各样的Java对象

接下来,通过四个不同的角度,来具体讲述Struts2在这两个方面的工作。

最简单的参数传递

使用OGNL的最基本的功能,就能完成普通的Java对象的赋值工作。Struts2在内部已经完成了OGNL的基本封装。这些封装包括对OGNL表达式到Java对象的赋值机制,以及对基本的Java类型的类型转化支持。这些基本类型包括String、Number(以及其基本类型int、float、double等)、Boolean(boolean)、数组、Class、Date等类型。

在这里我想额外强调的是XWork对JDK5.0中的Enum类型和Date类型的支持。

Enum类型

枚举类型是JDK5.0引入的新特性。枚举类型也能解决很多实际问题,是J2EE编程中的最佳实践之一。XWork中,有一个专门的EnumTypeConverter负责对Enum类型的数据进行转化。

 

public class EnumTypeConverter extends DefaultTypeConverter {   
  
    /**  
     * Converts the given object to a given type. How this is to be done is implemented in toClass. The OGNL context, o  
     * and toClass are given. This method should be able to handle conversion in general without any context or object  
     * specified.  
     *  
     * @param context - OGNL context under which the conversion is being done  
     * @param o       - the object to be converted  
     * @param toClass - the class that contains the code to convert to enumeration  
     * @return Converted value of type declared in toClass or TypeConverter.NoConversionPossible to indicate that the  
     *         conversion was not possible.  
     */  
    public Object convertValue(Map context, Object o, Class toClass) {   
        if (o instanceof String[]) {   
            return convertFromString(((String[]) o)[0], toClass);   
        } else if (o instanceof String) {   
            return convertFromString((String) o, toClass);   
        }   
  
        return super.convertValue(context, o, toClass);   
    }   
  
    /**  
     * Converts one or more String values to the specified class.  
     * @param value - the String values to be converted, such as those submitted from an HTML form  
     * @param toClass - the class to convert to  
     * @return the converted object  
     */  
    public java.lang.Enum convertFromString(String value, Class toClass) {   
        return Enum.valueOf(toClass, value);   
    }   
  
}  
有了这个类,我们就可以比较轻松的对枚举类型进行数据赋值了。
通过上面的代码,就完成了对枚举类型的赋值。不过这里有一点需要特别指出:那就是XWork在XWork-2.1.X的版本之前,枚举类型不被默认支持。如果你需要获得枚举类型的自动赋值,还需要增加一个配置文件xwork-conversion.properties到classpath下:

 

 

java.lang.Enum=com.opensymphony.xwork2.util.EnumTypeConverter 

对于使用新的版本的XWork的朋友,则不需要增加这个配置文件。


Array、List、Map等容器类型的参数传递

除了简单的基于JavaBean方式的参数传递支持,Struts2还支持对Array、List、Map等容器类型的数据结构做数据赋值。不过历史一路走来,XWork针对容器类型的数据赋值一直有变化,让我们慢慢解读这些变化,从而也来看看编程思路是如何改变的。

1. 2004年,XWork-1.0.X的年代

当时XWork所支持的针对容器的数据赋值还比较土。这方面moxie在论坛上有一篇文章专门来讲述:http://www.javaeye.com/topic/8770

总的来说,那个年代对于容器的数据赋值,需要依赖于XWork的辅助类。我们可以看到,如果你要对List进行赋值,需要新建一个XWorkList的实现类,并把所需要进行数据赋值的Java类传递到XWorkList的构造函数中。而对Map等对象的赋值,也同理可得。

这种数据赋值的方式的优缺点都非常明显。优点在于简单,你不需要额外定义任何其他的内容,而是直接使用XWork的辅助类来实现类型转化。缺点在于扩展性很弱,很明显,针对某一个具体的容器,就需要一个XWork的实现类,List有XWorkList对应,Map有XWorkMap对应。甚至在那个时候,还没有Set的支持,因为没有XWorkSet的实现。所以使用这种方式,在扩展性方面需要遭受严重的考验。

2. 2006年,XWork-2.0.X的年代

也许是XWork团队看到了扩展性上的问题,所以在XWork和Webwork同时升级以后,采用了新的方式来处理容器赋值。而此时,Javaeye上也涌现出了新的文章,Tin同学对新的方式做了详细的表述:http://www.javaeye.com/topic/17939

不过这个新的整合方式似乎并不被大家所看好。


lllyq 写道
我觉得XWorkList, XWorkMap还是很有用的,挺好的设计,其实没有必要deprecated。
moxie 写道
集合支持不向下兼容。XWorkList已经是@deprecated,用它就错,还不如直接删除掉。在webwork2.2中,它需要为集合另外配置一个conversion.properties文件。真不明白,这样有什么优点?


这种新的整合方式,实际上只是解决了针对容器赋值,不需要依赖XWork的辅助类这样的一个问题,不过其付出的代价,却是多了一个配置文件,这也让人非常郁闷。好好的类型转化,平白无故多出了一个同package下的配置文件,这也无形中增加了编程的复杂度。

3. 现在,拥抱了泛型和Annotation的年代

实际上,在XWork发展到XWork-2.0.X之后,也开始注重了对泛型和Annotation的支持。所以,容器类型的转化,我们也可以尝试一下使用JDK的新特性来进行,当然这也是目前最为推荐的做法。

下面分别给出使用泛型和Annotation的代码示例:

<form method="post" action="/struts-example/ognl-collection-conversion.action">  
    <input type="text" name="users[0].name" value="aaa" />  
    <input type="text" name="users[1].name" value="bbb" />  
    <input type="text" name="users2[0].name" value="ccc" />  
    <input type="text" name="users2[1].name" value="ddd" />  
    <input type="text" name="userMap['user1'].name" value="eee" />  
    <input type="text" name="userMap['user2'].name" value="fff" />  
    <input type="text" name="userMap2['user3'].name" value="ggg" />  
    <input type="text" name="userMap2['user4'].name" value="hhh" />  
    <input type="submit" value="submit" />  
</form>  
public class OgnlConversionAction extends ActionSupport {   
  
    private static final long serialVersionUID = 4396125455881691845L;   
  
    private static final Log logger = LogFactory.getLog(Policy.class);   
       
    private List<User> users;   
       
    @Element(value = User.class)   
    private List users2;   
       
    private Map<String, User> userMap;   
       
    @Element(value = User.class)   
    private Map userMap2;   
       
    /* (non-Javadoc)  
     * @see com.opensymphony.xwork2.ActionSupport#execute()  
     */  
    @Override  
    public String execute() throws Exception {   
           
        // -> aaa   
        logger.info("users[0].name : " + users.get(0).getName());   
        // -> bbb   
        logger.info("users[1].name : " + users.get(1).getName());   
        // -> ccc   
        logger.info("users2[0].name : " + ((User)users2.get(0)).getName());   
        // -> ddd   
        logger.info("users2[1].name : " + ((User)users2.get(1)).getName());   
           
        // -> [user1, user2]   
        logger.info("userMap.key : " + userMap.keySet());   
        // -> eee   
        logger.info("userMap.key = " + "user1" + " : " + "userMap.value(user1's name) = " + userMap.get("user1").getName());   
        // -> fff   
        logger.info("userMap.key = " + "user2" + " : " + "userMap.value(user2's name) = " + userMap.get("user2").getName());   
        // -> [user3, user4]   
        logger.info("userMap2.key : " + userMap2.keySet());   
        // -> ggg   
        logger.info("userMap2.key = " + "user3" + " : " + "userMap.value(user3's name) = " + ((User)userMap2.get("user3")).getName());   
        // -> hhh   
        logger.info("userMap2.key = " + "user4" + " : " + "userMap.value(user4's name) = " + ((User)userMap2.get("user4")).getName());   
           
        return super.execute();   
    }   
       
    // setters and getters   
}  
上面的代码中,我们可以看到,如果你使用泛型,那么你无需再使用任何额外的配置文件或者Annotation,XWork会把一切都为你准备好。如果你没有使用泛型,那么你可以使用Annotation来指定你需要进行转化的对象类型。其中,对Map对象使用Annotation时,Element中的value所对应的值,是Map中的value所对应的class。

由此可见,泛型和Annotation,在一定程度上,还是可以简化我们很多工作的。

文件上传

文件上传其实也是参数传递的一种,所以从方案上来讲,Struts2同样使用了一个拦截器来处理。而这个拦截器,同样来自于原来的Webwork,基本上没有做什么很大的改变。有关这个拦截器的详细内容,我们也留一个悬念,在后续章节中详细讲解。目前,你只要知晓,这个拦截器能帮助你完成一切文件上传相关的机制。

早在2005年,Quake Wang就对Webwork的文件上传机制有了详细的讲解:http://www.javaeye.com/topic/10697

在这里我简单小结一下在进行文件上传时的三大要点:

1. 在配置文件上传时,拦截器的顺序非常关键

<interceptor-stack name="uploadStack">     
    <interceptor-ref name="upload"/>                     
    <interceptor-ref name="defaultStack"/>     
</interceptor-stack> 
具体来说,upload的拦截器,必须在params的拦截器之前

2. 拦截器额外提供了一些额外的文件信息

Quake Wang 写道
ContentType: 文件的ContentType(可以用在做download的时候)
FileName: 实际的文件名
在上面的action例子里, 那么有uploadFilesContentType和uploadFilesFileName这2个属性, 也能够被自动绑定


3. 拦截器提供的文件上传功能,你得到的是一个临时文件

robbin 写道
在webwork的file upload 拦截器功能中,它提供的File只是一个临时文件,Action执行之后就会被自动删除,因此你必须在Action中自己出来文件的存储问题,或者写到服务器的某个目录,或者保存到数据库中。如果你准备写到服务器的某个目录下面的话,你必须自己面临着处理文件同名的问题


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/njzdl/archive/2010/08/06/5794126.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值