浏览器服务器之间的数据通信不可能有丰富的数据类型,实际上http参数都是字符串类型的。因此必须在服务器端完成数据类型的转换。Struts2有强大的内建转换机制,类型转换可以依赖于OGNL表达式。开发者也可以自己创建类型转换器。
内建的类型转换器和基于OGNL类型转换
Struts2可以完成大多数常用的类型转换。借助于OGNL,Struts2允许以另一种简单方式请求参数转换成符合类型。比如表单需要提交的action中有一个user类型属性,那么提交的时候直接使用user.name和user.pass即可将表单数据传给user实例的相应属性。这种方式能够将普通的http请求参数(字符串)转化为符合类型对象(user对象,而非普通的String,int等)。演示代码如下:
<s:form action="lalala/login"> <s:textfield name="user.name" label="U" /> <s:textfield name="user.gender" label="gender"/> <s:textfield name="username" label="username"/> <s:submit value="adg"/> </s:form>
此表单会将username中内容赋给login中的username属性,将name与gender赋给login中user实例的name与gender属性。
<s:property value="user.gender"/><br/> <s:property value="user.name"/><br/>
在success视图页,通过property标签提取相关属性值。
此外如果想要给login这个类的Map<String,user> users赋值,我们就既需要指明给哪个value赋值,也需要指明这个值是此value下的什么属性。例如:
<s:form action="lalala/login"> <s:textfield name="users['1'].gender" label="gender1" /> <s:textfield name="users['1'].name" label="name1" /> <s:textfield name="users['2'].gender" label="gender2" /> <s:textfield name="users['2'].name" label="name1" /> <s:submit value="submit"/>
jsp中访问的时候:
<s:property value="users['1'].gender"/>
--------------------------------------------------
如果把map换成list,写法一样,只不过[]中的内容不同。map的[]中的内容是value,是String类型。而list的[]是数字,是int类型。不过它们都是user对象的标识(id)。
不使用泛型的时候,架构是没办法使用类型转换器处理users属性的,因此需要一个局部类型转换文件。这个文件是与action相对应的。文件中不仅可以指定action中的某个属性使用哪个自定义类型转换器,还能够指定此action的list元素是哪种对象类型。在login-conversion.properties中填写如下一行代码:
Element_users=com.cm.actions.user
此种代码专门为list而生,users指定的就是list中的元素类型。
自定义类型转换器
如果用户输入的是aaa,bbb,而我们想让aaa成为action中user属性的username,bbb成为user属性的password,就需要使用自定义类型转换器。自定义类型转换器能够将一个输入的字符串预处理,按照自定义的方式转换成相应实例的某种属性类型。转换器必须实现TypeConverter接口。但是这个接口过于复杂,所以GONL提供了一个DefaultTypeConverter类,它是这个接口的实现类。自定义转换器要继承该类,然后重写convertValue方法。一个自定义转换器能够完成双向的类型转换。书中的例子是,User可以转成字符串,字符串也可以转成User类型。为了确定转换方向,需要判断toType属性,它代表的目标属性,究竟是想要转到String,还是User。此方法中的三个参数,context是类型转化上下文,当需要转换ActionContext的时候使用。value是需要转换的参数,它其实是一个字符串数组,toType是目标类型。参考文章actioncontext
上述方法是基于非框架的。Struts2框架还提供了一个StrutsTypeConverter抽象类,它更好地实现了TypeConverter接口,将两个转换方向分成两个不同的方法。代码如下:
public class userconverter extends StrutsTypeConverter { @Override public Object convertFromString(Map arg0, String[] arg1, Class arg2) { user user = new user(); String[] userValues = arg1[0].split(","); user.setGender(userValues[1]); user.setName(userValues[0]); // TODO Auto-generated method stub return user; } @Override public String convertToString(Map arg0, Object arg1) { user user = (user) arg1; // TODO Auto-generated method stub return user.getName() + user.getGender(); } }
这里我们注意到,converFromString方法中的String是从一个字符串数组中取出来的。为什么不直接使用一个字符串呢?那是因为有些时候的输入,比如多选框,下拉框,传进来的String可能是很多个,它们对应的请求参数就是字符串数组。
由于现在user的两个属性值由同一个字符串表示了,所以在写表单的时候,不需要再用OGNL表达式来制定aciton的属性的属性了,直接写action的属性名。如下
<s:form action="lalala/login"> <s:textfield name="user" label="U and gender" /> <s:textfield name="username" label="username"/> <s:submit value="submit"/>
注册类型转换器
我们需要告诉架构什么时候需要使用哪一个类型转换器,因此我们要将类型转换器注册。我们可以注册全局,局部类型转换器,也可以通过JDK的注解实现。
局部类型转换器使用局部类型转换文件指定。此文件应该与对应的action同一目录,严格按照命名规则,ActionName-conversion.properties。此文件中添加如下一行:
user=com.cm.converter.userconverter
局部转换器只对一个action起作用(因为是根据actionclassname匹配的)。全局类型转换器能够针对多个action的user属性,或者一个action中的多个user属性进行类型转换。在WEB-INF/classes下创建一个xwor-conversion.properties文件,里面进行注册。此时注册代码要把包名打全。
com.cm.actions.login.user=com.cm.converter.userconverter
错误处理
由于表现层的用户输入可能存在错误,因此有必要对数据的正确性进行校验,同时提供错误处理的方法。实际上struts2中的校验跟类型转换是紧密相关的。因为在类型转换前,系统必须确保数据已经经过校验。
在默认xml中我们发现有一个conversionError拦截器,该拦截器能够处理转换中的异常,将错误封装成表单错误FieldError,并将这些信息放在ActionContext中。在处理页面(result为input的页面)中使用s:fielderror标签即可输出错误信息。为了使用这套机制,action必须继承ActionSupport类。
如果想国际化地输出类型转换错误信息,则要在国际化资源文件中增加key为xwork.default.invalid.fieldvalue的字段。
本文出自 “指尖轻飞” 博客,谢绝转载!