反射的应用 将form表单的数据自动封装为对象

我们经常做表单提交,然后把一大堆页面传过来的参数一一通过set方法赋值到对象中;

还经常遇到一个表单提交同一个类的多个对象,

甚至遇到:一个表单提交多种不同类的对象。

 

学习完反射后,很希望做一个比较通用的工具类,不再每次为上面的事情做重复劳动。

 

例如:页面有以下输入框:

<input type="text" name="name"  value="Jack"/>

<input type="text" name="name"  value="Mike"/>

<input type="text" name="name"  value="Rose"/>

 

<input type="text" name="age"  value="10"/>

<input type="text" name="age"  value="21"/>

<input type="text" name="age"  value="22"/>

 

<input type="text" name="birthday"  value="1978-07-22"/>

<input type="text" name="birthday"  value="1989-07-21 05:33"/>

<input type="text" name="birthday"  value="1999-08-21 23:33:12"/>

 

希望可以通过工具类,自动获得List<Person>,这个List有3个Person对象,

Person 1 : Jack,10,1978-07-22

Person 2 : Mike,21,1989-07-21 05:33

Person 3 : Rose,22,1999-08-21 23:33:12

 

第一步-准备工作 将字符串变为合适的数据类型

页面传过来的,都是String,而我们的bean里面的属性,是五花八门的数据类型。

我们首先需要准备一些小方法,将一个String的值转化成我们需要的数据类型的值。

 

 

Java代码   收藏代码
  1. public final static Map<String, String> toTypeMethods;  
  2.     static {  
  3.         //支持的转换类型:暂时为boolean,byte,char,int,long,float,double及他们的包装类 + String,java.util.Date,BigDecimal这几种类型  
  4.         toTypeMethods = new HashMap<String, String>();  
  5.         toTypeMethods.put("boolean""toBoolean");  
  6.         toTypeMethods.put("byte""toByte");  
  7.         toTypeMethods.put("char""toString");  
  8.         toTypeMethods.put("character""toString");  
  9.         toTypeMethods.put("string""toString");  
  10.         toTypeMethods.put("int""toInteger");  
  11.         toTypeMethods.put("integer""toInteger");  
  12.         toTypeMethods.put("long""toLong");  
  13.         toTypeMethods.put("float""toFloat");  
  14.         toTypeMethods.put("double""toDouble");  
  15.         toTypeMethods.put("date""toDate");  
  16.         toTypeMethods.put("bigdecimal""toBigDecimal");  
  17.     }  
  18.   
  19.     /** 
  20.      * 这个方法的作用是:告诉我对象的属性、字符串, 
  21.          * 这样我就可以将字符串转化成属性对应的数据类型的值了。 
  22.      * 例如:在类中Person的birthday定义为Date, 
  23.          * 我就会把"2010-10-01"转为整形的Date类型的2010-10-01 
  24.      * 如果你把birthday定义为int,并传入了"2010-10-01",我的转换方法会返回null, 
  25.          * 你也可以抛出异常,这个关键是看转换的方法实现,你可以按自己的要求更改 
  26.      * @param field 对象的属性 
  27.      * @param string 页面的参数 
  28.      * @param 将string转化为属性类型的值 
  29.      */  
  30.     public static Object toTypeValue(Field field, String string)  
  31.             throws Exception{  
  32.             String fieldTypename = field.getType().getSimpleName(); //属性的类型(不包含报名)  
  33.             //通过属性的类型,从map中找到要调用的方法的名字,这些方法是将一个String的值转化成我们需要的数据类型的值  
  34.             String methodName = toTypeMethods.get(fieldTypename.toLowerCase());   
  35.             //获取方法  
  36.             Method method =   
  37.                 BeanReflectUtil.class.  
  38.                 getDeclaredMethod(methodName, string.getClass());   
  39.             //调用方法,返回属性类型的值  
  40.             return method.invoke(null, string); //如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null。   
  41.         }  
  42.   
  43.     //下面这些小方法是为了将一个String的值转化成我们需要的数据类型的值  
  44.     @SuppressWarnings("unused")  
  45.     private static Boolean toBoolean(final String s) {  
  46.         return NumberUtil.toBoolean(s, true);  
  47.     }  
  48.     @SuppressWarnings("unused")  
  49.     private static Byte toByte(final String s) {  
  50.         return NumberUtil.toByte(s, (byte)0);  
  51.     }  
  52.   
  53.     @SuppressWarnings("unused")  
  54.     private static String toString(final String s) {  
  55.         return s;  
  56.     }  
  57.   
  58.     @SuppressWarnings("unused")  
  59.     private static Integer toInteger(final String s) {  
  60.         return NumberUtil.toInt(s, 0);  
  61.     }  
  62.     @SuppressWarnings("unused")  
  63.     private static Long toLong(final String s) {  
  64.         return NumberUtil.toLong(s, 0);  
  65.     }  
  66.     @SuppressWarnings("unused")  
  67.     private static Float toFloat(String s) {  
  68.         return NumberUtil.toFloat(s, (float)0);  
  69.     }  
  70.     @SuppressWarnings("unused")  
  71.     private static Double toDouble(String s) {  
  72.         return NumberUtil.toDouble(s, 0.0);  
  73.     }  
  74.     @SuppressWarnings("unused")  
  75.     private static Date toDate(String s) { //支持部分日期格式  
  76.         try {  
  77.             return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(s);  
  78.         } catch(Exception e1) {  
  79.             try {  
  80.                 return new SimpleDateFormat("yyyy-MM-dd HH:mm").parse(s);  
  81.             }catch(Exception e2) {  
  82.                 try {  
  83.                     return new SimpleDateFormat("yyyy-MM-dd").parse(s);  
  84.                 } catch (Exception e3) {  
  85.                     return null;  
  86.                 }  
  87.             }  
  88.         }   
  89.     }  
  90.   
  91.     @SuppressWarnings("unused")  
  92.     private static BigDecimal toBigDecimal(String s) {  
  93.         try {  
  94.             return new BigDecimal(s);  
  95.         } catch(Exception e) {  
  96.             return new BigDecimal(0);  
  97.         }  
  98.     }  
 

 

    NumberUtil.toXXX是为了将String转换为其他数据类型,它们的实现很简单,以整形为例:

