一、概述
Struts2.x中使用OGNL取代原来的EL用于页面数据绑定。
OGNL(Object-Graph Navigation Language,对象图导航语言)是一种功能强大的表达式语言,让你通过简单一致的表达式语法来读取和设置Java对象的属性值,调用对象的方法,遍历整个对象的结构图,实现字段类型转换功能。
页面数据绑定是指把页面元素(例如一个textfield,hidden)和对象层某个类的某个属性绑定在一起,修改和显示自动同步。这样做的好处非常明显:在Struts2.x中不需要为每个页面专门编写formbean,可以直接利用对象层的对象。
在B/S应用中,服务器接收到的用户数据只能是字符串或字符数组,但在服务器端的Java程序中,数据是有各种类型的,如整形、浮点型、日期类型等,以及各种自定义的数据类型。因此,在接收到客户端传过来的字符串数据后,我们还需要将这些数据转换为正确的类型。将字符串请求参数转换为相应的数据类型,是MVC框架提供的功能,而Struts2是很好的MVC框架实现者,理所当然,它也提供了类型转换机制。
Struts2的类型转换是基于OGNL表达式的,只要我们把HTML输入项(表单元素和其他GET/POET的参数)命名为合法的OGNL表达式,就可以充分利用Struts2的类型转换机制。Struts2本身对基本数据类型带有转换器,同时也提供对java.util.Date类型的转换。日期类型只需在文本输入框中输入类似2010-05-01(注意浏览器的默认语言应该是中文)这样格式的数据,提交后在action中会自动转成java.util.Date类型。
除此之外,Struts2提供了很好的扩展性,开发者可以非常简单的开发自己的类型转换器,完成字符串和自定义复合类型之间的转换。
总之,Struts2的类型转换器提供了非常强大的表现层数据处理机制,可以利用其类型转换机制来完成任意的类型转换。
二、Struts2内置的类型转换器
String
将int、long、double、boolean、String类型的数组或java.util.Date类型转换为字符串。
boolean/Boolean
在字符串和布尔值之间进行转换。
char/Character
在字符串和字符之间进行转换。
int/Integer、float/Float、long/Long、double/Double
在字符串和数值型的数据之间进行转换。
date
在字符串和日期类型之间进行转换。日期类型采用short格式处理输入和输出。
array
collection
如果不能确定对象类型,则假定集合元素类型为String,并创建一个新的ArrayList,存放所有的字符串。
com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter(内置类型转换类)
三、实现自定义类型转换器
需要实现ognl.TypeConverter接口或者继承ognl.DefaultTypeConverter类(该类实现了TypeCoverter接口)重写convertValue(Map context, Object value, Class toType)方法构建自己的类型转换器,参数context是表示OGNL上下文的Map对象,value是需要类型转换的对象,toType是要转换的目标类型。
为了简化类型转换器的实现,Struts2提供了org.apache.struts2.util.StrutsTypeConverter抽象类,这个抽象类是DefaultTypeConverter的子类,并提供了两个不同转换方向的方法:
Object convertFromString(Map context, String[] values, Class toClass);
参数context是表示action上下文的Map对象,values是需要转换的字符串值,toClass是要转换的目标类型。
String convertToString(Map context, Object o);
参数context是表示action上下文的Map对象,o是要转换的对象。
四、注册自定义类型转换器
编写完自定义类型转换器类之后,需要将该类型转换器注册在Web应用中,Struts2框架才可以正常使用该类型转换器。
类型转换器的注册方式,主要有3种:
1、注册局部类型转换器:仅仅对某个Action中的属性生效。
需提供如下格式的文件
文件名称:ClassName-conversion.properties【ClassName是需要进行类型转换的Action名称】
文件内容:多个“propertyName(Action中需要转换的属性名称)= 对应的类型转换器类名(含包名)”项组成
存放位置:和Action类在同一路径下面。
2、注册全局类型转换器:对所有Action的特定类型的属性都会生效。
需提供如下格式的文件
文件名称:xwork-conversion.properties【名称固定,不可改变】
文件内容:多个“propertyClassName(Action中需要转换的属性的类的全名)= 对应的类型转换器类名(含包名)”项组成
存放位置:WEB-INF\classes\。
3、使用注解注册类型转换器:通过注解方式生成类型转换器。
注解共有6个:TypeConversion、Conversion、Element、Key、KeyProperty、CreateIfNull
TypeConversion:应用于属性和方法级别。
Conversion:应用于类型(TYPE)级别,即类、接口或者枚举。
Element:用于指定Collection或Map中的元素类型,应用于属性和方法级别。
Key:用于指定Map中的key类型,应用于属性和方法级别。
KeyProperty:用于索引集合元素的属性名,应用于属性和方法级别。
CreateIfNull:在指定的集合元素为null时,是否让框架创建它,应用于属性和方法级别。
五、应用示例
1、局部类型转换:对某个Action中的属性进行类型转换(一个属性、多个属性)
(1)、编写类型转换器类,此类继承ognl.DefaultTypeConverter类。
在自己的转换器类中重写父类的Object convertValue(Map context, Object value, Class toType)方法。
//从表单字符串转换为*****对象类型
if(Hyphen.class == toType){
......
String [] valueStrings = (String[])value;
......
}
//从*****对象类型转换为字符串
if(String.class == toType){
......
Hyphen hyphen = (Hyphen)value;
......
}
(2)、编写类型转换文件,此文件名命名规则:ClassName-conversion.properties。
例如类名是LoginAction,则其对应的类型转换文件名称是LoginAction-conversion.properties。
在LoginAction-conversion.properties添加如下内容:
hyphen=com.xawx.struts2.converter.HyphenConverter
【key:Action中需要转换的属性名称】=【value:对应的类型转换器类全名】
(3)、LoginAction-conversion.properties文件的位置和LoginAction位置相同,即它们在同一个路径下面。
2、全局类型转换(例如:在不同Action中都有Hyphen类型成员变量)
编写类型转换文件,此文件名称是固定的,名称必须是xwork-conversion.properties,将该文件放在WEB-INF\classes\下。
在xwork-conversion.properties添加如下内容:
com.xawx.struts2.type.Hyphen=com.xawx.struts2.converter.HyphenConverter
【key:需要转换的属性的类的全名】=【value:对应的类型转换器类全名】
如果多个Action中用到了相同类型的属性,在进行类型转换时,宜用全局类型转换。
3、继承Struts2内置的类型转换器类org.apache.struts2.util.StrutsTypeConverter,转换器类需要重写该类中的两个方法:
Object convertFromString(Map context, String[] values, Class toClass)
String convertToString(Map context, Object o)
4、集合属性的转换
LoginAction有一个集合属性,此集合中存放某种类型的元素。
5、使用注解注册类型转换器
@TypeConversion(
converter="com.xawx.web.converter.HyphenConverter"
)
六、类型转换中的错误消息处理
Struts2内置的拦截器负责将转换时的错误消息封装成表单域错误消息(fielderror),并将其放入ActionContext中一个名为conversionErrors的Map对象中。
在Struts2中有两个拦截器负责处理类型转换错误,一个是com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor,另一个是org.apache.struts2.interceptor.StrutsConversionErrorInterceptor。当发生转换错误后,Struts2会将请求导向到“input”结果码映射的视图,因此需要在Action的配置中添加input结果映射。为了在input视图对应的页面中显示类型转换的错误消息,需要在页面中使用<s:fielderror/>标签。如果使用的是Struts form,则无需使用<s:fielderror/>标签;如果使用的是HTML form,则需手动添加<s:fielderror/>标签。
我们可以对类型转换失败后的错误消息进行国际化。
1、创建全局错误消息资源文件:即把struts2.jar包中org\apache\struts2\default.properties文件中的struts.custom.i18n.resources属性值用自定义的message.properties文件的文件名称替换掉。【struts.custom.i18n.resources已在struts2.jar包中org\apache\struts2\default.properties文件的165行定义】
(1)、在classes目录下创建自定义国际化资源文件,例如:message.properties。
(2)、在struts.xml中添加以下配置:
<!--
在struts.xml中添加常量标签,即添加<constant>标签。把该标签的name属性设置为struts.custom.i18n.resources,value属性设置为自定义国际化资源文件的basename名称。
有全局资源文件和局部资源文件之分。
全局资源文件:message.properties
局部资源文件:LoginAction.properties(无需在struts.xml中定义)
-->
<constant name="struts.custom.i18n.resources" value="message"/>
(3)、编写自定义国际化资源文件
message.properties中的内容:【注意参看xwork.jar包中com\opensymphony\xwork2\xwork-message.properties文件】
xwork.default.invalid.fieldvalue={0}字段类型转换失败!(需要用native2ascii将中文转换为unicode字符)
其中等号左边的内容是固定不变的,等号右边的{0}也是固定不变的,代表当前的属性名,"字段类型转换失败!"是开发人员自定义的内容。
2、创建局部错误消息资源文件
(1)、在与Action相同位置的包中创建资源文件,名称为:
ClassName.properties
例如action名称是LoginAction,则资源文件名称为LoginAction.properties。
(2)、编写资源文件
在ClassName.properties中添加如下内容:
invalid.fieldvalue.属性名=属性名类型转换错误!
其中,invalid.fieldvalue为固定不变的,属性名为对应的属性名称,"属性名类型转换错误!"是开发人员自定义的内容。
当同时存在全局错误消息资源文件和局部错误消息资源文件时,局部处理优先。
【注意】
①Struts2中有两种级别的错误消息:fielderror和actionerror,两种错误级别可根据实际情况选择使用。
②Struts2中的form表单内置了错误消息显示功能,但是只能显示fielderror级别的错误消息,不能显示actionerror级别的错误消息。如果需要显示actionerror级别的消息,手动添加<s:actionerror/>标签即可。
③Struts2中的form表单默认提供了显示fielderror级别的错误消息,如果不想使用该错误消息提示功能,可以把<s:form>标签中的theme属性设置为simple,此时Struts2的表单将不会被放在表格中,开发人员可以自定义页面布局。