String username= requst.getParameter("username"); //获取年龄然后转换成了整数 int age=Integer.parseInt(requst.getParameter("age"));
前面说的内建的类型转换器只是在普通的类型之间的转换,都是一些基本的类型可以实现自动转换,并不用自己定义类型转换器。但是我们现在需要将输出的字符串转换为复合对象,比如一个User(username,password)类,那么现在就不能使用内建的类型转换器自动转换了,现在需要自己定义类型转换器了。
实现类型转换器也是基于OGNL实现的,在OGNL中有一个 TypeConverter
接口,但是这个接口太复杂了,因此OGNL还提供了一个类 DefaultTypeConverter
,通过继承这个类就可以实现类型转换器了。
假设我们在登录界面需要在一个text中输入用户名和密码用逗号隔开,现在我们可以使用自定义的转换器。现在登录的JSP如下:
<form action="http://localhost:8080/web3/login" method="post"> <label>请输入用户名和密码(逗号隔开):</label> <input type="text" name="user"> <input type="submit" value="提交"> </form>
public class User{ private String username; //用户名 private String password; //密码 public String getUsername(){ return username; } public void setUsername(String username){ this.username = username; } public String getPassword(){ return password; } public void setPassword(String password){ this.password = password; } }
import com.opensymphony.xwork2.Action; import com.user.User; public class LoginActionimplements Action{ private User user; // User对象 public User getUser(){ return user; } public void setUser(User user){ this.user = user; } public String execute()throws Exception { return SUCCESS; } }
import java.util.Map; import com.user.User; import ognl.DefaultTypeConverter; public class UserConverterextends DefaultTypeConverter{ /* * context:类型转换的上下文环境 * value: value是需要转换的参数,随着转换的方向不同,value的参数值也是不一样的,因此需要强制转化 * toType: 表示转换后的目标类型 */ public Object convertValue(Map context, Object value, Class toType){ System.err.println("调用了"); // 有字符串转http://download.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html#sum换为User类 // toType表示转向的类型 if (toType == User.class) { String[] params = (String[]) value; // 将字符串转换为数组 User user = new User(); // 创建User对象 // 利用逗号将数组中的第一个字符串分割为两个字符串,设置成username,password user.setUsername(params[0].split(",")[0]); user.setPassword(params[0].split(",")[1]); return user; // 最后一定要返回User对象 } // 如果是从复合类转换为字符串 else if (toType == String.class) { User user = (User) value; // 将value转换为User对象 // 最后返回一个字符串表现的形式 return user.getUsername() + "," + user.getPassword(); } else { return null; // 没有相互转换的条件返回null } } }
context: 是类型转换环境的上下文
value :是需要转换的类型参数。随着转换方向的不同,value参数的值也是不一样的,当把字符串类型转换为User类型时,value就是原始字符串。当需要把User类型向字符串类型转换时,value是User的实例。当然无论向哪一个方向转换,value都是需要强制转换的。
toType: 是转换后的目标类型。
为什么自己当向User类转换的时候,value要转换为一个字符数组呢?
转换器分为局部转换器和全局转换器,局部转换器是针对指定的Action类,但是全局转换器是针对的是该项目中所有需要转换的Action类。
前面已经实现了Action类,现在我们只需要定义一个ActionName-conversion.properties文件和Action放在一个目录下即可,其中的ActionName是Action的类名,比如上面的Action类是LoginAction,那么这里的文件就是LoginAction-conversion,.properties。其中的内容如下:
user=com.converter.UserConverter
com.user.User=com.converter.UserConverter com.date.Date=com.converter.Date
其中的内容是一键值对存在的,com.user.User对应的是定义的JavaBean类,这里不再是action类中的定义的User对象了,是需要转换对象的类,com.converter.UserConverter这个是定义转换器的类。
从上面我们可以看出来定义两个转换器,最后一个是将字符串转换为日期类型的转换器。其实其中可以定多个类型转换器,并且只要是一键值对的形式写出即可。
上面的类型转换器都是基于OGNL的DefaultTypeConverter类实现的,基于该类实现转换时都要实现ConverterValue()方法,无论是从字符串转换为复合类型还是从复合类型转换为字符串都是在这个方法中实现。
为了简化类型转换器的实现,Struts2提供了一个StrutsTypeConverter抽象类,这个抽象类是DefaultTypeConverter的子类。其中重要的方法如下:
下面实现上面的登录转换,如下:
import java.util.Map; import org.apache.struts2.util.StrutsTypeConverter; import com.user.User; public class UserConverterStrutsextends StrutsTypeConverter{ protected Object performFallbackConversion(Map context, Object o, Class toClass) { return super.performFallbackConversion(context, o, toClass); } // 将字符串转换为复合类型的方法 public Object convertFromString(Map context, String[] values, Class toClass){ User user = new User(); //创建User对象 String[] userValues = values[0].split(","); // 将字符串数组中的第一个字符串分隔开 user.setUsername(userValues[0]); user.setPassword(userValues[1]); return user; } // 将复合类型转换为字符串 public String convertToString(Map context, Object values){ User user = (User) values; //强制转换成User类型的 String username = user.getUsername(); //获取username和password String password = user.getPassword(); return "<" + username + "," + password + ">"; } }
有了上面的转换器,那么局部转换器和全局转换器的配置还是和上面的一样,这里就不在赘述了。
<form action="http://localhost:8080/web3/login" method="post"> <label>请输入用户名和密码(逗号隔开):</label> <input type="text" name="users"> <input type="text" name="users"> <input type="submit" value="提交"> </form>
从上面的代码我们可以看出这里text中有两个name属性相同的表单,这个同时提交上去就是一个数组。
Action类:(定义一个User数组):
import com.opensymphony.xwork2.Action; import com.user.User; public class LoginSActionimplements Action{ private User[] users; //定义数组类型User public User[] getUsers() { return users; } public void setUsers(User[] users){ this.users = users; } public String execute()throws Exception { System.out.println(getUsers()[0].getUsername()); return SUCCESS; } }
import java.util.Map; import org.apache.struts2.util.StrutsTypeConverter; import com.user.User; public class UsersConverterStrutsextends StrutsTypeConverter{ // 将字符串转换复合类型 public Object convertFromString(Map context, String[] values, Class toClass){ if (values.length > 1) { User[] results= new User[values.length]; // 创建对象,这里是创建和字符串数组一样的长度 // 遍历所有的字符串数组,然后将其填入每一个User对象中 for (int i = 0; i < values.length; i++) { User user=new User(); //创建user对象 String[] uservalues = values[i].split(","); user.setUsername(uservalues[0]); // 将其设置为User的属性 user.setPassword(uservalues[1]); results[i]=user; //将实例化的user对象,填入数组 } return results; } else { // 这里表示数组中只有一个字符串 User user = new User(); // 创建对象 String[] uservalues = values[0].split(","); user.setUsername(uservalues[0]); user.setPassword(uservalues[1]); return user; } } // 将复合类型转换为字符串 public String convertToString(Map context, Object values){ // 只是一个单个的User类型的 if (values instanceof User) { User user = (User) values; String username = user.getUsername(); String password = user.getPassword(); return "<" + username + "," + password + ">"; } // User数组 else if (values instanceof User[]) { User[] users = (User[]) values; //转换为User数组 String results = "["; for (User user : users) { String username = user.getUsername(); String password = user.getPassword(); results += "<" + username + "," + password + ">"; } return results + "]"; //返回全部的字符串 } else { return ""; } } }