Java代码   收藏代码
  1. /*** 
  2.  * 将字符串变成整形 
  3.  * @param value 源 
  4.  * @param defaultInt 变成整形时若抛出异常则返回默认值 
  5.  * @return 
  6.  */  
  7. public static int toInt(String value, int defaultInt) {  
  8.     int result = 0;  
  9.     try {  
  10.         result = Integer.parseInt(value);  
  11.     } catch(NumberFormatException e) {  
  12.         result = defaultInt;  
  13.     }  
  14.     return result;  
  15. }  

 

 如何使用:

现在我在页面获得了"20",需要把"20"赋给age

Java代码   收藏代码
  1. //希望大家看看前一篇文章(1)发射getter And Setter 的基本内容:http://ivan0513.iteye.com/admin/blogs/728396  
  2. Person p = new Person();  
  3. //将字符串"20" 转换为Integer 20  
  4. Object age = toTypeValue(p.getClass().getDeclaredField("age"), "20");  
  5. //将整形20赋值给对象Person的age,这里我故意不使用setAge方法,因为以后我们从页面换取参数,  
  6. //我们又怎会知是哪个对象的哪个属性呢。需要通用的反射。  
  7. //invokeSetMethod在附件BeanReflectUtil.java中  
  8. BeanReflectUtil.invokeSetMethod(Person.class"age", p, age);  
  9. //打印验证  
  10. System.out.println(p.getAge());  

 那么控制台就会打印出:

Java代码   收藏代码
  1. 20   

 

完成上面的工具方法,那么,离自动将form表单的参数封装成对象集合的路就不远了!

第二步-获取页面的参数,封装返回对象集合List

Java代码   收藏代码
  1. /*** 
  2.  * 从页面取关于这个bean的元素数组 
  3.  * 页面与类的字段名称必须一致 
  4.  * @param c 要从页面中获取哪个类的信息 
  5.  * return Map 字段名,字段值数组 
  6.  */  
  7. public static Map<String, String[]> getFieldValues(HttpServletRequest request, Class<?> c) {  
  8.  Map<String, String[]> fieldValues = new HashMap<String, String[]>();  
  9. //这个类有哪些属性  
  10.  String[] fieldNames = BeanReflectUtil.getDeclaredFieldNames(c);  
  11.  for(int i=0; i<fieldNames.length; i++) {  
  12. //循环属性,获取页面相应参数数组  
  13.   String[] values = request.getParameterValues(fieldNames[i]);  
  14.   fieldValues.put(fieldNames[i], values);  
  15.  }  
  16.  return fieldValues;  
  17. }  
