您的位置:首页 > 编程语言 > Java开发

详解Struts2的类型转换(3)

2017-04-07 12:25 295 查看
四、自定义的类型转换器

大部分的时候我们使用前面的类型转换器就可以满足大部分的类型转换需求,但是也会出现很多的情况,在这些情况下,我们需要自己创建自己的类型转换器(例如将一个请求字符串转换为User对象)

下面的表单产生的参数是以“,”分隔的字符串
<s:form action="converter/login">
<s:textfield name="user" label="用户"/>
<s:submit value="转换"/>
</s:form>

而处理该请求的Action代码如下
public class LoginAction extends ActionSupport{
private User user;

public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}

@Override
public String execute() throws Exception {
if(getUser().getUsername().equals("rgx")&&getUser().getPassword().equals("lj"))
{
addActionMessage("转换成功!");
return SUCCESS;
}
addActionMessage("转换失败!");
return ERROR;
}

}

我们可以很清楚的发现Action的user属性是User类型,虽然Struts2的类型转换很强大,但是它还是不会知道如何将一个请求里的字符串转换成为Use类型的复合对象,所以开发者就需要创建自定义转换器。

实现类型转换器必须实现接口TypeConverter,但是这个接口方法太过于复杂,所以OGNL项目还为该接口提供了一个实现类DefaultTypeConverter,通常都采用扩展该类来实现自定义的类型转换器。实现自定义类型转换器需要重写converValue()方法,先看下面的代码
public class UserConverter extends DefaultTypeConverter{
// 类型转换器需要重写convertValue()方法,该方法需要完成双向转换
/* context是上下文对象
* value时需要转换的参数
* toType是转换后的目标类型
*/
public Object convertValue(Map<String, Object> context, Object value, Class toType) {
// 当需要将字符串向User对象类型转换时
if(toType == User.class){
// 系统的请求参数是一个字符串数组
String[] params = (String[]) value;
// 创建一个User对象
User user = new User();
// 只处理数组的第一个元素
// 并且将该字符串以英文逗号分割成两个字符串
String[] userValue = params[0].split(",");
// 为User实例赋值
user.setUsername(userValue[0]);
user.setPassword(userValue[1]);
return user;
}
else if(toType == String.class){
User user = (User) value;
return "<" +user.getUsername()+","+user.getPassword()+">";
}
return null;
}
}


值得注意的是上面转换器是双向的,起到作用的就是toType参数,他决定了转换后的类型。另外一点,这里的value是字符串数组而不是普通请求中的字符串,因为对于DefaultTypeConverter转换器而言,必须考虑到尽可能多的情况,所以把所有的请求参数都视为字符串数组。上面的代码中取得的就是数组的第一个元素,也是表单的第一个元素。

好了,虽然现在有了转换器,但是Struts2依然不知道何时去使用这些类型转换器。所以下一步工作就是将转换器注册进WEB应用中,Struts2才可以正常使用这些转换器。Struts2支持三种注册类型转换器的方式:
1.注册局部类型转换器:仅仅对某个Action的属性起作用。
2.注册全局类型转换器:对所有的Action的特定类型的属性都会生效。
3.使用JDK1.5的注解来注册类型转换器:通过注解方式来注册类型转换器。
这里只讲解前两种方式。
局部类型转换器,与前面的情况类似:局部类型转换器的命名方式是ActionName-conversion.properties,需要将其放在本例中LoginAction的包下,文件中添加如下一行
<propName>=<ConverterClass>,等号左边是Action需要进行类型转换的属性,右边是类型转换器的实现类。所以在本例中应当改为:user=edu.ctgu.action.converter.UserConverter。
全局类型转换器,局部类型转换器的局限性太明显了,更广阔的局面是将这个类型转换器对所有的Action的相关类型的属性的转换都起作用。全局文件命名是死的:xwork-conversion.properties。该注册文件中的代码如下
edu.ctgu.action.entity.User=edu.ctgu.action.converter.UserConverter。

这里需要说一下的就是全局类型转换器和局部类型转换器的区别。
对于局部类型转换器,无论是什么属性,就算是集合或者数组,类型转换时只会调用一次convertValue(),这也很好解释,局部类型转换器注册时直接配置的就是属性,我的Action使用你的转换器只想得到一个想要的参数类型一样的返回值,所以你这个转换器处理一遍就得给我想要的结果。
而全局类型转换器则恰恰相反,配置的是进行类型转换的类型。所以遇到了数组和集合,转换器需要一个个的去处理里面的元素,所以需要多次调用convertValue()方法。

讲了这么多,按照执行的流程。我们大致可以看出这个逻辑。首先,表单的请求参数提交给LoginAction,Action发现参数是字符串,和自己的User对象不符合,于是就去查找注册文件中配置的类型转换器,于是找到了一个转换器,将这个字符串交给转换器,并且告诉它Action需要的返回值类型,当然这个传参过程框架底层帮助实现了。转换器处理完成将返回值返回给Action。于是Action就一本满足的去执行后面的逻辑。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: