第五章 数据转移:OGNL和类型转换
5.1 数据转移和类型转换:Web应用程序领域的常见任务
5.2 OGNL和Struts 2
OGNL代表Object-Graph Navigation Language(对象图导航语言)。它被集成在Struts 2框架中用来帮助实现数据转移和类型转换。
表达式语言允许我们使用简单的语法来引用Java环境中存在的对象。
OGNL如何融入框架,如下图所示:
params拦截器将会把请求对象中的数据转移到ValueStack上。这个工作微妙的地方是将参数的名字映射到ValueStack上的一个真实的属性。这是OGNL进入的地方。params拦截器把请求参数的名字解析为一个OGNL表达式,用来在ValueStack上定位正确的目标属性。
ValueStack是一个虚拟的对象?这听起来有点复杂,但实际上并不复杂。ValueStack持有一堆对象,这些对象都有属性。ValueStack的魔力是这些对象的所有属性看起来像是ValueStack的属性。
5.3 内建的类型转换器
Struts 2 框架自带了对HTTP本地字符串和以下列出的Java类型之间转换的内建支持。
- String
- boolean/Boolean,true和false字符串可以被转换为Boolean的原始类型和对象类型
- char/Character,原始类型或者对象类型
- int/Integer、float/Float、long/Long、double/Double,原始类型或者对象类型
- Date,当前Locale的SHORT格式的字符串版本(例如,12/10/98)
- Array,每一个字符串元素必须能够转换为数组的类型
- List,默认情况下使用String填充,也可以使用泛型
- Map,默认情况下使用String填充,也可以使用泛型
当框架定位到一个给定的OGNL表达式指向的Java属性时,它会查找这个类型的转换器。如果这个类型在前面的列表中,你不需要做任何事情,等着接收数据即可。
类型转换错误导致用户会被返回到输入页面,这与验证出错的情况相似。
当尝试导航到目标属性时,如果发现深层OGNL表达式中的任何中间属性不存在(null),框架会自动实例化它们。解决不存在属性的访问能力依赖于每一个属性都存在一个默认的构造方法。
5.4 自定义类型转换
类型转换是OGNL的一部分。正因如此,所有类型转换器必须都实现ognl.TypeConverter接口。Struts 2 提供了一个开发人员编写自定义类型转换器时可以使用的便利基类,org.apache.struts2.util.StrutsTypeConverter。
public abstract class StrutsTypeConverter extends DefaultTypeConverter {
public Object convertValue(Map context, Object o, Class toClass) {
if (toClass.equals(String.class)) {
return convertToString(context, o);
} else if (o instanceof String[]) {
return convertFromString(context, (String[]) o, toClass);
} else if (o instanceof String) {
return convertFromString(context, new String[]{(String) o}, toClass);
} else {
return performFallbackConversion(context, o, toClass);
}
}
/**
* Hook to perform a fallback conversion if every default options failed. By default
* this will ask Ognl's DefaultTypeConverter (of which this class extends) to
* perform the conversion.
*
* @param context
* @param o
* @param toClass
* @return The fallback conversion
*/
protected Object performFallbackConversion(Map context, Object o, Class toClass) {
return super.convertValue(context, o, toClass);
}
/**
* Converts one or more String values to the specified class.
*
* @param context the action context
* @param values 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 abstract Object convertFromString(Map context, String[] values, Class toClass);
/**
* Converts the specified object to a String.
*
* @param context the action context
* @param o the object to be converted
* @return the converted String
*/
public abstract String convertToString(Map context, Object o);
}
其中的两个抽象方法是必须实现的。
配置框架使用自定义转换器有两种方式:
- 属性专用。第一种选择是指定这个转换器用来转换给定动作类上的给定属性。我们使用ActionName-conversion.properties文件为特定的属性指定自定义转换器。
- 全局类型转换。我们使用xwork-conversion.properties文件指定类型转换器。