struts2的类型转换

    <br>1. 前面讲的自定义类型转换器是基于 ognl 的 defaulttypeconverter 类并实现 convertvalue() 方法,两个转换方向的逻辑都写在这一个方法中。而 struts 2 为我们提供了一个 defaulttypeconverter 的抽象子类 strutstypeconverter 来继承,并实现其中两个抽象方法convertfromstring() 和 converttostring(),这要简单易懂。对比 struts 1 的转换器是要实现org.apache.commons.beanutils.converter 接口,以及它的 convert() 方法的。
2. 注意,上面的 convertfromstring() 的第二个参数是一个字符串数组,所以可为请求的数组(如请求串为 ?u=1&amp;u=2&amp;u=3)定义转换器,action 中相应的属性就应为数组或 list,这一方法的返回值也该为相应的类型(数组或list,要通过第三个参数 toclass 来判断是返回数组还是 list 了)。
3. 字符串(如 "user,pass") 转换成 action 中的复合属性(如 user user) 前面是自定了类型转换器。除此之外,还可以 struts 2 内置的ognl 表达式,更简单的转换,不用写转换器。例如,你的 action 有属性 user user,只要在 jsp 页面的输入框命名为 user.name 和user.pass 即可: <br>        <input type="text" name="user.name"/> 或用标签:<s:textfield name="user.name" label="用户名"/> <br>        <input type="text" name="user.pass"/> 或用标签:<s:textfield name="user.pass" label="密 码"/> <br>    提交后,struts 2 即会帮你构造 user 对象(user = new user()),并赋上属性值(user.setname(),user.setpass()),最后 user 对象赋给 action (xxxaction.setuser(user))。所以要明白有三个必备的东西: <br>        1) user 要用一个默认构造方法 2) user 要有对应 name 和 pass 的设置方法 setname() 和 setpass() 3) action 要有 user 属性的设置方法 setuser(),getuser() 也是要的,至于功用后面能看到。 <br>其实在 struts 1 中也有这种用法,不过那是在 beanutils 中实现的。
4. 如果 action 中的属性是 map<string, user> users; 那么与此对应的表单写法就是:(用标签来写) <br>        <s:textfield name="users['one'].name" label="第一个用户名"/> <br>        <s:textfield name="users['one'].name" label="第一个密码"/> <br>        <s:textfield name="users['two'].name" label="第二个用户名"/> <br>        <s:textfield name="users['two'].name" label="第二个密码"/> <br>    应该不难想像,这个表单提交后,users 中存储的是什么吧! <br>    如果是对于 action 中的 list 属性,list<user> users; 那么与此对应的表单写法就是: <br>        <s:textfield name="users[0].name" label="第一个用户名"/> <br>        <s:textfield name="users[0].name" label="第一个密码"/> <br>        <s:textfield name="users[1].name" label="第二个用户名"/> <br>        <s:textfield name="users[1].name" label="第二个密码"/>
 
5. 归纳前面3、4、5 几点,struts2 的 action 在设置每一个属性时都会 get 一下相应的元素 getuser() 或 getusers()。 <br>    对于 3,在设置 user.name 和 user.pass 之前都会 getuser() 来获取 user 属性,如果 user 为 null 就构造 user 对象,然后设置相应的值。假如声明的时候就已构造好 user 对象,如有其他属性如 age=18,并不会被覆盖。 <br>   对于 4 和 5,也是在设置每一个属性前都会调用 getusers() 判断声明的 map 或 list 是否为 null,是则构造对应的 hashmap 或arraylist() 对象;接着根据 key 或下标去获取相应位置的元素,如果不存在或为 null 则构造之,然后设置相应属性值。由此可见,若某元素的某个属性未重设值则保留原值,若原来map或list 已有多个元素,也只会改变到 key 或索引所对应元素的某个属性。对于 list 有可能出现跳空的情况,如页面只有索引不从 0 开始 <br>         <s:textfield name="users[1].name" label="第二个用户名"/> <br>        <s:textfield name="users[1].name" label="第二个密码"/> <br>提交后就会发现,list 属性 users 的第一个元素为 null 了。同时如果尝试一下,你就会发现这里的 list 不能替代为数组 user[] users。 <br>    这种样法,可在 struts 1 中实现,但要略施些小节,见我的另一篇日志:提交多行数据到struts的actionform的list属性中 ,行为表现完全一致,只是换到 struts 2 中一切都不用自己操心。
6. 看第四点,action 之所以知道该构造什么类型的元素完全是由泛型告诉它的。如果不用泛型(比如用的是 jdk1.4),action 中仅仅声明的是 map users; 或 list users; action 该如何处理呢?它也不知道,只能够帮你构造出无类型的 hashmap 和 arraylist(),填充不了元素。这就必须在局部类型转换的配置文件中来指定集合元素的类型。例如 action 为 loginaction,就要在 loginaction-conversion.properties 中声明了,格式如下:
    #element_xxx=复合类型,基中 element 是固定的,xxx 为属性名 <br>    #下面表示为 list 属性 users 的元素为 com.unmi.vo.user 类型 <br>     element_users=com.unmi.vo.user
    对于 map,须分别指定 key 的类型和 value 的类型 <br>    #key_xxx=复合类型,基中 key 是固定的,xxx 为 map 属性名,下面写成 string 都不行的 <br>    key_users=java.lang.string <br>    指定 map 的 value 的类型与指定 list 元素类型是一样的 <br>    element_users=com.unmi.vo.user
