Struts2类型转换详解

jopen 11年前

一、类型转换的意义

对于一个智能的MVC框架而言,不可避免的需要实现类型转换.因为B/S(浏览器/服务器)结构应用的请求参数是通过浏览器发送到服务器的,这些参数不可能有丰富的数据类型,因此必须在服务器端完成数据类型的转换

 

MVC框架是一个表现层解决方案,理应提供类型转换的支持,Struts2提供了功能非常强大的类型转换支持.

 

二、表现层数据的处理

1、对于web应用而言,表现层主要用于与用户交互,包括收集用户输入数据,向用户呈现服务器的状态。因此表现层的数据的流向主要有两个方向:输入数据和输出数据。


2、对于输入数据:则需要完成由字符串数据向多种类型数据的转化。程序通常无法自动完成,需要在代码中手动转化


3、对于输出数据:不管是java或是jsp都支持多种数据类型的直接输出。


4、表现层另外一个数据处理是:数据校验,分为客户校验和服务器端校验.后边会重点讲解

三、类型转换

1、HTTP参数都是字符串类型。 保存的数据可能是字符串、数字、布尔、日期时间等或者JavaBean类型。 手工的类型转换,比如将字符串转换为日期,通过: 通过request.getParameter方法获取字符串; 检查是否为空; 通过DateFormat.parse方法将字符串转换为Date对象

2、Struts2类型转换


Struts2内置的类型转换
String和boolean 完成字符串与布尔值之间的转换
String和char  往常字符串与字符之间的转换
String和int、Integer 完成字符串与整型之间的转换
String和Long 完成字符串与长整型值之间的转换
String和double、Double 完成字符串与双精度浮点值的转换
String和Float 完成字符串和单精度浮点之间的转换
String和Date 完成字符串和日期类型之间的转换,日期格式使用格式用户请求所在Locale的SHORT格式
String和数组 在默认的情况,数组元素是字符串,如果用户定义类型转换器,也可以是其它复合数据类型
String和Map、List

 

 

Struts2内置的类型转换
String和boolean 完成字符串与布尔值之间的转换
String和char  往常字符串与字符之间的转换
String和int、Integer 完成字符串与整型之间的转换
String和Long 完成字符串与长整型值之间的转换
String和double、Double 完成字符串与双精度浮点值的转换
String和Float 完成字符串和单精度浮点之间的转换
String和Date 完成字符串和日期类型之间的转换,日期格式使用格式用户请求所在Locale的SHORT格式
String和数组 在默认的情况,数组元素是字符串,如果用户定义类型转换器,也可以是其它复合数据类型
String和Map、List

 

3、内置类型转换

Struts2类型转换详解

 

Struts2类型转换详解

Struts2类型转换详解

4、Struts类型转换的API

Struts2的类型转换器实际上是基于OGNL实现的,在OGNL项目中有一个ognl.TypeConverter接口,这个接口就是实现类型转换器必须实现的接口。该接口定义如下:

 

public interface TypeConverter {
     public Object convertValue(Map arg0, Object arg1, Member arg2, String arg3,
          Object arg4, Class arg5) {
              return null;
}

实现类型转换器必须实现上面的TypeConverter,不过上面的接口里的方法过于复杂,所以OGNL项目还提供了一个该接口实现类:ognl.DefaultTypeConverter,通过继承该类实现自己类型转换器.该类定义如下:


