0 摘要
1 基于OGNL的自定义类型转换
通过继承OGNL中的DefaultTypeConverter类,并重写其convertValue方法,实现自定义类型转换。我们先看一个示例,然后再作相关说明。
1.1 示例1
第一步:创建web project
创建web project并命名为localconverter。
第二步:写输入页面
写输入页面,input1.jsp,其主要代码如下:
<h3>局部类型转换器</h3>
请输入用户名和密码(中间以逗号分隔)
<form action="login" method="post" >
用户:<input type="text" name="user"><br/>
<input type="submit" value="转换">
<input type="submit" value="重填">
</form>
第三步:写配置文件
在struts.xml中,配置action,其主要代码如下:
<action name="login" class="com.test.action.LoginAction">
<result name="success" >output1.jsp</result>
<result name="error" >error.jsp</result>
</action>
第四步:写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"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>output1</title>
</head>
<body>
转换成功 <br/>
用户名名为:<s:property value="user.name"/>
用户密码为:<s:property value="user.password"/>
</body>
</html>
第九步:运行检测
输入界面1 输出界面1
1.2 关于convertValue方法
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() + ">";
}
}
3 注册类型转换器
仅仅为web应用提供类型转换器还不够,因为Struts 2依然不知道何时使用这些类型转换器,所以我们必须将类型转换器注册到Web应用中,Struts2才可以正常使用该类型转换器,通俗的说就是必须说明这个类型转换器是给谁用的。
Struts 2支持如下三种注册类型转换器的方式。
|- 注册局部类型转换器:局部类型转换器仅仅对某个Action的属性起作用。
|- 注册全局类型转换器:全局类型转换器对所有Action的特定类型的属性都会生效。
|- 使用JDK 1.5的注释来注册类型转换器:通过注释来注册类型转换器。
3.1 局部类型转化器
局部类型转换又分为三种:
a、普通实体bean的自定义类型转换
b、基于领域模型的自定义类型转换
c、基于模型驱动的自定义类型转换
普通实体bean的自定义类型转换:
在对应的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的文件其内容为:
同样在User类的同级目录会存在一个名为User-conversion.properties的文件内容为//因为在Action中引用的对象名为user而现在要处理的是user中的point属性,所以这里需要使用user.point来指明
user.point= com.dl.convertor.PointConvertor
//因为该文件只针对user,所以只需指明User中的point对象即可不需在添加user否则会出现预想不到的结果
point=com.test.convertor.PointConvertor
示例2:基于领域模型的自定义类型转换
待完善
基于模型驱动的自定义类型转换
示例3:基于模型驱动的自定义类型转换
待完善
3.2 全局类型转换器
全局类型转换器的使用规则是:
在classpath下新建文件xwork-conversion.properties(固定名称)
其内容为:目标转换对象=转换器类(包名+类名) 如:
com.test.bean.User=com.test.converter.UserConverter2
示例4:全局类型转换器
第一步:创建web project
第二步:写输入页面
input4.jsp,代码如下:
<body>
<h3>局部类型转换器</h3>
请输入用户名和密码(中间以逗号分隔)
<form action="login4" method="post" >
用户:<input type="text" name="user"><br/>
朋友:<input type="text" name="friend"><br/>
<input type="submit" value="转换">
<input type="submit" value="重填">
</form>
</body>
第三步:写配置文件
写struts.xml配置文件,配置Action,主要代码如下:
<action name="login4" class="com.test.action.LoginAction4">
<result name="success" >output4.jsp</result>
<result name="error" >error.jsp</result>
</action>
第四步:写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"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>output1</title>
</head>
<body>
转换成功 <br/>
用户名名为:<s:property value="user.name"/> <br>
用户密码为:<s:property value="user.password"/> <br>
朋友名为:<s:property value="friend.name"/> <br>
朋友密码为:<s:property value="friend.password"/>
</body>
</html>
第九步:运行检测
输入界面4 输出界面4
3.3 关于局部类型转换器和全局类型转换器的说明
局部类型转换器是对指定Action的指定属性进行转换,不管该Action的该属性是数组也好,是List集合也罢,该转换器的转换方法对该属性只转换一次;假如某个Action有个List<User>类型的属性Users,那么局部类型转换器将只调用一次convertValue方法,该方法把users请求参数一次性地转换为一个List<User>集合对象。
全局类型转换器会对所有Action的特定类型进行转换,如果一个Action的某个属性是数组或集合属性,而数组或集合元素需要该转换器转换的方法,那么全局类型转换将不是对该集合属性整体进行转换,而是对该集合属性的每个元素进行转换。
局部类型转换器对指定Action的指定属性起作用,一个属性只调用convertValue()方法一次。全局类型转换器对所有Action的特定类型起作用,因此可能对一个属性多次调用convertValue()方法进行转换------当该属性是一个数组或集合时,该数组或集合中包含几个该类型的元素,那么就会调用vonvertValue方法几次。
4 类型转换中Set集合的处理
5 类型转换中的错误处理
5.1 处理类型转换错误
5.2 处理集合属性的转换错误
6 源码与参考
轻量级Java EE企业应用实战(第3版)