难怪 struts 2 要与 1.5 以上 jdk 使用,泛型比配置来得方便。如果硬要用 1.4 jdk,就只有配置类型了,会多很多 conversion 文件的。在 提交多行数据到struts的actionform的list属性中 中类型的确定由 autoarraylist() 的构造参数完成。
7. set 是无序集合,所以无法像 list 那样用数字下标来访问,幸好 struts 2 可为其指定索引属性。例如,loginaction 声明为 set users; (这里好像用泛型只能省得了 element_users 说明,keyproperty_users 少不了)。则需在 loginaction-conversion.properties 中写下: <br>    #指定 set 的元素类型 <br>    element_users=com.unmi.vo.user
    #keyproperty_集合属性名=集合元素的索引属性名,这里为 user 的 name 属性 <br>    keyproperty_users=name
此时提交页面这么写,最好提交前能根据输入的用户名自动修动输入框的 name。 <br>        用户名: <input name="users('scott').name"/> <br>        密 码: <input name="users('scott').pass"/> <br>显示的时候页面可用标签 <br>        用户名: <s:property value="users('scott').name"/> <br>        密 码: <s:property value="users('scott').pass"/> <br>注意前面,访问 set 元素是用的圆括号,而不同于 map、list、数组是用中括号。我想一般也犯不着非要用 set 而不用 list,struts 2 中用set 比在 struts 1 中似乎还麻烦。
8. struts 2 内建了一批转换器:boolean、char、int、long、float、double 和它们的包装类型;date,日期格式使用请求所在 locale的 short 格式;数组,默认元素为字符串,其他类型则要转换每一个元素?(好像是一次性转换完成的);集合,默认元素为字符串xworklist(string.class, object[]),其他如 list<integer> ids,类型为 xworklist(integer.class, object[]),xworklist 继承自 arraylist。
9. 类型转换出错由 struts 来帮你处理,在默认拦截器栈中提供了 conversionerror 拦截器,不用你写一点代码逻辑。conversionerror 在出错时将错误封装成 fielderror,并放在 actioncontext 中。你所要做的就是遵循它的规则,1) 你的 action 要继承自actionsupport,2)在 struts.xml 中声明名为 "input" 的 result,出错时会在 input 逻辑视图显示信息。3)尽量用标签来写输入域(如<s:textfield name="number" label="数量"/>),这样转换出错后,就会像校验失败一样把错误信息显示在每个输入框上面(视模板而定),否则要手工用 <s:fielderror/> 输出在某处。 <br>默认时输出错误信息为(比如是属性 number,输入的是字符串时):invalid field value for field "number".你可以改变默认显示,在全局国际化资源文件中加上 xwork.default.invalid.fieldvalue={0}字段类型转换失败!。在某些时候,可能还需要对特定字段指定特别的提示信息, 那么在名为 actionname.properties 的局部资源文件中加上 invalid.fieldvalue.属性名=提示信息 (如invalid.fieldvalue.number=数量格式错误)
10. 最后是集合属性转换错误时的显示,对于页面中的同名输入框,有多个出错误,如果手工用 <s:fielderror/> 只会显示一条错误,但要是输入页是用标签(如<s:textfield name="number" label="数量"/>),仍会在每一个出错的输入框上都提示。至此类型转换的内容也就完结了。
 
 

猜你喜欢

转载自tomfish88.iteye.com/blog/1142718