    public class DefaultTypeConverter extends Object implements TypeConverter{
             public Object convertValue(Map context, Object value, Class toType) {
              }
             ……//其他的方法
     }

ConvertValue方法的作用
该方法完成类型转换,不过这种类型转换是双向的,当需要把字符串转化对象实例时,通过该方法实现,当把对象实例转换成字符串时也通过该方法实现。这种转换是通过toType参数类型是需要转换的目标类型。所以可以根据toType参数来判断转换方向。
ConvertValue方法参数和返回意义
第一个参数:context是类型转换环境的上下文
第二个参数:value是需要转换的参数,根据转换方向的不同value参数的值也是不一样的。
第三个参数:toType是转换后的目标类型
该方法的返回值是类型转换后的值。该值的类型也会随着转换的方向的改变而改变。由此可见转换的convertValue方法接受需要转换的值,需要转换的目标类型为参数,然后返回转换后的目标值
Value为什么是一个字符串数组?
对于DefaultTypeConverter转换器而言,它必须考虑到最通用的情形,因此他把所有请求参数都视为字符串数组而不是字符串。相当于getParameterValues()获取的参数值

 

四、类型转换器的实现

1、第一步注册页面

Struts2类型转换详解

2、第二步骤:实现User封装类

Struts2类型转换详解

3、第三步骤:实现Action类
Struts2类型转换详解

Struts2类型转换详解

5、

第五步骤:实现类型转换器的注册,注册方式有以下三种:


 1、注册局部类型转换器:局部类型转换器仅仅对某个Action的属性其作用
 2、注册全局类型转换器:全局类型转换器对所有Action的特定属性都会生效
 3、使用JDK1.5的注释来注册类型转换器:通过注册方式来生成类型转换器

 

6、局部类型转换器注册
注册文件名格式:ActionName-conversion.properties:ActionName是需要转换器生效的Action的类名,后面的-conversion.properties字符串是固定部分
以上文件时典型的properties文件,文件有key-value对组成.文件内容为:propertyName=类型转换器类
下面是UserAction-conversion.properties文件的内容:
#指定UserAction中的user属性需要使用redarmy.user.UserConverter类完成类型转换
user=redarmy.user.UserConverter
注意:以上properties文件一定要与UserAction在同一个包中
即上述案例可采用上面的方式实现局部类型转换

7、

全局类型转换器
注册名的文件格式:xwork-conversion.properties文件该文件也是properties文件,其内容也是由”复合类型=对应的类型转换器类”项组成的。
以下是xwork-conversion.properties文件内容:
     #指定所有redarmy.user.User类的类型转换器为redarmy.user.UserConverter
     redarmy.user.User=redarmy.user.UserConverter
     注意:xwork-conversion.properties文件必须为class文件夹下即在src下面创建

 

 

五、Struts2自定义类型转换

 在Struts2中提供了StrutsTypeConverter类来简化自定义类型转换的设计,这个类有两个抽象方法需要实现:

     (1) public Object convertFromString(Map context,  String[] values,  Class toClass) ;
          用于String类型数据转成自定义类型的处理方法
          参数:
             context  --- 与Action有关的上下文信息
             values   --- 从请求中获取的参数值
             toClass --- 要转换的目标类型

     (2)  public String convertToString(Map context, Object obj) ;
    用于自定义类型转换成String
      参数:
         context  --- 与Action有关的上下文信息
         obj --- 自定义类型对象

实例分析:一个日期类型转换的设计和配置

(1) 设计MyDateTypeConverter,继承StrutsTypeConverter,覆盖其中的两个方法,参考代码如下:
public Object convertFromString(Map context, String[] values, Class toClass) {
  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  try{
   Date v = sdf.parse(values[0]);
   return v;
  }catch(Exception e){
   e.printStackTrace();
   return new Date();
  }
    
 }


 public String convertToString(Map context, Object obj) {
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
   Date v = (Date)obj;
   return sdf.format(v);
 }
虽然Struts2默认可支持String和Date的转换,但仅支持短格式和本地化有关日期格式转换,不一定符合自己的需要,我们需要实现自己的类型转换。
(2) 为UserInfo类增加一个birthday属性,其类型为java.util.Date
public class UserInfo {
 private Integer id;
 private String name;
 private String password;
 private Date birthday;
     ...
}

(3)为UserInfo这个组件配置该类型转换器
首先,以UserInfo组件的类名为基础创建一个特性文件,文件命名格式为类名-conversion.properties
  
