Struts2之类型转换器
- 本人独立博客https://chenjiabing666.github.io
- 在我们接收表单的请求参数的时候其实默认的都是String类型,但是有时候我们需要其他的数据类型,比如int,double,float,Date。
- 其实前面表单的传值都是字符串形式的,但是为什么我们在JavaBean中定义了不同的类型的数据,Struts还是会正确接收表单传递过来的值呢,因为使用了Struts中的内建的类型转换器
传统的类型转换器
- 在Servlet中我们可以自己获取请求参数自己转换类型,通常使用request.getParamerter(String name) 获取请求的参数 如下:
代码语言:javascript
复制String username= requst.getParameter("username");
//获取年龄然后转换成了整数
int age=Integer.parseInt(requst.getParameter("age"));
内建的类型转换器
- 其实内建的类型转换器已经可以完成大部分的功能了,比如表单传值,其实传递的是字符串,但是我们在JavaBean中定义的却是不同类型的数据,内部原理就是用了内置的类型转换器
- 内建类型转换器可以完成基本类型之前的转换
自定义类型转换器
- 前面说的内建的类型转换器只是在普通的类型之间的转换,都是一些基本的类型可以实现自动转换,并不用自己定义类型转换器。但是我们现在需要将输出的字符串转换为复合对象,比如一个User(username,password)类,那么现在就不能使用内建的类型转换器自动转换了,现在需要自己定义类型转换器了。
- 实现类型转换器也是基于OGNL实现的,在OGNL中有一个
TypeConverter
接口,但是这个接口太复杂了,因此OGNL还提供了一个类DefaultTypeConverter
,通过继承这个类就可以实现类型转换器了。 - 假设我们在登录界面需要在一个text中输入用户名和密码用逗号隔开,现在我们可以使用自定义的转换器。现在登录的JSP如下:
代码语言:javascript
复制<form action="http://localhost:8080/web3/login" method="post">
<label>请输入用户名和密码(逗号隔开):</label>
<input type="text" name="user">
<input type="submit" value="提交">
</form>
代码语言:javascript
复制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;
}
}
代码语言:javascript
复制import com.opensymphony.xwork2.Action;
import com.user.User;
public class LoginAction implements 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;
}
}
代码语言:javascript
复制import java.util.Map;
import com.user.User;
import ognl.DefaultTypeConverter;
public class UserConverter extends 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
}
}
}
- 从上面的代码可以看出有两类的转换:一是从字符串转换为User类,二是从User类转换为字符串,这个都是使用toType来控制的。
ConverterValue方法参数和返回值的含义
- 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是Action中定义User对象,com.converter.UserConverter是对应的转换的类,一定要定义到包名。
代码语言:javascript
复制 user=com.converter.UserConverter
全局转换器
- 全局转换器是作用于全部需要转换的Action的,只需要定义一个xwork-conversion. Properties。这个的名字就不需要改变了,放在src目录下即可,这样才可以作用到全局中。内容如下:
代码语言:javascript
复制com.user.User=com.converter.UserConverter
com.date.Date=com.converter.Date
- 其中的内容是一键值对存在的,com.user.User对应的是定义的JavaBean类,这里不再是action类中的定义的User对象了,是需要转换对象的类,com.converter.UserConverter这个是定义转换器的类。
- 从上面我们可以看出来定义两个转换器,最后一个是将字符串转换为日期类型的转换器。其实其中可以定多个类型转换器,并且只要是一键值对的形式写出即可。
基于Struts2的类型转换器
- 上面的类型转换器都是基于OGNL的DefaultTypeConverter类实现的,基于该类实现转换时都要实现ConverterValue()方法,无论是从字符串转换为复合类型还是从复合类型转换为字符串都是在这个方法中实现。
- 为了简化类型转换器的实现,Struts2提供了一个StrutsTypeConverter抽象类,这个抽象类是DefaultTypeConverter的子类。其中重要的方法如下:
- public Object convertFromString(Map context, String[] values, Class toClass)将字符串转换为复合类型个方法。
- context是上下文环境,value是字符串数组,toClass是要转换的类型
- public String convertToString(Map context, Object values) 将复合类型转换为字符串
- values是复合类对象,context是上下文环境
- public Object convertValue(Map context, Object values, Class toClass)实现DefaultTypeConverter方法,其中的变量还是上面的意思
- 下面实现上面的登录转换,如下:
代码语言:javascript
复制import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
import com.user.User;
public class UserConverterStruts extends 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 ">";
}
}
- 有了上面的转换器,那么局部转换器和全局转换器的配置还是和上面的一样,这里就不在赘述了。
数组属性的类型转换器
- 数组类型的转换器是用于提交的参数为数组的类型的,也就是同时Action中有一个属性为数组。
- 现在我们要同时输入两个用户的信息,jsp如下:
代码语言:javascript
复制 <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数组):
代码语言:javascript
复制import com.opensymphony.xwork2.Action;
import com.user.User;
public class LoginSAction implements 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;
}
}
代码语言:javascript
复制import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
import com.user.User;
public class UsersConverterStruts extends 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 "";
}
}
}