Struts使用BeanUtils提供的数据类型转换器
2010-07-12 16:57
302 查看
在使用Struts开发的应用中,当请求转交到Action时,如果有关联这个Action的ActionForm,Struts会用请求参数填充ActionForm里相应的字段。
由于ActionForm字段的数据类型是在应用运行前写死的,请求参数是在应用运行后才能确定的,所以它们之间存在数据类型转换的问题。
Struts在用请求参数填充ActionForm字段时,不论它们数据类型是否一致,都会根据ActionForm字段的数据类型,使用相应的数据类型转换器将请求参数转换成和ActionForm字段相同的数据类型,然后调用字段对应的setter方法来填充字段。
Struts没有自己实现这些转换器,而是使用Apache Commons BeanUtils提供的一系列转换器,在org.apache.commons.beanutils.ConvertUtilsBean类的deregister()方法里,可以看到这些转换器的注册过程,代码如下:
对数据的类型转换实际上就是调用相应转换器类的convert()方法,该方法在Converter接口中定
义,上面的转换器类都直接或间接的实现了该接口,方法定义如下:
根据各转换器类convert()方法代码类似程度,可以把它们分为3类。下面详细说说它们的convert()方法的实现。
第1类:StringConverter
StringConverter.java
它的实现最简单,如果参数value为null,返回null;否则,返回value.toString()。
第2类:BigDecimalConverter、BigIntegerConverter、BooleanConverter、ByteConverter、CharacterConverter、DoubleConverter、FloatCon
verter、IntegerConverter、LongConverter、ShortConverter、SqlDateConverter、SqlTimeConverter、SqlTimestampConverter、FileConvert
er、URLConverter、ClassConverter
它们对convert()方法的实现很类似,可分为3步。下面仅列出IntegerConverter的convert()方法代码,以便给后面的纯文字叙述做个参考。
IntegerConverter.java
第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外的Co
nverter使用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、IntegerAr
rayConverter、LongArrayConverter、ShortArrayConverter、StringArrayConverter
从名字就可看出,这些都是转换到数组类型的,这里要注意的是,并不是包装类数组,而是基本数据类型数组。它们都继承自org.apache.commons.beanutils.
converters.AbstractArrayConverter,这是个抽象类,它实现了Converter接口。它们的convert()方法实现可分为4步。下面仅列出IntegerArrayConverter
的convert()方法代码,以便给后面的纯文字叙述做个参考。
IntegerArrayConverter.
java
第1步:和第2类中的第1步一样。
第2步:如果参数value的类型和转换器类的model字段的类型相同,直接返回value。model字段的类型也就是该转换器类对应的目标类类型,比如LongArrayCo
nverter里的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
方法注释里指出,它要求参数svalue是形如“{abc,def,ghi}”的字符串,使用逗号对svalue进行分隔,将分隔后的元素放到List里返回。
在这段代码的try块里,首先构造一个java.io.StreamTokenizer,设置逗号做为分隔符,再将0到9、负号、小数点这些字符设置为普通字符,因为默认的StreamTokenizer会将这些这些字符组成的字符串转换成double类型,而在这里不需要这个功能。然后使用StreamTokenizer的方式分隔svalue,将分隔的元素放到List里返回。
由于ActionForm字段的数据类型是在应用运行前写死的,请求参数是在应用运行后才能确定的,所以它们之间存在数据类型转换的问题。
Struts在用请求参数填充ActionForm字段时,不论它们数据类型是否一致,都会根据ActionForm字段的数据类型,使用相应的数据类型转换器将请求参数转换成和ActionForm字段相同的数据类型,然后调用字段对应的setter方法来填充字段。
Struts没有自己实现这些转换器,而是使用Apache Commons BeanUtils提供的一系列转换器,在org.apache.commons.beanutils.ConvertUtilsBean类的deregister()方法里,可以看到这些转换器的注册过程,代码如下:
/** * Remove all registered {@link Converter}s, and re-establish the * standard Converters. */ public void deregister() { boolean booleanArray[] = new boolean[0]; byte byteArray[] = new byte[0]; char charArray[] = new char[0]; double doubleArray[] = new double[0]; float floatArray[] = new float[0]; int intArray[] = new int[0]; long longArray[] = new long[0]; short shortArray[] = new short[0]; String stringArray[] = new String[0]; converters.clear(); register(BigDecimal.class, new BigDecimalConverter()); register(BigInteger.class, new BigIntegerConverter()); register(Boolean.TYPE, new BooleanConverter(defaultBoolean)); register(Boolean.class, new BooleanConverter(defaultBoolean)); register(booleanArray.getClass(), new BooleanArrayConverter(booleanArray)); register(Byte.TYPE, new ByteConverter(defaultByte)); register(Byte.class, new ByteConverter(defaultByte)); register(byteArray.getClass(), new ByteArrayConverter(byteArray)); register(Character.TYPE, new CharacterConverter(defaultCharacter)); register(Character.class, new CharacterConverter(defaultCharacter)); register(charArray.getClass(), new CharacterArrayConverter(charArray)); register(Class.class, new ClassConverter()); register(Double.TYPE, new DoubleConverter(defaultDouble)); register(Double.class, new DoubleConverter(defaultDouble)); register(doubleArray.getClass(), new DoubleArrayConverter(doubleArray)); register(Float.TYPE, new FloatConverter(defaultFloat)); register(Float.class, new FloatConverter(defaultFloat)); register(floatArray.getClass(), new FloatArrayConverter(floatArray)); register(Integer.TYPE, new IntegerConverter(defaultInteger)); register(Integer.class, new IntegerConverter(defaultInteger)); register(intArray.getClass(), new IntegerArrayConverter(intArray)); register(Long.TYPE, new LongConverter(defaultLong)); register(Long.class, new LongConverter(defaultLong)); register(longArray.getClass(), new LongArrayConverter(longArray)); register(Short.TYPE, new ShortConverter(defaultShort)); register(Short.class, new ShortConverter(defaultShort)); register(shortArray.getClass(), new ShortArrayConverter(shortArray)); register(String.class, new StringConverter()); register(stringArray.getClass(), new StringArrayConverter(stringArray)); register(Date.class, new SqlDateConverter()); register(Time.class, new SqlTimeConverter()); register(Timestamp.class, new SqlTimestampConverter()); register(File.class, new FileConverter()); register(URL.class, new URLConverter()); }
对数据的类型转换实际上就是调用相应转换器类的convert()方法,该方法在Converter接口中定
义,上面的转换器类都直接或间接的实现了该接口,方法定义如下:
/** * Convert the specified input object into an output object of the * specified type. * * @param type Data type to which this value should be converted * @param value The input value to be converted * * @exception ConversionException if conversion cannot be performed * successfully */ public Object convert(Class type, Object value);
根据各转换器类convert()方法代码类似程度,可以把它们分为3类。下面详细说说它们的convert()方法的实现。
第1类:StringConverter
StringConverter.java
/** * Convert the specified input object into an output object of the * specified type. * * @param type Data type to which this value should be converted * @param value The input value to be converted * * @exception ConversionException if conversion cannot be performed * successfully */ public Object convert(Class type, Object value) { if (value == null) { return ((String) null); } else { return (value.toString()); } }
它的实现最简单,如果参数value为null,返回null;否则,返回value.toString()。
第2类:BigDecimalConverter、BigIntegerConverter、BooleanConverter、ByteConverter、CharacterConverter、DoubleConverter、FloatCon
verter、IntegerConverter、LongConverter、ShortConverter、SqlDateConverter、SqlTimeConverter、SqlTimestampConverter、FileConvert
er、URLConverter、ClassConverter
它们对convert()方法的实现很类似,可分为3步。下面仅列出IntegerConverter的convert()方法代码,以便给后面的纯文字叙述做个参考。
IntegerConverter.java
/** * Convert the specified input object into an output object of the * specified type. * * @param type Data type to which this value should be converted * @param value The input value to be converted * * @exception ConversionException if conversion cannot be performed * successfully */ public Object convert(Class type, Object value) { if (value == null) { if (useDefault) { return (defaultValue); } else { throw new ConversionException("No value specified"); } } if (value instanceof Integer) { return (value); } else if(value instanceof Number) { return new Integer(((Number)value).intValue()); } try { return (new Integer(value.toString())); } catch (Exception e) { if (useDefault) { return (defaultValue); } else { throw new ConversionException(e); } } }
第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外的Co
nverter使用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、IntegerAr
rayConverter、LongArrayConverter、ShortArrayConverter、StringArrayConverter
从名字就可看出,这些都是转换到数组类型的,这里要注意的是,并不是包装类数组,而是基本数据类型数组。它们都继承自org.apache.commons.beanutils.
converters.AbstractArrayConverter,这是个抽象类,它实现了Converter接口。它们的convert()方法实现可分为4步。下面仅列出IntegerArrayConverter
的convert()方法代码,以便给后面的纯文字叙述做个参考。
IntegerArrayConverter.
java
/** * Convert the specified input object into an output object of the * specified type. * * @param type Data type to which this value should be converted * @param value The input value to be converted * * @exception ConversionException if conversion cannot be performed * successfully */ public Object convert(Class type, Object value) { // Deal with a null value if (value == null) { if (useDefault) { return (defaultValue); } else { throw new ConversionException("No value specified"); } } // Deal with the no-conversion-needed case if (model.getClass() == value.getClass()) { return (value); } // Deal with input value as a String array if (strings.getClass() == value.getClass()) { try { String values[] = (String[]) value; int results[] = new int[values.length]; for (int i = 0; i < values.length; i++) { results[i] = Integer.parseInt(values[i]); } return (results); } catch (Exception e) { if (useDefault) { return (defaultValue); } else { throw new ConversionException(value.toString(), e); } } } // Parse the input value as a String into elements // and convert to the appropriate type try { List list = parseElements(value.toString()); int results[] = new int[list.size()]; for (int i = 0; i < results.length; i++) { results[i] = Integer.parseInt((String) list.get(i)); } return (results); } catch (Exception e) { if (useDefault) { return (defaultValue); } else { throw new ConversionException(value.toString(), e); } } }
第1步:和第2类中的第1步一样。
第2步:如果参数value的类型和转换器类的model字段的类型相同,直接返回value。model字段的类型也就是该转换器类对应的目标类类型,比如LongArrayCo
nverter里的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
/** * Parse an incoming String of the form similar to an array initializer * in the Java language into a List individual Strings * for each element, according to the following rules. * * The string must have matching '{' and '}' delimiters around * a comma-delimited list of values. * Whitespace before and after each element is stripped. * If an element is itself delimited by matching single or double * quotes, the usual rules for interpreting a quoted String apply. * @param svalue String value to be parsed * * @exception ConversionException if the syntax of svalue * is not syntactically valid * @exception NullPointerException if svalue * is null */ protected List parseElements(String svalue) { // Validate the passed argument if (svalue == null) { throw new NullPointerException(); } // Trim any matching '{' and '}' delimiters svalue = svalue.trim(); if (svalue.startsWith("{") && svalue.endsWith("}")) { svalue = svalue.substring(1, svalue.length() - 1); } try { // Set up a StreamTokenizer on the characters in this String StreamTokenizer st = new StreamTokenizer(new StringReader(svalue)); st.whitespaceChars(',',','); // Commas are delimiters st.ordinaryChars('0', '9'); // Needed to turn off numeric flag st.ordinaryChars('.', '.'); st.ordinaryChars('-', '-'); st.wordChars('0', '9'); // Needed to make part of tokens st.wordChars('.', '.'); st.wordChars('-', '-'); // Split comma-delimited tokens into a List ArrayList list = new ArrayList(); while (true) { int ttype = st.nextToken(); if ((ttype == StreamTokenizer.TT_WORD) || (ttype > 0)) { list.add(st.sval); } else if (ttype == StreamTokenizer.TT_EOF) { break; } else { throw new ConversionException ("Encountered token of type " + ttype); } } // Return the completed list return (list); } catch (IOException e) { throw new ConversionException(e); } }
方法注释里指出,它要求参数svalue是形如“{abc,def,ghi}”的字符串,使用逗号对svalue进行分隔,将分隔后的元素放到List里返回。
在这段代码的try块里,首先构造一个java.io.StreamTokenizer,设置逗号做为分隔符,再将0到9、负号、小数点这些字符设置为普通字符,因为默认的StreamTokenizer会将这些这些字符组成的字符串转换成double类型,而在这里不需要这个功能。然后使用StreamTokenizer的方式分隔svalue,将分隔的元素放到List里返回。
相关文章推荐
- Struts使用BeanUtils提供的数据类型转换器
- Struts使用BeanUtils提供的数据类型转换器
- 在Struts中使用JavaBean和List(多行数据)类型属性
- 在Struts中使用JavaBean和List(多行数据)类型属性-JSP教程,Java技巧及代码
- 使用commons-beanutils封装请求中的数据与数据类型的转换,web中使用md5和BASE64Encoder加密
- java使用BeanUtils封装file类型表单数据到一个对象中
- 在Struts中使用JavaBean和List(多行数据)类型属性
- struts对comments-beanutils包的使用分析以及使用自定义类型转化器的ActionServlet
- Struts2内建类型转换器数据器使用简介
- 在Struts中使用JavaBean和List(多行数据)类型属性
- 九宫格 Swift提供经典的数组和字典两种集合类型来存储集合数据,使用数组实现一个九宫格程序,
- 使用Struts2时为Android端提供数据
- net控件中数据导到Excel的格式 首先,我们了解一下excel从web页面上导出的原理。当我们把这些数据发送到客户端时,我们想让客户端程序(浏览器)以excel的格式读取它,所以把mime类型设为:application/vnd.ms-excel,当excel读取文件时会以每个cell的格式呈现数据,如果cell没有规定的格式,则excel会以默认的格式去呈现该cell的数据。这样就给我们提供了自定义数据格式的空间,当然我们必须使用excel支持的格式。下面就列出常用的一些格式: 1) 文本
- 使用BeanUtils封装数据时数据类型的转换
- struts对comments-beanutils包的使用分析以及使用自定义类型转化器的ActionServlet
- mysql的数据类型及使用
- mybatis 处理数组类型及使用Json格式保存数据 JsonTypeHandler and ArrayTypeHandler
- AS3效率优化:使用Vector数据类型
- hibernate对象映射Date数据类型和input datetime使用注意事项
- mysql常用数据类型的使用方式--日期时间型