     比如UserInfo-conversion.properties

该文件必须和UserInfo组件在同一个包下。

该特性文件内容格式如下:
 birthday=demo.converter.MyDateTypeConverter
 说明:
birthday 为UserInfo组件中java.util.Date类型的属性名
demo.converter.MyDateTypeConverter为自定义转换实现类

Strus2框架为我们考虑到这一点,提供了一种简单的处理方式。

将类型转换器配置为全局级别,只需编写一个名为xwork-conversion.properties的特性文件,该文件必须位于/WEB-INF/classes目录下,内容如下:
            java.util.Date=demo.converter.MyDateTypeConverter

 

六、自定义类型转换器

java.util.Date类型的属性可以接收格式为2009-07-20的请求参数值。但如果我们需要接收格式为20091221的请求参数,我们必须定义类型转换器,否则struts2无法自动完成类型转换。

import java.util.Date;
public class HelloWorldAction {
 private Date createtime;

 public Date getCreatetime() {
  return createtime;
 }

 public void setCreatetime(Date createtime) {
  this.createtime = createtime;
 }
}

 

public class DateConverter extends DefaultTypeConverter {
                @Override  public Object convertValue(Map context, Object value, Class toType) {
 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
 try {
  if(toType == Date.class){//当字符串向Date类型转换时
   String[] params = (String[]) value;// Request.getParameterValues()
   return dateFormat.parse(params[0]);
  }else if(toType == String.class){//当Date转换成字符串时
   Date date = (Date) value;
   return dateFormat.format(date);
  }
 } catch (ParseException e) {}
 return null;
 }
}
将上面的类型转换器注册为局部类型转换器:
在Action类所在的包下放置ActionClassName-conversion.properties文件,ActionClassName是 Action的类名,后面的-conversion.properties是固定写法,对于本例而言,文件的名称应为HelloWorldAction- conversion.properties 。在properties文件中的内容为:
属性名称=类型转换器的全类名
对于本例而言, HelloWorldAction-conversion.properties文件中的内容为:
createtime= cn.csdn.conversion.DateConverter

将上面的类型转换器注册为全局类型转换器:
在WEB-INF/classes下放置xwork-conversion.properties文件 。在properties文件中的内容为:
待转换的类型=类型转换器的全类名
对于本例而言, xwork-conversion.properties文件中的内容为:
java.util.Date= cn.csdn.conversion.DateConverter

java.util.Date类型的属性可以接收格式为2009-07-20的请求参数值。但如果我们需要接收格式为20091221的请求参数,我们必须定义类型转换器,否则struts2无法自动完成类型转换。

import java.util.Date;
public class HelloWorldAction {
 private Date createtime;

 public Date getCreatetime() {
  return createtime;
 }

 public void setCreatetime(Date createtime) {
  this.createtime = createtime;
 }
}

 

public class DateConverter extends DefaultTypeConverter {
                @Override  public Object convertValue(Map context, Object value, Class toType) {
 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
 try {
  if(toType == Date.class){//当字符串向Date类型转换时
   String[] params = (String[]) value;// Request.getParameterValues()
   return dateFormat.parse(params[0]);
  }else if(toType == String.class){//当Date转换成字符串时
   Date date = (Date) value;
   return dateFormat.format(date);
  }
 } catch (ParseException e) {}
 return null;
 }
}
将上面的类型转换器注册为局部类型转换器:
在Action类所在的包下放置ActionClassName-conversion.properties文件,ActionClassName是 Action的类名,后面的-conversion.properties是固定写法,对于本例而言,文件的名称应为HelloWorldAction- conversion.properties 。在properties文件中的内容为:
属性名称=类型转换器的全类名
对于本例而言, HelloWorldAction-conversion.properties文件中的内容为:
createtime= cn.csdn.conversion.DateConverter

将上面的类型转换器注册为全局类型转换器:
在WEB-INF/classes下放置xwork-conversion.properties文件 。在properties文件中的内容为:
待转换的类型=类型转换器的全类名
对于本例而言, xwork-conversion.properties文件中的内容为:
java.util.Date= cn.csdnconversion.DateConverter