你的位置:首页 > Java教程

[Java教程]Struts2学习笔记(七)——类型转换


1、自动类型转换

Struts2内部提供大量类型转换器,用来完成数据类型转换问题:

  • String和boolean、Boolean:完成字符串与布尔值之间的转换
  • String和char、Character:往常字符串与字符之间的转换
  • String和int、Integer:完成字符串与整型之间的转换
  • String和long、Long:完成字符串与长整型值之间的转换
  • String和double、Double:完成字符串与双精度浮点值的转换
  • String和float、Float:完成字符串和单精度浮点之间的转换
  • String和Date:完成字符串和日期类型之间的转换,可以接收yyyy-MM-dd格式字符串
  • String和数组:可以将多个同名参数,转换到数组中
  • String和Map、List:支持将数据保存到List或者Map集合

自动类型转换例子:

表单信息:

1 <form action="${pageContext.servletContext.contextPath}/converterAction.action">2   name:<input type="text" name="name"><br>3   password:<input type="password" name="password"><br>4   age:<input type="text" name="age"><br>5   birthday:<input type="text" name="birthday"><br>6   hobby:<input name="hobby" type="checkbox" value="music">music7     <input name="hobby" type="checkbox" value="movie">movie<br>8   <input type="submit" value="提交">9 </form>

Action类:

 1 public class ConverterAction extends ActionSupport { 2   private String name; 3   private String password; 4   private int age; 5   private Date birthday; 6   private String[] hobby; 7    8   public String getName() { 9     return name;10   }11   public void setName(String name) {12     this.name = name;13   }14   public String getPassword() {15     return password;16   }17   public void setPassword(String password) {18     this.password = password;19   }20   public int getAge() {21     return age;22   }23   public void setAge(int age) {24     this.age = age;25   }26   public Date getBirthday() {27     return birthday;28   }29   public void setBirthday(Date birthday) {30     this.birthday = birthday;31   }32   public String[] getHobby() {33     return hobby;34   }35   public void setHobby(String[] hobby) {36     this.hobby = hobby;37   }38   39   @Override40   public String execute() throws Exception {41     System.out.println("name: " + name);42     System.out.println("password: " + password);43     System.out.println("age: " + age);44     System.out.println("birthday: " + birthday);45     System.out.print("hobby: ");46     for (int i = 0; i < hobby.length; i++) {47       System.out.print(hobby[i]);48       if (i != hobby.length - 1) {49         System.out.print(", ");50       }51     }52     return SUCCESS;53   }54 }

前台输入信息:

后台显示信息:

2、自定义类型转换

  1)基于OGNL的类型转换器

  Struts2的类型转换器实际上是基于OGNL实现的,都需要实现一个TypeConverter接口,该接口位于ognl.jar包内。该接口定义了一个convertValue()方法,实现该接口的类型转换器实现类都需要重写该方法来进行类型转换。

1 public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType);

  由于TypeConverter接口的convertValue()方法过于复杂,OGNL还提供了一个实现TypeConverter接口的类DefaultTypeConverter,开发者只要继承该类,就可以开发类型转换器的实现类。DefaultTypeConverter类的子类需要重写convertValue()方法,来实现字符串类型与复合类型之间的双向转换,convertValue()方法有三个参数:Map context:该参数为类型转换环境的上下文内容;Object value:该参数为需要转换的参数,是一个字符串数组;Class toType:该参数指的是转换目标的类型。

  在Struts2中并没有直接使用ognl.DefaultTypeConverter实现类,甚至都没有使用ognl.TypeConverter接口,而是自己定义了一个与ognl.TypeConverter接口一样的TypeConverter接口,该接口位于com.opensymphony.xwork2.conversion包下,其名称和接口函数定义完全相同。Struts2自行定义TypeConverter接口的目的在于对外屏蔽类型转换的实现细节,从而能够将Struts2对TypeConverter的扩展实现纳入到Struts2的容器中进行管理,从而方便对OGNL原始的TypeConverter接口进行扩展并支持更加广泛的类型转换逻辑。

  在Struts2的com.opensymphony.xwork2.conversion包下DefaultTypeConverter实现类有3个convertValue方法:

所以我们在继承com.opensymphony.xwork2.conversion包下DefaultTypeConverter实现类的时候可以直接重写convertValue(Object value, Class toType)方法即可。

无论是继承ongl包下的DefaultTypeConverter还是继承com.opensymphony.xwork2.conversion包下DefaultTypeConverter,在自定义类型转换的时候,实现方式都一样。

  2)基于Struts2的类型转换器

  Struts2框架提供了一个类型转换器的StrutsTypeConverter抽象类,可以继承该类来开发自定义的类型转换器实现类。 该抽象类实际上继承了DefaultTypeConverter类,在该类的基础上进行了简化。StrutsTypeConverter类中提供了两个抽象方法,分别实现"form字符串参数-Struts复合类型"之间的双向转换。

3、注册类型转换器

