`
文鸯
  • 浏览: 305676 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

Struts使用BeanUtils提供的数据类型转换器

阅读更多

Struts版本——1.2.9

BeanUtils版本——1.7.0

 

 

在使用Struts开发的应用中,当请求转交到Action时,如果有关联这个Action的ActionForm,Struts会用请求参数填充ActionForm里相应的字段。

由于ActionForm字段的数据类型是在应用运行前写死的,请求参数是在应用运行后才能确定的,所以它们之间存在数据类型转换的问题。

Struts在用请求参数填充ActionForm字段时,不论它们数据类型是否一致,都会根据ActionForm字段的数据类型,使用相应的数据类型转换器将请求参数转换成和ActionForm字段相同的数据类型,然后调用字段对应的setter方法来填充字段。

Struts没有自己实现这些转换器,而是使用Apache Commons BeanUtils提供的一系列转换器,在org.apache.commons.beanutils.ConvertUtilsBean类的deregister()方法里,可以看到这些转换器的注册过程,代码如下:

  1. /**  
  2.  * Remove all registered {@link Converter}s, and re-establish the  
  3.  * standard Converters.  
  4.  */  
  5. public void deregister() {   
  6.   
  7.     boolean booleanArray[] = new boolean[0];   
  8.     byte byteArray[] = new byte[0];   
  9.     char charArray[] = new char[0];   
  10.     double doubleArray[] = new double[0];   
  11.     float floatArray[] = new float[0];   
  12.     int intArray[] = new int[0];   
  13.     long longArray[] = new long[0];   
  14.     short shortArray[] = new short[0];   
  15.     String stringArray[] = new String[0];   
  16.   
  17.     converters.clear();   
  18.     register(BigDecimal.classnew BigDecimalConverter());   
  19.     register(BigInteger.classnew BigIntegerConverter());   
  20.     register(Boolean.TYPE, new BooleanConverter(defaultBoolean));   
  21.     register(Boolean.class,  new BooleanConverter(defaultBoolean));   
  22.     register(booleanArray.getClass(),   
  23.                    new BooleanArrayConverter(booleanArray));   
  24.     register(Byte.TYPE, new ByteConverter(defaultByte));   
  25.     register(Byte.classnew ByteConverter(defaultByte));   
  26.     register(byteArray.getClass(),   
  27.                    new ByteArrayConverter(byteArray));   
  28.     register(Character.TYPE,   
  29.                    new CharacterConverter(defaultCharacter));   
  30.     register(Character.class,   
  31.                    new CharacterConverter(defaultCharacter));   
  32.     register(charArray.getClass(),   
  33.                    new CharacterArrayConverter(charArray));   
  34.     register(Class.classnew ClassConverter());   
  35.     register(Double.TYPE, new DoubleConverter(defaultDouble));   
  36.     register(Double.classnew DoubleConverter(defaultDouble));   
  37.     register(doubleArray.getClass(),   
  38.                    new DoubleArrayConverter(doubleArray));   
  39.     register(Float.TYPE, new FloatConverter(defaultFloat));   
  40.     register(Float.classnew FloatConverter(defaultFloat));   
  41.     register(floatArray.getClass(),   
  42.                    new FloatArrayConverter(floatArray));   
  43.     register(Integer.TYPE, new IntegerConverter(defaultInteger));   
  44.     register(Integer.classnew IntegerConverter(defaultInteger));   
  45.     register(intArray.getClass(),   
  46.                    new IntegerArrayConverter(intArray));   
  47.     register(Long.TYPE, new LongConverter(defaultLong));   
  48.     register(Long.classnew LongConverter(defaultLong));   
  49.     register(longArray.getClass(),   
  50.                    new LongArrayConverter(longArray));   
  51.     register(Short.TYPE, new ShortConverter(defaultShort));   
  52.     register(Short.classnew ShortConverter(defaultShort));   
  53.     register(shortArray.getClass(),   
  54.                    new ShortArrayConverter(shortArray));   
  55.     register(String.classnew StringConverter());   
  56.     register(stringArray.getClass(),   
  57.                    new StringArrayConverter(stringArray));   
  58.     register(Date.classnew SqlDateConverter());   
  59.     register(Time.classnew SqlTimeConverter());   
  60.     register(Timestamp.classnew SqlTimestampConverter());   
  61.     register(File.classnew FileConverter());   
  62.     register(URL.classnew URLConverter());   
  63.   
  64. }  

对数据的类型转换实际上就是调用相应转换器类的convert()方法,该方法在Converter接口中定义,上面的转换器类都直接或间接的实现了该接口,方法定义如下:

  1. /**  
  2.  * Convert the specified input object into an output object of the  
  3.  * specified type.  
  4.  *  
  5.  * @param type Data type to which this value should be converted  
  6.  * @param value The input value to be converted  
  7.  *  
  8.  * @exception ConversionException if conversion cannot be performed  
  9.  *  successfully  
  10.  */  
  11. public Object convert(Class type, Object value);  

 

根据各转换器类convert()方法代码类似程度,可以把它们分为3类。下面详细说说它们的convert()方法的实现。

 

第1类:StringConverter

StringConverter.java
  1. /**  
  2.  * Convert the specified input object into an output object of the  
  3.  * specified type.  
  4.  *  
  5.  * @param type Data type to which this value should be converted  
  6.  * @param value The input value to be converted  
  7.  *  
  8.  * @exception ConversionException if conversion cannot be performed  
  9.  *  successfully  
  10.  */  
  11. public Object convert(Class type, Object value) {   
  12.   
  13.     if (value == null) {   
  14.         return ((String) null);   
  15.     } else {   
  16.         return (value.toString());   
  17.     }   
  18.   
  19. }  

它的实现最简单,如果参数value为null,返回null;否则,返回value.toString()。

 

第2类:BigDecimalConverter、BigIntegerConverter、BooleanConverter、ByteConverter、CharacterConverter、DoubleConverter、FloatConverter、IntegerConverter、LongConverter、ShortConverter、SqlDateConverter、SqlTimeConverter、SqlTimestampConverter、FileConverter、URLConverter、ClassConverter

它们对convert()方法的实现很类似,可分为3步。下面仅列出IntegerConverter的convert()方法代码,以便给后面的纯文字叙述做个参考。

IntegerConverter.java
  1. /**  
  2.  * Convert the specified input object into an output object of the  
  3.  * specified type.  
  4.  *  
  5.  * @param type Data type to which this value should be converted  
  6.  * @param value The input value to be converted  
  7.  *  
  8.  * @exception ConversionException if conversion cannot be performed  
  9.  *  successfully  
  10.  */  
  11. public Object convert(Class type, Object value) {   
  12.   
  13.     if (value == null) {   
  14.         if (useDefault) {   
  15.             return (defaultValue);   
  16.         } else {   
  17.             throw new ConversionException("No value specified");   
  18.         }   
  19.     }   
  20.   
  21.     if (value instanceof Integer) {   
  22.         return (value);   
  23.     } else if(value instanceof Number) {   
  24.         return new Integer(((Number)value).intValue());   
  25.     }   
  26.   
  27.     try {   
  28.         return (new Integer(value.toString()));   
  29.     } catch (Exception e) {   
  30.         if (useDefault) {   
  31.             return (defaultValue);   
  32.         } else {   
  33.             throw new ConversionException(e);   
  34.         }   
  35.     }   
  36.   
  37. }  

第1步:如果参数value为null,根据类字段useDefault的值,要么返回类字段defaultValue的值,要么抛出ConversionException。

第2步:如果参数value instanceof目标类型,则返回value。

其中,ByteConverter、DoubleConverter、FloatConverter、IntegerConverter、LongConverter、ShortConverter还会判断如果参数value instanceof java.lang.Number,则把value转换成Number,调用Number相应的XXXValue()方法返回值。

第3步:如果参数value都不满足前面两步,则分别做如下的转换:

SqlDateConverter、SqlTimeConverter、SqlTimestampConverter调用XXX.valueOf(value.toString())来转换。其它除了BooleanConverter外的Converter使用new XXX(value.toString())来转换。XXX表示转换的目标类。BooleanConverter判断value.toString()的值,如果是"yes"、"y"、"true"、"on"、"1"之一,返回Boolean.TRUE;如果是"no"、"n"、"false"、"off"、"0"之一,返回Boolean.FALSE;如果都不是,按照第1步中如果参数value为null同样方式处理。

如果在这个第3步中抛出异常,按照第1步中如果参数value为null同样方式处理。

 

第3类:BooleanArrayConverter、ByteArrayConverter、CharacterArrayConverter、DoubleArrayConverter、FloatArrayConverter、IntegerArrayConverter、LongArrayConverter、ShortArrayConverter、StringArrayConverter

从名字就可看出,这些都是转换到数组类型的,这里要注意的是,并不是包装类数组,而是基本数据类型数组。它们都继承自org.apache.commons.beanutils.converters.AbstractArrayConverter,这是个抽象类,它实现了Converter接口。它们的convert()方法实现可分为4步。下面仅列出IntegerArrayConverter的convert()方法代码,以便给后面的纯文字叙述做个参考。

IntegerArrayConverter.java
  1. /**  
  2.  * Convert the specified input object into an output object of the  
  3.  * specified type.  
  4.  *  
  5.  * @param type Data type to which this value should be converted  
  6.  * @param value The input value to be converted  
  7.  *  
  8.  * @exception ConversionException if conversion cannot be performed  
  9.  *  successfully  
  10.  */  
  11. public Object convert(Class type, Object value) {   
  12.   
  13.     // Deal with a null value   
  14.     if (value == null) {   
  15.         if (useDefault) {   
  16.             return (defaultValue);   
  17.         } else {   
  18.             throw new ConversionException("No value specified");   
  19.         }   
  20.     }   
  21.   
  22.     // Deal with the no-conversion-needed case   
  23.     if (model.getClass() == value.getClass()) {   
  24.         return (value);   
  25.     }   
  26.   
  27.     // Deal with input value as a String array   
  28.     if (strings.getClass() == value.getClass()) {   
  29.         try {   
  30.             String values[] = (String[]) value;   
  31.             int results[] = new int[values.length];   
  32.             for (int i = 0; i < values.length; i++) {   
  33.                 results[i] = Integer.parseInt(values[i]);   
  34.             }   
  35.             return (results);   
  36.         } catch (Exception e) {   
  37.             if (useDefault) {   
  38.                 return (defaultValue);   
  39.             } else {   
  40.                 throw new ConversionException(value.toString(), e);   
  41.             }   
  42.         }   
  43.     }   
  44.   
  45.     // Parse the input value as a String into elements   
  46.     // and convert to the appropriate type   
  47.     try {   
  48.         List list = parseElements(value.toString());   
  49.         int results[] = new int[list.size()];   
  50.         for (int i = 0; i < results.length; i++) {   
  51.             results[i] = Integer.parseInt((String) list.get(i));   
  52.         }   
  53.         return (results);   
  54.     } catch (Exception e) {   
  55.         if (useDefault) {   
  56.             return (defaultValue);   
  57.         } else {   
  58.             throw new ConversionException(value.toString(), e);   
  59.         }   
  60.     }   
  61.   
  62. }  

第1步:和第2类中的第1步一样。

第2步:如果参数value的类型和转换器类的model字段的类型相同,直接返回value。model字段的类型也就是该转换器类对应的目标类类型,比如LongArrayConverter里的model是long[]。

第3步:除StringArrayConverter外,如果参数value的类型和AbstractArrayConverter类的strings字段的类型相同,也就是String[],则把value转换成String[]类型,循环对其中的每个String做如下转换:

ByteArrayConverter、DoubleArrayConverter、FloatArrayConverter、IntegerArrayConverter、LongArrayConverter、ShortArrayConverter使用对应包装类的parseXXX()方法;BooleanArrayConverter同第2类中第3步里BooleanConverter的处理方式;CharacterArrayConverter使用String.charAt(0)。

对于StringArrayConverter,第2步就做了这个判断了。所以第3步它判断的是如果参数value的类型和它的ints字段的类型相同,也就是int[],则value转换成int[]类型,循环对其中的每个int使用Integer.toString(int)转换。

返回转换后的新数组。

第4步:如果参数value都不满足上面几步的条件,则以value.toString()做为参数,调用AbstractArrayConverter的parseElements方法,得到一个List,其中的每个元素都是String。然后除StringArrayConverter外的其它Converter,按照与第3步中处理String[]的相同方式来处理List。StringArrayConverter则更简单,直接把List里的元素转到数组里返回。

下面是parseElements()方法的代码:

AbstractArrayConverter.java
  1. /**  
  2.  * Parse an incoming String of the form similar to an array initializer  
  3.  * in the Java language into a List individual Strings  
  4.  * for each element, according to the following rules. 
  5.  * 
  6.  * The string must have matching '{' and '}' delimiters around  
  7.  * a comma-delimited list of values.  
  8.  * Whitespace before and after each element is stripped.

  9.  * If an element is itself delimited by matching single or double

  10.  * quotes, the usual rules for interpreting a quoted String apply.  

  11.  * @param svalue String value to be parsed  
  12.  *  
  13.  * @exception ConversionException if the syntax of svalue  
  14.  *  is not syntactically valid  
  15.  * @exception NullPointerException if svalue  
  16.  *  is null  
  17.  */  
  18. protected List parseElements(String svalue) {   
  19.   
  20.     // Validate the passed argument   
  21.     if (svalue == null) {   
  22.         throw new NullPointerException();   
  23.     }   
  24.   
  25.     // Trim any matching '{' and '}' delimiters   
  26.     svalue = svalue.trim();   
  27.     if (svalue.startsWith("{") && svalue.endsWith("}")) {   
  28.         svalue = svalue.substring(1, svalue.length() - 1);   
  29.     }   
  30.   
  31.     try {   
  32.   
  33.         // Set up a StreamTokenizer on the characters in this String   
  34.         StreamTokenizer st =   
  35.             new StreamTokenizer(new StringReader(svalue));   
  36.         st.whitespaceChars(',',','); // Commas are delimiters   
  37.         st.ordinaryChars('0', '9');  // Needed to turn off numeric flag   
  38.         st.ordinaryChars('.''.');   
  39.         st.ordinaryChars('-', '-');   
  40.         st.wordChars('0', '9');      // Needed to make part of tokens   
  41.         st.wordChars('.''.');   
  42.         st.wordChars('-', '-');   
  43.   
  44.         // Split comma-delimited tokens into a List   
  45.         ArrayList list = new ArrayList();   
  46.         while (true) {   
  47.             int ttype = st.nextToken();   
  48.             if ((ttype == StreamTokenizer.TT_WORD) ||   
  49.                 (ttype > 0)) {   
  50.                 list.add(st.sval);   
  51.             } else if (ttype == StreamTokenizer.TT_EOF) {   
  52.                 break;   
  53.             } else {   
  54.                 throw new ConversionException   
  55.                     ("Encountered token of type " + ttype);   
  56.             }   
  57.         }   
  58.   
  59.         // Return the completed list   
  60.         return (list);   
  61.   
  62.     } catch (IOException e) {   
  63.   
  64.         throw new ConversionException(e);   
  65.   
  66.     }   
  67.   
  68.   
  69.   
  70. }  

 方法注释里指出,它要求参数svalue是形如“{abc,def,ghi}”的字符串,使用逗号对svalue进行分隔,将分隔后的元素放到List里返回。

在这段代码的try块里,首先构造一个java.io.StreamTokenizer,设置逗号做为分隔符,再将0到9、负号、小数点这些字符设置为普通字符,因为默认的StreamTokenizer会将这些这些字符组成的字符串转换成double类型,而在这里不需要这个功能。然后使用StreamTokenizer的方式分隔svalue,将分隔的元素放到List里返回。

分享到:
评论

相关推荐

    Struts自定义类型转换器

    Struts框架为了更好地处理这种类型转换的需求,提供了自定义类型转换器的功能,使得开发者能够更加灵活地控制数据类型转换的过程。本文主要介绍Struts1和Struts2中的自定义类型转换器,并探讨其实现机制。 #### 二...

    Struts相关资料\beanutils-1.5.rar

    在Struts 2中,你可以使用Struts的类型转换器或者直接利用OGNL(Object-Graph Navigation Language)来执行类型转换。OGNL不仅支持基本类型的转换,还支持更复杂的对象导航和表达式语言,这使得在处理复杂数据类型和...

    struts1和struts2区别

    - **Struts2**:使用OGNL进行类型转换,提供更灵活的配置和基本及常见类型的转换器。 9. **校验**: - **Struts1**:校验可以在ActionForm的validate方法中完成,或使用Commons Validator扩展,对子对象的校验...

    BeanUtils教程

    3. **数据类型转换**:利用 `org.apache.commons.beanutils.converters` 包中的转换器可以方便地进行数据类型的转换。 这些功能极大地简化了 Java Bean 的操作,提高了开发效率。 #### 五、总结 通过本文的学习,...

    struts1和struts2的区别

    Struts2则使用OGNL进行类型转换,提供更强大的内置转换器。 最后,在验证功能上,Struts1支持在ActionForm的validate方法中进行手动验证,或者使用Commons Validator扩展。Struts2提供了更高级的验证机制,可以通过...

    commons-beanutils-1.9.2下载

    2. **类型转换**:库内置了多种类型的转换器,例如`convert()`方法,它可以自动将值转换为指定的目标类型,这对于数据绑定和验证非常有用。 3. **复制属性**:`copyProperties()`方法可以将一个对象的所有属性复制...

    Struts1和Struts2的区别和对比

    在类型转换上,Struts1的ActionForm属性通常是String类型,依赖于Commons-Beanutils进行转换,转换器不可配置。Struts2则利用OGNL进行转换,内置了对基本类型和常见对象的转换。 最后,在数据校验方面,Struts1支持...

    JSTL_BeanUtils_Struts相关资料

    它简化了JavaBean属性的访问和设置,包括属性的自动类型转换。BeanUtils的一个主要功能是`BeanUtils.copyProperties()`,可以将一个对象的所有属性值复制到另一个对象上,这在数据绑定和对象复制场景中非常有用。...

    struts1和struts2的区别(详细)

    - **Struts1**: Struts1使用`Commons-Beanutils`库来进行类型转换,但对于复杂的数据类型转换来说,这种方式并不十分方便。 - **Struts2**: Struts2采用了OGNL表达式语言进行数据绑定和类型转换,这使得Struts2能够...

    struts1与struts2本质区别

    - **Struts1**:使用Commons-Beanutils进行类型转换,每个类一个转换器,转换器不可配置。 - **Struts2**:使用OGNL进行类型转换,支持基本数据类型和常用对象之间的转换,并且具有更高的灵活性。 #### 九、数据...

    Struts1与Struts2本质区别

    - **Struts 2**:使用OGNL进行类型转换,支持更多的数据类型转换,提高了灵活性。 #### 9. 数据校验的对比 - **Struts 1**:支持在`ActionForm`中重写`validate`方法进行手动校验,也可以整合`Commons-validator`...

    commons-beanutils

    1. **错误处理**:虽然BeanUtils提供了便利,但使用时应注意异常处理,例如属性不存在或类型转换失败等情况。 2. **性能考虑**:频繁使用反射可能会对性能造成一定影响,因此在性能敏感的场景下,可以考虑缓存`...

    struts2 与 struts1的区别

    - **Struts2** 则使用OGNL来进行类型转换,并且为常见的对象类型提供了内置的转换器。此外,Struts2的校验机制更加完善,支持链式校验子属性,使得校验规则更加灵活和精细。 #### 七、Action执行控制 - **Struts1*...

    转:struts1与struts2的区别

    - **Struts2**: 使用OGNL进行类型转换,为基本和常用对象提供了转换器。Struts2的类型转换机制更为灵活且易于配置。 #### 9. 数据校验机制 - **Struts1**: 支持在`ActionForm`的`validate`方法中手动校验数据,...

    commons-beanutils-1.8.3

    - **类型转换**:库内含了自动类型转换机制,使得不同类型的值可以安全地赋给JavaBean的属性,避免了常见的类型转换异常。 - **复制属性**:`copyProperties()`方法可以方便地将一个JavaBean的所有属性复制到另一...

    struts2新特性预览

    Struts1的ActionForm属性通常是String类型,依赖于Commons-Beanutils进行类型转换,转换器固定且无法配置。Struts2则使用OGNL进行类型转换,提供了更灵活的基本和复杂对象转换。 9. **验证机制**: Struts1支持在...

    Struts2与struts1不同

    在类型转换上,Struts1的ActionForm属性多为String类型,通过Commons-Beanutils进行类型转换,转换器不可配置。而Struts2利用OGNL进行类型转换,提供了更多内置的转换器,并支持自定义转换。 最后,对于数据验证,...

    struts1与struts2的区别

    - **Struts2**:Struts2使用OGNL进行类型转换,并提供了一组预定义的转换器,支持更丰富的类型转换需求。 #### 校验 - **Struts1**:Struts1支持在`ActionForm`的`validate`方法中进行手动校验,也可以通过Commons ...

Global site tag (gtag.js) - Google Analytics