Java代码   收藏代码
  1. /** 
  2.  * 返回潜在对象可能的个数 
  3.  * 本方法假定假设以下条件成立 
  4.  * 1.页面的参数可能不会有对象的所有属性,但至少存在1个, 
  5.  * 即Person{name, age, birthday}在页面中,至少有<input type="text" name="age" value="20" />(以文本框为例,不一定是文本框) 
  6.  * 2.在存在的前提下,不同属性的参数个数一样 
  7.  * 即<input type="text" name="age" id="age1" />  <input type="text" name="name" id="name1" /> 
  8.  * <input type="text" name="age" id="age2" /> <input type="text" name="name" id="name2" /> 
  9.  * 其他特殊情况恕不支持,如: 
  10.  * <input type="text" name="age" id="age1" />  <input type="text" name="name" id="name1" /> <input type="text" name="birthday" id="birthday1" /> 
  11.  * <input type="text" name="age" id="age2" /> <input type="text" name="name" id="name2" /> <!--有2个age,name,却只有1个birthday--> 
  12.  * @param fieldValues 
  13.  * @return 
  14.  */  
  15. public static int getParameterLenth(HttpServletRequest request, Class<?> c) {  
  16.    
  17.  int parameterLenth = 0;  
  18.  String[] fieldNames = BeanReflectUtil.getDeclaredFieldNames(c);  
  19.  for(int i=0; i<fieldNames.length; i++) {  
  20.   String[] values = request.getParameterValues(fieldNames[i]);  
  21.   if(values != null) {  
  22.    parameterLenth = values.length;  
  23.    break;  
  24.   }  
  25.  }  
  26.  return parameterLenth;  
  27. }  
Java代码   收藏代码
  1. /** 
  2.  * 将页面元素自动封装成bean,而且是多个bean 
  3.  * @param request 
  4.  * @param c 
  5.  * @return 
  6.  * @throws Exception 
  7.  * @throws NoSuchFieldException 
  8.  */  
  9. public static List<?> assembleObjectList(HttpServletRequest request, Class<?> c)   
  10.  throws Exception, NoSuchFieldException {  
  11.  Object[] objArray = null;  
  12.  //1.获取页面元素(关于这个bean的页面元素)  
  13.  Map<String, String[]> fieldValues = getFieldValues(request, c);  
  14.  List objList = null;  
  15.  if(fieldValues != null) {  
  16.   //2.获取bean的数量  
  17.   int objLength = getParameterLenth(request, c);  
  18.   objArray = new Object[objLength];  
  19.   objList = new ArrayList();  
  20.   //3.生成实例  
  21.   for(int i=0; i<objLength; i++) {  
  22.    objArray[i] = c.newInstance();  
  23.    objList.add(objArray[i]);  
  24.   }  
  25.   //为每个实例的每个元素赋值(如果页面有该参数数组)  
  26.   Iterator<String> keyIt = fieldValues.keySet().iterator();  
  27.   while(keyIt.hasNext()) {  
  28.    String fieldName = keyIt.next();  
  29.    Field field = c.getDeclaredField(fieldName); //获取参数对应的字段  
  30.    String[] fieldValue = fieldValues.get(fieldName); //获取参数数组  
  31.    if(fieldValue != null) {  
  32.     for(int i=0; i<objArray.length; i++) { //循环:为每个对象的字段,附上参数数组的值(通过set方法)  
  33.      //1.准备字段的Set方法  
  34.      Method m = BeanReflectUtil.assembleSetMethod(c, field);  
  35.      //2.页面的值(String类型)转变为该字段对应类型的值  
  36.      Object fieldObj = BeanReflectUtil.toTypeValue(field, fieldValue[i]);   
  37.      //3.调用Set方法  
  38.      m.invoke(objArray[i], fieldObj); //为对象objArray[i]调用set方法,为上文中的field字段附上fieldObj这个值  
  39.     }  
  40.    }  
  41.   }  
  42.  }  
  43.    
  44. //  return objArray;  
  45.  return objList;  
  46. }  

 

使用:

如页面中有:<form>

Html代码   收藏代码
  1. <input type="text" name="age" id="age1" />    
  2. <input type="text" name="name" id="name1" />  
  3. <input type="text" name="age" id="age2" />   
  4. <input type="text" name="name" id="name2" />  
  5. </form>  

 

提交后,后台封装List<Person>,只需以下代码:

Java代码   收藏代码
  1. List<Person> list = (List<Person>) BaiscDataUtil.assembleObjectList(request, Person.class);  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值