在Struts2框架中使用自定义类型转换器需要注册,这样Struts2框架在处理用户请求的时候才知道使用哪个类型转换器进行转换。Struts2有两种方式注册类型转换器:

 1)注册局部类型转换器

  局部类型转换器仅仅对某个Action的属性其作用,注册局部类型转换器需要建立一个命名规则为ActionName-conversion.properties的属性文件,该属性文件保存在与Action类文件相同的目录下。ActionName就是使用类型转换器的Action类的类名,而-conversion.properties是固定的格式。该文件是一个标准的属性文件,内容为标准的Key-Value格式,该键值对定义如下:

1 <!--propertyName为要进行转换的属性名-->2 propertyName=类型转换器

如果在model中有两个类User和Product,它们都有Date类型属性,都需要在页面上输入,但是它们格式不一样,例如:

  User birthday 格式:yyyy/MM/dd

  Product producttime 格式:yyyy-MM-dd

如果遇到这种情况,可以在model所在的包下创建注册的properties文件,名称的命名规则为modelname-conversion.properties,该属性文件的内容和上面的一样:

1 <!--propertyName为要进行转换的属性名-->2 propertyName=类型转换器

 2)注册全局类型转换器

  全局类型转换器对所有Action的特定属性都会生效,注册一个全局类型转换器,需要建立一个xwork-conversion.properties属性文件,该文件需要保存在class路径的根目录下,如WEB-INF/classes。该文件的内容为"复合类型-对应的类型转换器",其中复合类型就是Action中需要进行类型转换的属性所属于的类型,对应的类型转换器就是转换该复合类型的对应转换器,比如要对Date类型的属性进行转换:

java.util.Date=com.sunny.converter.DateConverter

4、类型转换器的实现

在类型转换器的实现例子中自定义类型转换器继承的是DefaultTypeConverter,注册局部类型转换器。

表单信息:

1 <form action="${pageContext.servletContext.contextPath}/converterAction.action">2   name:<input type="text" name="name"><br>3   password:<input type="password" name="password"><br>4   age:<input type="text" name="age"><br>5   birthday:<input type="text" name="birthday"><br>6   hobby:<input name="hobby" type="checkbox" value="music">music7     <input name="hobby" type="checkbox" value="movie">movie<br>8   <input type="submit" value="提交">9 </form>

自定义类型转换器类:

 1 public class DateConverter extends DefaultTypeConverter { 2   @Override 3   public Object convertValue(Object value, Class toType) { 4     if (value == null || toType == null) { 5       return false; 6     } 7      8     if (toType != Date.class) { 9       return false;10     }11     12     /*13      * 对于DefaultTypeConverter转换器而言,它必须考虑到最通用的情形,14      * 因此他把所有请求参数都视为字符串数组而不是字符串。15     */16     if (value instanceof String[]) {17       String str[] = (String[])value;18       if (str[0] != null && str[0].length() > 0) {19         SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");20         try {21           //把请求参数转换成特定格式的date类22           return sdf.parse(str[0]);23         } catch (ParseException e) {24           /*25            * 在struts2框架里,自定义的类型转换器,26            * 如果我们不手动抛出异常,struts2框架只捕获异常,但是并不抛出。27            * 所以框架就会认为类型转换器转换成功,转向成功页面。28           */29           throw new RuntimeException(e);30         }31       }32     }33     return new Date();34   }35 }

注册局部类型转换器,对Date类型的birthday进行转换,接收yyyy/MM/dd类型字符串:

1 birthday=com.sunny.converter.DateConverter

Action类:

 1 public class ConverterAction extends ActionSupport { 2   private String name; 3   private String password; 4   private int age; 5   private Date birthday; 6   private String[] hobby; 7    8   public String getName() { 9     return name;10   }11   public void setName(String name) {12     this.name = name;13   }14   public String getPassword() {15     return password;16   }17   public void setPassword(String password) {18     this.password = password;19   }20   public int getAge() {21     return age;22   }23   public void setAge(int age) {24     this.age = age;25   }26   public Date getBirthday() {27     return birthday;28   }29   public void setBirthday(Date birthday) {30     this.birthday = birthday;31   }32   public String[] getHobby() {33     return hobby;34   }35   public void setHobby(String[] hobby) {36     this.hobby = hobby;37   }38   39   @Override40   public String execute() throws Exception {41     System.out.println("name: " + name);42     System.out.println("password: " + password);43     System.out.println("age: " + age);44     System.out.println("birthday: " + birthday);45     System.out.print("hobby: ");46     for (int i = 0; i < hobby.length; i++) {47       System.out.print(hobby[i]);48       if (i != hobby.length - 1) {49         System.out.print(", ");50       }51     }52     return SUCCESS;53   }54 }

前台输入信息:

后台显示信息:

注意事项:

  • 在进行自定义类型转换时,如果转换错误,我们不手动抛出异常,struts2框架只捕获异常,并不抛出,框架就会认为转换成功,转向成功页面,所以一定要手动抛出异常。
  • 不管是自动类型转换还是自定义类型转换,如果类型转换错误,会跳转到input视图,如果在struts.