通过继承OGNL中的DefaultTypeConverter类,并重写其convertValue方法,实现自定义类型转换。我们先看一个示例,然后再作相关说明。
第一步:创建web project
创建web project并命名为localconverter。
第二步:写输入页面
写输入页面,input1.jsp,其主要代码如下:
局部类型转换器
请输入用户名和密码(中间以逗号分隔)
第三步:写配置文件
在struts.xml中,配置action,其主要代码如下:
output1.jsp
error.jsp
第四步:写Action
写相应的LoginAction.java,其代码如下:
package com.test.action;
import com.opensymphony.xwork2.ActionSupport;
import com.test.bean.User;
public class LoginAction extends ActionSupport {
private String result;
private User user;
//此处省略getter和setter方法
public String execute() throws Exception {
if(getUser().getName().equals("hello")
&& getUser().getPassword().equals("world")) {
setResult("登录成功");
return SUCCESS;
} else {
setResult("登录失败!");
return ERROR;
}
}
}
第五步:写JavaBean
写JavaBean,User.java其代码如下:
package com.test.bean;
public class User {
private String name;
private String password;
//此处省略getter和setter方法
} 第六步:写自定义类型转换器
写UserConverter.java其代码如下:
package com.test.converter;
import java.util.Map;
import com.test.bean.User;
import ognl.DefaultTypeConverter;
public class UserConverter extends DefaultTypeConverter{
@Override
//自定义类型转换器,须重写convertValue方法,该方法完成双向转换
public Object convertValue(Map context, Object value, Class toType) {
//当字符串向User类型转换时
if(toType==User.class) {
//系统的请求参数是一个字符串数组
String[] params = (String[]) value;
User user = new User();
//只处理请求参数数组第一个数组元素,并将该字符串以英文逗号分割成两个字符串
String[] userValue = params[0].split(",");
user.setName(userValue[0]);
user.setPassword(userValue[1]);
return user;
} else if(toType == String.class) {
User user = (User)value;
return "<" + user.getName() + ","
+ user.getPassword() + ">";
}
return null;
}
}
第七步:注册类型转换器
这里写局部类型转换文件LoginAction-conversion.properties,其代码如下:
user=com.test.converter.UserConverter
第八步:写输出界面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags"%>
output1
转换成功
用户名名为:
用户密码为:
第九步:运行检测
输入界面1 输出界面1
Struts2的类型转化器实际上依然是基于OGNL框架的,在OGNL项目中有一个TypeConverter接口,这个接口就是自定义类型转换器必须实现的接口。该接口的定义代码如下:
//OGNL提供的类型转换器接口
public interface TypeConverter {
public Object convertValue(Map context, Object target, Member member, String propertyName,
Object value, Class toType);
}
实际类型转换器必须实现上面的TypeConverter,不过上面接口里的方法太过复杂,所以OGNL还为该接口提供了一个实现类:DefaultTypeConverter,通常都采用改类来实现自定义类型转换。实现自定义类型转换器需要重写DefaultTypeConverter类的convertValue方法。
vonvertValue方法的作用及方法参数说明
public Object convertValue(Map context, Object value, Class toType) {
···························
}
convertValue方法的作用是负责完成类型的转换,这种转换是双向的,把字符串转换成User实例时和把User实例转换成字符串均通过该方法实现,我们可以通过判断toType的类型来判断转换的方向,可参考下图:
convertValue方法中,有三个参数:
|- 第一个参数:context是类型转换环境的上下文
|- 第二个参数:value是需要转换的参数。随着转换方向的不同,value参数的值也是不一样的,当把字符串类型向User类型转换时,value是原始字符串数组;当需要把User类型向字符串类型转换时,value是User实例。
|- 第三个参数:toType是转换后的目标类型,可参考上图说明。
2 基于Struts2的自定义类型转换器
为了简化类型转换器的实现,Struts 2 提供了一个StrutsTypeConverter抽象类,这个抽象类是DefaultTypeConverter类的子类。StrutsTypeConverter类简化了类型转换器的实现,该类已经实现了DefaultTypeConverter的convertValue方法。实现该方法时,它将两个不同转换方向替换成不同方法----当需要把字符串转换成复合类型时,调用convertFromString抽象方法;当需要把复合类型转换成字符串时,调用convertToString抽象方法。转换方向和方法之间的对应关系见下图:
下面是基于StrutsTypeConverter实现的类型转换器代码:
package com.test.converter;
import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
import com.test.bean.User;
public class UserConverter2 extends StrutsTypeConverter{
@Override
public Object convertFromString(Map context,
String[] values , Class toClass) {
User user = new User();
String[] userValues = values[0].split(",");
user.setName(userValues[0]);
user.setPassword(userValues[1]);
return user;
}
@Override
public String convertToString(Map context, Object obj) {
User user = (User)obj;
return "<" + user.getName() + "," + user.getPassword() + ">";
}
}
仅仅为web应用提供类型转换器还不够,因为Struts 2依然不知道何时使用这些类型转换器,所以我们必须将类型转换器注册到Web应用中,Struts2才可以正常使用该类型转换器,通俗的说就是必须说明这个类型转换器是给谁用的。
Struts 2支持如下三种注册类型转换器的方式。
|- 注册局部类型转换器:局部类型转换器仅仅对某个Action的属性起作用。
|- 注册全局类型转换器:全局类型转换器对所有Action的特定类型的属性都会生效。
|- 使用JDK 1.5的注释来注册类型转换器:通过注释来注册类型转换器。
局部类型转换又分为三种:
a、普通实体bean的自定义类型转换
b、基于领域模型的自定义类型转换
c、基于模型驱动的自定义类型转换
在对应的Action的同级目录下新建Action名-conversion.properties(一定要与Action类名对应)
其内容为: 目标转换对象=转换器类(包名+类名),如下:
user=com.test.converter.UserConverter
基于普通实体bean的自定义类型转换可参考示例1。
在对应的Action的同级目录下新建Action名-conversion.properties(一定要与Action类名对应)文件,同时还需在引用模型同级目录下建properties文件取名规则为引用名- conversion.properties。如:
在User类中有个Point对象的引用,现在要基于Point来做自定义类型转换,这里Point与User之间的这层关系就叫做领域模型,在操作User时需要对Point进行自定义类型转换,这时就必须在User类的同级目录下新建User-conversion.properties文件,在文件中指明point对象需要用什么类来进行转换。
我们约定Point类的对象名就为point,而对应的转换类为com.test.convertor.PointConvertor,对应的Action类为PointUserAtion, PointUserAtion中有一个User类型的属性名为user
那么在PointUserAtion的同级目录中会存在一个名为PointUserAtion-conversion.properties的文件其内容为:
//因为在Action中引用的对象名为user而现在要处理的是user中的point属性,所以这里需要使用user.point来指明
user.point= com.dl.convertor.PointConvertor
同样在User类的同级目录会存在一个名为User-conversion.properties的文件内容为
//因为该文件只针对user,所以只需指明User中的point对象即可不需在添加user否则会出现预想不到的结果
point=com.test.convertor.PointConvertor
示例2:基于领域模型的自定义类型转换
待完善
示例3:基于模型驱动的自定义类型转换
待完善
全局类型转换器的使用规则是:
在classpath下新建文件xwork-conversion.properties(固定名称)
其内容为:目标转换对象=转换器类(包名+类名) 如:
com.test.bean.User=com.test.converter.UserConverter2
示例4:全局类型转换器
第一步:创建web project
第二步:写输入页面
input4.jsp,代码如下:
局部类型转换器
请输入用户名和密码(中间以逗号分隔)
第三步:写配置文件
写struts.xml配置文件,配置Action,主要代码如下:
output4.jsp
error.jsp
第四步:写Action
写相应的LoginAction4.java,其代码为:
package com.test.action;
import com.opensymphony.xwork2.ActionSupport;
import com.test.bean.User;
public class LoginAction4 extends ActionSupport {
private String result;
private User user;
private User friend;
//此处省略相应的set,get方法
public String execute() throws Exception {
if(getUser().getName().equals("hello")
&& getUser().getPassword().equals("world")) {
setResult("登录成功");
return SUCCESS;
} else {
setResult("登录失败!");
return ERROR;
}
}
}
第五步:写JavaBean
写实体类,User.java,其代码如下:
package com.test.bean;
public class User {
private String name;
private String password;
//此处省略相应的get,set方法
}
第六步:写自定义类型转换器
写自定义类型转换器,UserConverter4.java,其代码如下:
package com.test.converter;
import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
import com.test.bean.User;
public class UserConverter4 extends StrutsTypeConverter{
@Override
public Object convertFromString(Map context,
String[] values , Class toClass) {
User user = new User();
String[] userValues = values[0].split(",");
user.setName(userValues[0]);
user.setPassword(userValues[1]);
return user;
}
@Override
public String convertToString(Map context, Object obj) {
User user = (User)obj;
return "<" + user.getName() + "," + user.getPassword() + ">";
}
}
第七步:注册类型转换器
在src目录下注册全局类型转换器:xwork-conversion.properties,其内容为:
com.test.bean.User=com.test.converter.UserConverter
第八步:写输出界面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="s" uri="/struts-tags"%>
output1
转换成功
用户名名为:
用户密码为:
朋友名为:
朋友密码为:
第九步:运行检测
输入界面4 输出界面4
局部类型转换器是对指定Action的指定属性进行转换,不管该Action的该属性是数组也好,是List集合也罢,该转换器的转换方法对该属性只转换一次;假如某个Action有个List
全局类型转换器会对所有Action的特定类型进行转换,如果一个Action的某个属性是数组或集合属性,而数组或集合元素需要该转换器转换的方法,那么全局类型转换将不是对该集合属性整体进行转换,而是对该集合属性的每个元素进行转换。
局部类型转换器对指定Action的指定属性起作用,一个属性只调用convertValue()方法一次。全局类型转换器对所有Action的特定类型起作用,因此可能对一个属性多次调用convertValue()方法进行转换------当该属性是一个数组或集合时,该数组或集合中包含几个该类型的元素,那么就会调用vonvertValue方法几次。
可参考阅读:雪山飞鹄的Struts2自定义类型转换
轻量级Java EE企业应用实战(第3版)