1. 程式人生 > >反射的應用 將form表單的資料自動封裝為物件

反射的應用 將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.      * 例如:在類中Person的birthday定義為Date, 
  22.          * 我就會把"2010-10-01"轉為整形的Date型別的2010-10-01 
  23.      * 如果你把birthday定義為int,並傳入了"2010-10-01",我的轉換方法會返回null, 
  24.          * 你也可以丟擲異常,這個關鍵是看轉換的方法實現,你可以按自己的要求更改 
  25.      * @param field 物件的屬性 
  26.      * @param string 頁面的引數 
  27.      * @param 將string轉化為屬性型別的值 
  28.      */  
  29.     public static Object toTypeValue(Field field, String string)  
  30.             throws Exception{  
  31.             String fieldTypename = field.getType().getSimpleName(); //屬性的型別(不包含報名)  
  32.             //通過屬性的型別,從map中找到要呼叫的方法的名字,這些方法是將一個String的值轉化成我們需要的資料型別的值  
  33.             String methodName = toTypeMethods.get(fieldTypename.toLowerCase());   
  34.             //獲取方法  
  35.             Method method =   
  36.                 BeanReflectUtil.class.  
  37.                 getDeclaredMethod(methodName, string.getClass());   
  38.             //呼叫方法,返回屬性型別的值  
  39.             return method.invoke(null, string); //如果底層方法是靜態的,那麼可以忽略指定的 obj 引數。該引數可以為 null。   
  40.         }  
  41.     //下面這些小方法是為了將一個String的值轉化成我們需要的資料型別的值  
  42.     @SuppressWarnings("unused")  
  43.     private static Boolean toBoolean(final String s) {  
  44.         return NumberUtil.toBoolean(s, true);  
  45.     }  
  46.     @SuppressWarnings("unused")  
  47.     private static Byte toByte(final String s) {  
  48.         return NumberUtil.toByte(s, (byte)0);  
  49.     }  
  50.     @SuppressWarnings("unused")  
  51.     private static String toString(final String s) {  
  52.         return s;  
  53.     }  
  54.     @SuppressWarnings("unused")  
  55.     private static Integer toInteger(final String s) {  
  56.         return NumberUtil.toInt(s, 0);  
  57.     }  
  58.     @SuppressWarnings("unused")  
  59.     private static Long toLong(final String s) {  
  60.         return NumberUtil.toLong(s, 0);  
  61.     }  
  62.     @SuppressWarnings("unused")  
  63.     private static Float toFloat(String s) {  
  64.         return NumberUtil.toFloat(s, (float)0);  
  65.     }  
  66.     @SuppressWarnings("unused")  
  67.     private static Double toDouble(String s) {  
  68.         return NumberUtil.toDouble(s, 0.0);  
  69.     }  
  70.     @SuppressWarnings("unused")  
  71.     private static Date toDate(String s) { //支援部分日期格式  
  72.         try {  
  73.             return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(s);  
  74.         } catch(Exception e1) {  
  75.             try {  
  76.                 return new SimpleDateFormat("yyyy-MM-dd HH:mm").parse(s);  
  77.             }catch(Exception e2) {  
  78.                 try {  
  79.                     return new SimpleDateFormat("yyyy-MM-dd").parse(s);  
  80.                 } catch (Exception e3) {  
  81.                     return null;  
  82.                 }  
  83.             }  
  84.         }   
  85.     }  
  86.     @SuppressWarnings("unused")  
  87.     private static BigDecimal toBigDecimal(String s) {  
  88.         try {  
  89.             return new BigDecimal(s);  
  90.         } catch(Exception e) {  
  91.             return new BigDecimal(0);  
  92.         }  
  93.     }  

    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.  int parameterLenth = 0;  
  17.  String[] fieldNames = BeanReflectUtil.getDeclaredFieldNames(c);  
  18.  for(int i=0; i<fieldNames.length; i++) {  
  19.   String[] values = request.getParameterValues(fieldNames[i]);  
  20.   if(values != null) {  
  21.    parameterLenth = values.length;  
  22.    break;  
  23.   }  
  24.  }  
  25.  return parameterLenth;  
  26. }  
Java程式碼  收藏程式碼
  1. /** 
  2.  * 將頁面元素自動封裝成bean,而且是多個bean 
  3.  * @param request 
  4.  * @param c