通过继承OGNL中的DefaultTypeConverter类,并重写其convertValue方法,实现自定义类型转换。我们先看一个示例,然后再作相关说明。
第一步:创建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
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类的同级目录会存在一个名为User-conversion.properties的文件内容为user.point= com.dl.convertor.PointConvertor
//因为该文件只针对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,代码如下:
<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
局部类型转换器是对指定Action的指定属性进行转换,不管该Action的该属性是数组也好,是List集合也罢,该转换器的转换方法对该属性只转换一次;假如某个Action有个List<User>类型的属性Users,那么局部类型转换器将只调用一次convertValue方法,该方法把users请求参数一次性地转换为一个List<User>集合对象。
全局类型转换器会对所有Action的特定类型进行转换,如果一个Action的某个属性是数组或集合属性,而数组或集合元素需要该转换器转换的方法,那么全局类型转换将不是对该集合属性整体进行转换,而是对该集合属性的每个元素进行转换。
局部类型转换器对指定Action的指定属性起作用,一个属性只调用convertValue()方法一次。全局类型转换器对所有Action的特定类型起作用,因此可能对一个属性多次调用convertValue()方法进行转换------当该属性是一个数组或集合时,该数组或集合中包含几个该类型的元素,那么就会调用vonvertValue方法几次。
可参考阅读:雪山飞鹄的Struts2自定义类型转换
轻量级Java EE企业应用实战(第3版)