大多数情况下只需要使用Struts2提供的类型转换器以及基于OGNL的类型转换机制就能满足大部分类型转换需求。但是如果需要把一个字符串转换成一个复合对象(例如User对象)时,这就需要使用自定义类型转换器。例如,用户输入一个admin,12345字符串,我们需要将其转换成一个User类型实例,其中admin作为User实例的name属性值,12345作为User实例的password属性值。
如图:
我们就需要定义一个自定义类型转换器,来完成这个需求。
Action类代码
package com.test.action;
import com.opensymphony.xwork2.Action;
import com.test.dao.User;
public class LoginAction implements Action{
//封装请求参数的Map对象
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
//处理用户请求的execute方法
public String execute() throws Exception {
// 调用user属性的name、password进行判断
if(getUser().getName().equals("admin")
&&getUser().getPassword().equals("12345")){
return SUCCESS;
}else{
return ERROR;
}
}
}
package com.test.dao;
public class User {
private String name;
private String password;
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
publicinterface TypeConverter {
public Object convertValue(Map context, Object target, Member member,
String propertyName, Object value, Class toType);
}
不过上面接口里的方法太复杂了,所以OGNL项目还提供了一个该接口的实现类:DefaultTypeConverter,通过继承该类来实现自己的类型转换器。实现自定义类型转换器需要重写DefaultTypeConverter类的convertValue方法。
本应用所使用的类型转换器UserConverter如下
package com.test.action;
import java.util.Map;
import com.opensymphony.xwork2.conversion.impl.DefaultTypeConverter;
import com.test.dao.User;
//通过继承DefaultTypeConverter来实现类型转换器
public class UserConverter extends DefaultTypeConverter{
//类型转换器必须重写convertValue方法,该方法需要完成双向转换。通过判断toType参数的类型即可判断转换的方向
public Object convertValue(Map context,Object value,Class toType){
//toType类型是需要转换的目标类型
//当需要将字符串向User类型转换时
if(toType==User.class){
//系统的请求参数是一个字符串数组
String[] params=(String[]) value;
//创建一个User实例
User user=new User();
//只处理请求参数数组的第一个数组元素,并将该字符串以英文逗号分割成两个字符串
String[] userValues=params[0].split(",");
//为User实例赋值
user.setName(userValues[0]);
user.setPassword(userValues[1]);
//返回转换来的User实例
return user;
}
//当需要将User实例转换成字符串时
else if(toType==String.class){
//将需要转换的值强制类型转换为User实例
User user=(User) value;
return "<"+user.getName()+","+user.getPassword()+">";
}
return null;
}
}
convertValue方法介绍
作用:该方法负责完成类型的转换,这种转换是双向的。通过判断toType参数的类型即可实现判断转换的方向。toType类型是需要转换的目标类型,当toType类型是User类型时,表明需要将字符串转换成User实例;当toType类型是String类型时,表明需要将User实例转换成字符串类型。
参数和返回值的意义:
该方法有三个参数
1、context是类型转换环境的上下文
2、value是需要转换的参数。随着转换方向的不同,value参数的值也是不一样的,当把字符串类型向User类型转换时,value是原始字符串数组;当需要把User类型转换成字符串类型时,value是User实例。
3、toType是转换后的目标类型。
该方法的返回值就是类型转换后的值,该值的类型也会随转换方向的不同而不同,当需要把字符串向User类型转换时,返回值类型就是User类型;当需要把User类型向字符串类型转换时,返回值类型就是字符串类型。
由此可见,转换器的convertValue方法,接收需要转换的值,需要转换的目标类型为参数,然后返回转换后的目标值
实现了自定义类型转换器之后,将该类型转换器注册在Web应用中,Struts2框架才可以正常使用该类型转换器。
类型转换器注册的方式有三种:
1、注册局部类型转换器:局部类型转换器仅仅对某个Action的属性起作用。
2、注册全局类型转换器:全局类型转换器对所有Action的特定类型的属性都会生效。
3、使用JDK1.5的Annotation来注册类型转换器
局部类型转换器的注册
要注册局部类型转换器只需要提供文件名为如下格式的文件即可。
ActionName-conversion.properties:ActionName是需要转换器生效的Action的类名,而后的字符串则是固定部分。
对于上面的LoginAction类,应该提供的类型转换器注册文件的文件名为:LoginAction-conversion.properties,该文件是一个典型的Properties文件,文件由key-value对组成。文件内容为:propertyName=类型转换器类
本应用所使用的LoginAction-conversion.properties文件
user=com.test.action.UserConverter
至此,局部类型转换器注册成功。
如果在用户信息输入框中输入“admin,12345”字符串,根据类型转换器的作用,它会将admin解析成User实例的name属性,12345将被作为User实例的password属性。如图
局部类型转换器只对指定Action的特定属性起作用,这具有很大的局限性。通常我们会将类型转换器注册成全局类型的转换器,让该类型转换器对该类型的所有属性起作用。
下图所示的输入页面,包含三个请求参数,其中用户信息和客人信息都需要转换成User类型,而生日参数则需要转换成Date类型。
Action类
package com.test.action;
import java.util.Date;
import com.opensymphony.xwork2.Action;
import com.test.dao.User;
public class LoginAction implements Action{
//使用类型转换器将字符串请求参数直接转换成一个User实例
private User user;
//封装customer请求参数的属性
private User customer;
//封装birth请求参数的属性
private Date birth;
//无参构造函器
public LoginAction() {
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public User getCustomer() {
return customer;
}
public void setCustomer(User customer) {
this.customer = customer;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
//处理用户请求的execute方法
public String execute() throws Exception {
// 调用user属性的name、password进行判断
if(getUser().getName().equals("admin")
&&getUser().getPassword().equals("12345")){
return SUCCESS;
}else{
return ERROR;
}
}
}
注册全局类型转换器需要一个名为xwork-conversion.properties的文件,该文件也是Properties文件,其内容由多个“复合类型=对应的类型转换器”项组成,其中“复合类型”指定需要完成类型转换的复合类,“对应类型转换器”指定所指定类型转换的转换器。
下面是本应用中注册全局类型转换器的注册文件代码
com.test.dao.User=com.test.action.UserConverter
一旦注册了上面的全局类型转换器,该全局类型转换器就会对所有的User类型属性起作用
。
在用户信息输入框中输入“admin,12345”,在客人信息输入框中输入“abc,def”,在生日输入框中输入“2013-01-10”,然后提交请求,将看到如下所示
局部类型转换器对指定Action的指定属性起作用,一个属性只调用convertValue方法一次。全局类型转换器对所有Action的特定类型起作用,因此可能对一个属性多次调用convertValue方法进行转换--当该属性是一个数组或集合时,该数组或集合中包含几个该类型的元素,那就会调用几次convertValue方法。