深度剖析:对象与表单的自动装配

开发 后端
时下很多 Web 框架 都实现了 Form 表单域与 Java 对象属性的自动装配功能,该功能确实非常有用,试想如果没这功能则势必到处冲积着 request.getParameter() 系列方法与类型转换方法的调用。

时下很多 Web 框架 都实现了 Form 表单域与 Java 对象属性的自动装配功能,该功能确实非常有用,试想如果没这功能则势必到处冲积着 request.getParameter() 系列方法与类型转换方法的调用。重复代码量大,容易出错,同时又不美观,影响市容。

现在的问题是,这些框架通过什么方法实现自动装配的?如果不用这些框架我们自己如何去实现呢?尤其对于那些纯 JSP/Servlet 应用,要是拥有自动装配功能该多好啊!本座深知各位之期盼,决定把自动装配的原理和实现方法娓娓道来。

实现原理其实比较简单,主要由以下3个步骤构成:

  • 通过 request.getParameterMap() 获取被提交的 Form 的所有表单域的名称-值映射,其中名称和值均为字符串类型。
  • 利用 java.beans.PropertyDescriptor 对象获取 Java Bean 的所有属性的名称及其类型。
  • 把表单域的名称与 Bean 的属性的名称逐个进行匹配,当找到相匹配的属性时就调用 Bean 的 setter 方法把表单域的值设置给该 Bean 属性。当然,因为表单域的值总是字符串类型,很可能与 Bean 属性的类型不一致,所以在设置 Bean 属性前要进行必要的类型转换。

上面所表述的3点原理不知大家是否完全理解,没关系,下面我们通过一个具体的表单提交的例子来看一看实际的效果,首先看看待提交的表单页面及其代码:

  1. <form action="checkbean.action" method="post"> 
  2.     First Name: <input type="text" name="firstName" value="丑"> 
  3.     <br> 
  4.     Last Name: <input type="text" name="lastName" value="怪兽"> 
  5.     <br> 
  6.     Birthday: <input type="text" name="birthday" value="1978-11-03"> 
  7.     <br> 
  8.     Gender: 男 <input type="radio"" name="gender" value="false"> 
  9.         &nbsp;女 <input type="radio"" name="gender" value="true" checked="checked"> 
  10.     <br> 
  11.     Working age: <select name="working-Age"> 
  12.         <option value="-1">-请选择-</option> 
  13.         <option value="3">三年</option> 
  14.         <option value="5" selected="selected">五年</option> 
  15.         <option value="10">十年</option> 
  16.         <option value="20">二十年</option> 
  17.     </select> 
  18.     <br> 
  19.     Interest: 游泳 <input type="checkbox" name="its" value="1" checked="checked"> 
  20.         &nbsp;打球 <input type="checkbox" name="its" value="2" checked="checked"> 
  21.         &nbsp;下棋 <input type="checkbox" name="its" value="3"> 
  22.         &nbsp;打麻将 <input type="checkbox" name="its" value="4"> 
  23.         &nbsp;看书 <input type="checkbox" name="its" value="5" checked="checked"> 
  24.     <br> 
  25. <br> 
  26. <input type="submit" value="确 定">&nbsp;&nbsp;<input type="reset" value="重 置"> 
  27. </form> 

从上图可以看出,总共有6个表单域,其名称-值分别是:{"firstName" - "丑","lastName" - "怪兽","birthday" - "1978-11-03","gender" - "女","working-Age" - "5","its" - "1,2,5"},该表单需要提交给 checkbean.action 进行处理(请注意:不要一看到 .aciton 就以为是 struts2,骑白马的不一定都是唐僧!),下面来看看 CheckBean Action 的处理代码和 Bean 的定义:

  1. import java.util.HashMap;  
  2. import java.util.Map;  
  3.  
  4. import vo.Persion;  
  5.  
  6. import com.bruce.mvc.ActionSupport;  
  7.  
  8. public class CheckBean extends ActionSupport  
  9. {  
  10.     @Override 
  11.     public String execute()  
  12.     {  
  13.         // 如果表单元素的名称和 Form Bean 属性名不一致则使用 keyMap 进行映射  
  14.         // key: 表单元素名称, value: Form Bean 属性名  
  15.         Map<String, String> keyMap = new HashMap<String, String>();  
  16.         keyMap.put("working-Age""workingAge");  
  17.         keyMap.put("its""interest");  
  18.           
  19.         /* 自动装配方法一 */ 
  20.         // 使用表单元素创建 Form Bean  
  21.         // 如果表单元素的名称和 Form Bean 属性名完全一致则不需使用 keyMap 进行映射  
  22.         Persion p = createFormBean(Persion.class, keyMap);  
  23.           
  24.         /* 自动装配方法二 */ 
  25.         // 先创建 Form Bean 对象, 然后再填充它的属性  
  26.         Persion p2 = new Persion();  
  27.         fillFormBeanProperties(p2, keyMap);  
  28.           
  29.         // 可以获取 Form Bean 的所有属性值  
  30.         //Map<String, Object> result = BeanHelper.getProperties(p);  
  31.           
  32.         // 把 p 设置为 request 属性,并最终在结果页面展示  
  33.         setRequestAttribute("persion", p);  
  34.           
  35.         return SUCCESS;  
  36.     }  
  1. import java.util.Date;  
  2. import java.util.List;  
  3.  
  4. public class Persion  
  5. {  
  6.     private String firstName;  
  7.     private String lastName;  
  8.     private Date birthday;  
  9.     private boolean gender;  
  10.     private int workingAge;  
  11.     private int[] interest;  
  12.     private List<String> photos;  
  13.  
  14.     // getter 和 setter 方法  
  15.     // (略)。。。。。。  

从 CheckBean 的代码可以看出,它是通过 createFormBean() 或 fillFormBeanProperties() 方法来自动装配 Persion 的,它们之间的区别是:前者会直接创建新的 Persion 对象,而后者填充原有 Persion 对象的属性。请注意,如果表单域的名称与 Persion 对应的属性名不一致则用 keyMap 进行映射,如表单域 "working-Age" 是对应 Persion 的 workingAge 属性的,但它们的名称不一致,所以要进行映射。另外,Persion 有一个 photos 属性,而我们的表单域却没有,自动装配时会忽略该属性。最后看一下输出的结果页面及其代码:

  1. <body> 
  2.   <br> 
  3.   <div align="right"> 
  4.       <a href="index.action"><u:msg key="jsp-set_locale.back-to-index"/></a> 
  5.   </div> 
  6.     <br><br><br><br> 
  7.     <div align="center"> 
  8.     <table border="1"> 
  9.     <caption>Persion Attributs</caption> 
  10.       
  11.         <tr><td>Name</td><td><c:out value="${persion.firstName} ${persion.lastName}"/>&nbsp;</td></tr> 
  12.         <tr><td>Brithday</td><td><c:out value="${persion.birthday}"/>&nbsp;</td></tr> 
  13.         <tr><td>Gender</td><td><c:out value="${persion.gender}"/>&nbsp;</td></tr> 
  14.         <tr><td>Working Age</td><td><c:out value="${persion.workingAge}"/>&nbsp;</td></tr> 
  15.         <tr><td>Interest</td><td><c:forEach var="its" items="${persion.interest}"> 
  16.                                      <c:out value="${its}" /> &nbsp;  
  17.                               </c:forEach>&nbsp;</td></tr> 
  18.         <tr><td>Photos</td><td><c:forEach var="p" items="${persion.photos}"> 
  19.                                      <c:out value="${p}" /><br> 
  20.                               </c:forEach>&nbsp;</td></tr> 
  21.     </table> 
  22.    </div> 
  23.   </body> 

通过上面的例子可以看到,通过自动装配 Bean,我们获得了非常大的便利。现在我们就从createFormBean() 和 fillFormBeanProperties() 开始,逐步揭开自动装配的神秘面纱,先看看下面两个类及其方法的定义:

  1. package com.bruce.mvc;  
  2.  
  3. import com.bruce.util.http.HttpHelper;  
  4.  
  5. /** {@link Action} 对象公共基类 */ 
  6. public class ActionSupport implements Action  
  7. {  
  8.     private ServletContext servletContext;  
  9.     private HttpServletRequest request;  
  10.     private HttpServletResponse response;  
  11.     private HttpSession session;  
  12.  
  13.     /** 默认 {@link Action} 入口方法(返回 {@link Action#SUCCESS}) */ 
  14.     public String execute()  
  15.     {  
  16.         return SUCCESS;  
  17.     }  
  18.  
  19.     /** 使用表单元素创建 Form Bean (表单元素的名称和 Form Bean 属性名完全一致) */ 
  20.     public final <T> T createFormBean(Class<T> clazz)  
  21.     {  
  22.         return HttpHelper.createFormBean(request, clazz);  
  23.     }  
  24.  
  25.     /** 使用表单元素创建 Form Bean (用 keyMap 映射与表单元素名称不对应的 Form Bean 属性) */ 
  26.     public final <T> T createFormBean(Class<T> clazz, Map<String, String> keyMap)  
  27.     {  
  28.         return HttpHelper.createFormBean(request, clazz, keyMap);  
  29.     }  
  30.       
  31.     /** 使用表单元素填充 Form Bean (表单元素的名称和 Form Bean 属性名完全一致) */ 
  32.     public final <T> void fillFormBeanProperties(T bean)  
  33.     {  
  34.         HttpHelper.fillFormBeanProperties(request, bean);  
  35.     }  
  36.       
  37.     /** 使用表单元素填充 Form Bean (用 keyMap 映射与表单元素名称不对应的 Form Bean 属性) */ 
  38.     public final <T> void fillFormBeanProperties(T bean, Map<String, String> keyMap)  
  39.     {  
  40.         HttpHelper.fillFormBeanProperties(request, bean, keyMap);  
  41.     }  
  42.       
  43.     // 其它方法  
  44.     // (略)。。。  
  1. package com.bruce.util.http;  
  2.  
  3. import com.bruce.util.BeanHelper;  
  4.  
  5. /** HTTP 帮助类 */ 
  6. public class HttpHelper  
  7. {  
  8.     /** 使用表单元素创建 Form Bean (表单元素的名称和 Form Bean 属性名完全一致) */ 
  9.     public final static <T> T createFormBean(HttpServletRequest request, Class<T> clazz)  
  10.     {  
  11.         return createFormBean(request, clazz, null);  
  12.     }  
  13.  
  14.     /** 使用表单元素创建 Form Bean (用 keyMap 映射与表单元素名称不对应的 Form Bean 属性) */ 
  15.     public final static <T> T createFormBean(HttpServletRequest request, Class<T> clazz, Map<String, String> keyMap)  
  16.     {  
  17.         Map<String, String[]> properties = getParamMap(request);  
  18.         return BeanHelper.createBean(clazz, properties, keyMap);  
  19.     }  
  20.       
  21.     /** 使用表单元素填充 Form Bean (表单元素的名称和 Form Bean 属性名完全一致) */ 
  22.     public final static <T> void fillFormBeanProperties(HttpServletRequest request, T bean)  
  23.     {  
  24.         fillFormBeanProperties(request, bean, null);  
  25.     }  
  26.       
  27.     /** 使用表单元素填充 Form Bean (用 keyMap 映射与表单元素名称不对应的 Form Bean 属性) */ 
  28.     public final static <T> void fillFormBeanProperties(HttpServletRequest request, T bean, Map<String, String> keyMap)  
  29.     {  
  30.      Map<String, String[]> properties = getParamMap(request);  
  31.      BeanHelper.setProperties(bean, properties, keyMap);  
  32.     }  
  33.       
  34.     /** 获取 {@link HttpServletRequest} 的所有参数名称和值 */ 
  35.     public final static Map<String, String[]> getParamMap(HttpServletRequest request)  
  36.     {  
  37.         return request.getParameterMap();  
  38.     }  
  39.  
  40.     // 其它方法  
  41.     // (略)。。。  

哈哈,大家看到了吧,我们迂回了那么久,但 ActionSupport 类和 HttpHelper 类并没有并没有做多少事情,他们只是获取请求参数 Map,并传递给 BeanHelper 类的 createBean() 和 setProperties() 方法进行装配,实际负责装配工作的是 BeanHelper 。这里解析一下为何要写得那么迂回,其实这些代码是从本座自己写的 “Portal Web 开发框架” 中摘录出来的,总之一句话:是因为框架的需要而写得那么迂回的,并非本座有意而为之。顺便做下广告:“Portal Web 开发框架”是一套功能完备的 Web 服务端开发框架,内置 MVC Web 基础架构,支持可扩展的数据访问接口(已内置 Hibernate、MyBaits 和 JDBC 支持),集成拦截器、国际化、文件上传下载和缓存等基础 Web 服务,基于纯 Jsp/Servlet API 实现,非常容易学习和使用。尤其适合那些希望使用纯 Jsp/Servlet API 进行开发或对 SSH 等主流框架的复杂性感到繁琐与无奈的人士使用。该框架已通过多个商业项目考验,并不是写来玩的哦。如果各位有兴趣,本座以后再找个机会开个专贴详细介绍下这个框架。

不扯远了,回到我们的正题,我们再来看看 BeanHelper 的装配工装是如何实现的:

  1. /** Java Bean 帮助类,执行 Java Bean 属性的 get / set 相关操作 */ 
  2. public class BeanHelper  
  3. {  
  4.     /** 创建指定类型的 Java Bean,并设置相关属性  
  5.      *   
  6.      *  @param clazz        : Bean 类型  
  7.      *  @param properties    : 属性名 / 值映射<br>  
  8.      *                        其中名称为 {@link String} 类型,与属性名称可能一直也可能不一致<br>  
  9.      *                        属性值可能为以下 3 中类型:<br>  
  10.      *                        &nbsp; &nbsp; 1) 属性的实际类型:直接对属性赋值<br>  
  11.      *                        &nbsp; &nbsp; 2) {@link String} 类型:先执行自动类型转换再对属赋值<br>  
  12.      *                        &nbsp; &nbsp; 3) {@link String}[] 类型:先执行自动类型转换再对属赋值<br>  
  13.      *  @param keyMap        : properties.key / Bean 属性名映射,当 properties 的 key 与属性名不对应时,  
  14.      *                        用 keyMap 把它们关联起来  
  15.      *  @return                  生成的 Bean实例    
  16.      */ 
  17.     public static final <B, T> B createBean(Class<B> clazz, Map<String, T> properties, Map<String, String> keyMap)  
  18.     {  
  19.         B bean = null;  
  20.           
  21.         try 
  22.         {  
  23.             // 创建 Bean 实例  
  24.             bean = clazz.newInstance();  
  25.             // 设置 Bean 属性  
  26.             setProperties(bean, properties, keyMap);  
  27.         }  
  28.         catch(Exception e)  
  29.         {  
  30.             throw new RuntimeException(e);  
  31.         }  
  32.           
  33.         return bean;  
  34.     }  
  35.       
  36.     public static final <B, T> B createBean(Class<B> clazz, Map<String, T> properties)  
  37.     {  
  38.         return createBean(clazz, properties, null);  
  39.     }  
  40.  
  41.     /** 设置 Java Bean 的属性  
  42.      *   
  43.      *  @param bean            : Bean 实例  
  44.      *  @param properties    : 属性名 / 值映射<br>  
  45.      *                        其中名称为 {@link String} 类型,与属性名称可能一直也可能不一致<br>  
  46.      *                        属性值可能为以下 3 中类型:<br>  
  47.      *                        &nbsp; &nbsp; 1) 属性的实际类型:直接对属性赋值<br>  
  48.      *                        &nbsp; &nbsp; 2) {@link String} 类型:先执行自动类型转换再对属赋值<br>  
  49.      *                        &nbsp; &nbsp; 3) {@link String}[] 类型:先执行自动类型转换再对属赋值<br>  
  50.      *  @param keyMap        : properties.key / Bean 属性名映射,当 properties 的 key 与属性名不对应时,  
  51.      *                        用 keyMap 把它们关联起来    
  52.      */ 
  53.     public static final <T> void setProperties(Object bean, Map<String, T> properties, Map<String, String> keyMap)  
  54.     {  
  55.         // 获取所有 Bean 属性  
  56.         Map<String, PropertyDescriptor> pps = getPropDescMap(bean.getClass());  
  57.         Set<Map.Entry<String, T>> set        = properties.entrySet();  
  58.           
  59.         // 根据属性名称设置 Bean 的每个属性值  
  60.         for(Map.Entry<String, T> o : set)  
  61.         {  
  62.             String name    = null;    // 属性名称  
  63.             String key    = o.getKey();  
  64.               
  65.             if(keyMap != null)  
  66.                 name = keyMap.get(key);  
  67.             if(name == null)  
  68.                 name = key;  
  69.  
  70.             T value    = o.getValue();  
  71.             PropertyDescriptor pd = pps.get(name);    // 名称对应的 PropertyDescriptor  
  72.               
  73.             if(pd != null && value != null)  
  74.                 // 设置指定属性值  
  75.                 setProperty(bean, pd, value);  
  76.         }  
  77.     }  
  78.  
  79.     public static final <T> void setProperties(Object bean, Map<String, T> properties)  
  80.     {  
  81.         setProperties(bean, properties, null);  
  82.     }  
  83.  
  84.     // 设置指定属性值  
  85.     private static final <T> boolean setProperty(Object bean, PropertyDescriptor pd, T value)  
  86.     {  
  87.         // 获取属性的 setter 方法  
  88.         Method method = pd.getWriteMethod();  
  89.         // 只处理 public 的实例 setter 方法  
  90.         if(method != null && isPublicInstanceMethod(method))  
  91.         {  
  92.             method.setAccessible(true);  
  93.               
  94.             Class<?> clazz = pd.getPropertyType();  
  95.             // 设置具体属性值  
  96.             setProperty(bean, value, method, clazz);  
  97.               
  98.             return true;  
  99.         }  
  100.           
  101.         return false;  
  102.     }  
  103.  
  104.     // 设置具体属性值  
  105.     private static <T> void setProperty(Object bean, T value, Method method, Class<?> clazz)  
  106.     {  
  107.         Object param                = null;  
  108.         Class<?> valueType        = value.getClass();  
  109.         Class<?> valueComType    = valueType.getComponentType();  
  110.         Class<?> clazzComType    = clazz.getComponentType();  
  111.           
  112.         // 检查是否需要作类型转换          
  113.         if(  
  114.             !clazz.isAssignableFrom(valueType)            &&  
  115.             (      
  116.                 (valueType.equals(String.class))        ||   
  117.                 (valueType.isArray() && valueComType.equals(String.class))  
  118.             )                                            &&  
  119.             (      
  120.                 (GeneralHelper.isSimpleType(clazz))        ||   
  121.                 (clazz.isArray() && GeneralHelper.isSimpleType(clazzComType))  
  122.             )  
  123.         )  
  124.             // 转换为目标类型的属性值  
  125.             param = parseParameter(clazz, value);  
  126.         else 
  127.             param = value;  
  128.           
  129.         // 调研 setter 方法设置属性值  
  130.         invokeMethod(bean, method, param);  
  131.     }  
  132.       
  133.     // 执行类型转换 (不解释了,看官们自己参详吧 ^_^)  
  134.     private static final <T> Object parseParameter(Class<?> clazz, T obj)  
  135.     {  
  136.         Object param        = null;  
  137.         Class<?> valueType    = obj.getClass();  
  138.           
  139.         if(clazz.isArray())  
  140.         {  
  141.             String[] value = null;  
  142.               
  143.             if(valueType.isArray())  
  144.                 value    = (String[])obj;  
  145.             else 
  146.             {  
  147.                 String str    = (String)obj;  
  148.                 StringTokenizer st = new StringTokenizer(str, " ,;\t\n\r\f");  
  149.                 value    = new String[st.countTokens()];  
  150.  
  151.                 for(int i = 0; st.hasMoreTokens(); i++)  
  152.                     value[i] = st.nextToken();  
  153.             }  
  154.               
  155.             int length        = value.length;  
  156.             Class<?> type    = clazz.getComponentType();  
  157.             param            = Array.newInstance(type, length);  
  158.  
  159.             for(int i = 0; i < length; i++)  
  160.             {  
  161.                 String v = value[i];  
  162.                 Object p = GeneralHelper.str2Object(type, v);  
  163.                 Array.set(param, i, p);  
  164.             }  
  165.         }  
  166.         else 
  167.         {  
  168.             String value = null;  
  169.               
  170.             if(valueType.isArray())  
  171.             {  
  172.                 String[] array    = (String[])obj;  
  173.                 if(array.length > 0)  
  174.                     value = array[0];  
  175.             }  
  176.             else 
  177.                 value = (String)obj;  
  178.               
  179.             param = GeneralHelper.str2Object(clazz, value);  
  180.         }  
  181.           
  182.         return param;  
  183.     }  
  184.       
  185.     // 其他方法  
  186.     // (略)。。。  
  1. public class GeneralHelper  
  2. {  
  3.     /** 简单数据类型集合 */ 
  4.     public static final Set<Class<?>> SMIPLE_CLASS_SET    = new HashSet<Class<?>>(18);  
  5.  
  6.     static 
  7.     {  
  8.         SMIPLE_CLASS_SET.add(int.class);  
  9.         SMIPLE_CLASS_SET.add(long.class);  
  10.         SMIPLE_CLASS_SET.add(float.class);  
  11.         SMIPLE_CLASS_SET.add(double.class);  
  12.         SMIPLE_CLASS_SET.add(byte.class);  
  13.         SMIPLE_CLASS_SET.add(char.class);  
  14.         SMIPLE_CLASS_SET.add(short.class);  
  15.         SMIPLE_CLASS_SET.add(boolean.class);  
  16.         SMIPLE_CLASS_SET.add(Integer.class);  
  17.         SMIPLE_CLASS_SET.add(Long.class);  
  18.         SMIPLE_CLASS_SET.add(Float.class);  
  19.         SMIPLE_CLASS_SET.add(Double.class);  
  20.         SMIPLE_CLASS_SET.add(Byte.class);  
  21.         SMIPLE_CLASS_SET.add(Character.class);  
  22.         SMIPLE_CLASS_SET.add(Short.class);  
  23.         SMIPLE_CLASS_SET.add(Boolean.class);  
  24.         SMIPLE_CLASS_SET.add(String.class);  
  25.         SMIPLE_CLASS_SET.add(Date.class);  
  26.     }  
  27.  
  28.     /** 检查 clazz 是否为简单数据类型 */ 
  29.     public final static boolean isSimpleType(Class<?> clazz)  
  30.     {  
  31.         return SMIPLE_CLASS_SET.contains(clazz);  
  32.     }  
  33.  
  34.     /** String -> Any,如果 handler 为 null 则把字符串转换为 8 种基础数据类型、及其包装类、 {@link Date} 或 {@link String},  
  35.      *                   如果 handler 不为 null 则由 handler 执行转换   
  36.      *   
  37.      * @param type    : 目标类型的 {@link Class} 对象  
  38.      * @param v        : 要转换的字符串  
  39.      * @param handler    : 类型转换处理器  
  40.      * @return        : 转换结果,如果转换不成功返回 null  
  41.      * @throws         : 如果目标类型不支持抛出 {@link IllegalArgumentException}  
  42.      *   
  43.      */ 
  44.     @SuppressWarnings("unchecked")  
  45.     public static final <T> T str2Object(Class<T> type, String v, TypeHandler<T> handler)  
  46.     {  
  47.         Object param = null;  
  48.           
  49.         if(handler != null)  
  50.             return handler.handle(v);  
  51.           
  52.         if(type == String.class)  
  53.             param =  safeTrimString(v);  
  54.         else if(type == int.class)  
  55.             param =  str2Int_0(v);  
  56.         else if(type == long.class)  
  57.             param =  str2Long_0(v);  
  58.         else if(type == byte.class)  
  59.             param =  str2Byte_0(v);  
  60.         else if(type == char.class)  
  61.             param =  str2Char_0(v);  
  62.         else if(type == float.class)  
  63.             param =  str2Float_0(v);  
  64.         else if(type == double.class)  
  65.             param =  str2Double_0(v);  
  66.         else if(type == short.class)  
  67.             param =  str2Short_0(v);  
  68.         else if(type == boolean.class)  
  69.             param =  str2Boolean_False(v);  
  70.         else if(type == Integer.class)  
  71.             param =  str2Int(v);  
  72.         else if(type == Long.class)  
  73.             param =  str2Long(v);  
  74.         else if(type == Byte.class)  
  75.             param =  str2Byte(v);  
  76.         else if(type == Character.class)  
  77.             param =  str2Char(v);  
  78.         else if(type == Float.class)  
  79.             param =  str2Float(v);  
  80.         else if(type == Double.class)  
  81.             param =  str2Double(v);  
  82.         else if(type == Short.class)  
  83.             param =  str2Short(v);  
  84.         else if(type == Boolean.class)  
  85.             param =  str2Boolean(v);  
  86.         else if(Date.class.isAssignableFrom(type))  
  87.             param =  str2Date(v);  
  88.         else 
  89.             throw new IllegalArgumentException(String.format("object type '%s' not valid", type));  
  90.           
  91.         return (T)param;  
  92.     }  
  93.       
  94.     public static final <T> T str2Object(Class<T> type, String v)  
  95.     {  
  96.         return str2Object(type, v, null);  
  97.     }  
  98.       
  99.     // 其他方法  
  100.     // (略)。。。  

从上面的代码可以看出,BeanHelper 支持8种简单数据类型及其包装类、String 和 Date 类型以及它们的数组类型的自动装配,最后强调一下:BeanHelper 和 GeneralHelper 其实是两个用途非常广泛的类,其作用不单是为了协助 Form 表单域自动装配 Bean 。下面列出一些使用例子,帮助大家进一步了解 BeanHelper 的使用方法:

  1. package test;  
  2.    
  3.  import java.beans.IntrospectionException;  
  4.  import java.util.Date;  
  5.  import java.util.HashMap;  
  6.  import java.util.Map;  
  7.  import java.util.StringTokenizer;  
  8.    
  9.  import com.bruce.util.BeanHelper;  
  10.  import com.bruce.util.GeneralHelper;  
  11.    
  12.  @SuppressWarnings("unused")  
  13.  public class TestBeanHelper extends Object  
  14.  {  
  15.      public static void main(String[] args) throws Exception  
  16.      {  
  17.          test();  
  18.          testStr2Object();  
  19.          test_setProperty();  
  20.          test_setProperties_1();  
  21.          test_setProperties_2();  
  22.      }  
  23.    
  24.      private static void test()  
  25.      {  
  26.          //System.out.println(GeneralHelper.str2Date("  1978-11-03  "));  
  27.  //System.out.println(GeneralHelper.str2Date("  1978-11-03  "));  
  28.  //GeneralHelper.str2Byte(null);  
  29.  //GeneralHelper.str2Char_0(null);  
  30.  //GeneralHelper.str2Boolean(null);  
  31.  //GeneralHelper.str2Boolean_False(null);  
  32.      }  
  33.    
  34.      private static void testStr2Object() throws IntrospectionException  
  35.      {  
  36.          int i = GeneralHelper.str2Object(int.class"123");  
  37.          Date dt = GeneralHelper.str2Object(Date.class"1978-11-03");  
  38.          String[] arr = GeneralHelper.str2Object(String[].class"12, 34, 56, 78"new GeneralHelper.TypeHandler<String[]>()  
  39.          {  
  40.              @Override 
  41.              public String[] handle(String v)  
  42.              {  
  43.                  StringTokenizer st = new StringTokenizer(v, " ,;\t\r\n\f");  
  44.                  String[] result = new String[st.countTokens()];  
  45.                    
  46.                  for(int i = 0; st.hasMoreTokens(); i++)  
  47.                      result[i] = st.nextToken();  
  48.                    
  49.                  return result;  
  50.              }  
  51.          });  
  52.            
  53.          // !! error !!  
  54.  // String[] arr2 = GeneralHelper.str2Object(String[].class, "12, 34, 56, 78");  
  55.      }  
  56.    
  57.      private static void test_setProperty()  
  58.      {  
  59.          C c = new C();  
  60.          BeanHelper.setProperty(c, "dt""2010-10-10");  
  61.          BeanHelper.setProperty(c, "i"456);  
  62.          BeanHelper.setProperty(c, "l""999");  
  63.          int i = BeanHelper.getProperty(c, "i");  
  64.          double l = BeanHelper.getProperty(c, "l");  
  65.          boolean b = BeanHelper.getProperty(c, "b");  
  66.          Date dt = BeanHelper.getProperty(c, "dt");  
  67.          System.out.println(c);  
  68.      }  
  69.    
  70.      private static void test_setProperties_1() throws Exception  
  71.      {  
  72.          Map<String, String[]> objs = new HashMap<String, String[]>();  
  73.          objs.put("si"new String[] {"888"});  
  74.          objs.put("fi"new String[] {"999"});  
  75.          objs.put("b"new String[] {"true"});  
  76.          objs.put("i"new String[] {"1"});  
  77.          objs.put("l"new String[] {"2.3"});  
  78.          objs.put("dt"new String[] {"2011-09-17"});  
  79.          objs.put("__str"new String[] {"我是怪兽"});  
  80.          objs.put("__ia"new String[] {"12""34""56"});  
  81.          objs.put("__sa"new String[] {"ab""cd""ef"});  
  82.            
  83.          Map<String, String> keyMap = new HashMap<String, String>();  
  84.          keyMap.put("__str""str");  
  85.          keyMap.put("__ia""ia");  
  86.          keyMap.put("__sa""sa");  
  87.            
  88.          C c = BeanHelper.createBean(C.class, objs, keyMap);  
  89.          Map<String, Object> result = BeanHelper.getProperties(c);  
  90.          System.out.println(result);  
  91.      }  
  92.        
  93.      private static void test_setProperties_2() throws Exception  
  94.      {  
  95.          java.sql.Date dt = new java.sql.Date(new java.util.Date().getTime());  
  96.            
  97.          Map<String, Object> objs = new HashMap<String, Object>();  
  98.          objs.put("si"888);  
  99.          objs.put("fi"999);  
  100.          objs.put("b""True");  
  101.          objs.put("i"123);  
  102.          objs.put("l""2.3");  
  103.          //objs.put("dt", new String[] {"2011-09-17"});  
  104.          objs.put("dt", dt);  
  105.          objs.put("str""我是怪兽");  
  106.          objs.put("ia"new int[] {123456});  
  107.          objs.put("sa""ab, cd, ef");  
  108.            
  109.          C c = new C();  
  110.          BeanHelper.setProperties(c, objs);  
  111.          Map<String, Object> result = BeanHelper.getProperties(c);  
  112.          System.out.println(result);  
  113.      }  
  114.        
  115.        
  116.  } 
  1. package test;  
  2.    
  3.  import java.util.Date;  
  4.    
  5.    
  6.  class A  
  7.  {  
  8.      private boolean b;  
  9.    
  10.      public boolean isB()  
  11.      {  
  12.          return b;  
  13.      }  
  14.    
  15.      public void setB(boolean b)  
  16.      {  
  17.          this.b = b;  
  18.      }  
  19.    
  20.  }  
  21.    
  22.  public class C extends A  
  23.  {  
  24.      static int si;  
  25.      final int fi = 100;  
  26.        
  27.      private int i;  
  28.      private Double l;  
  29.      private Date dt;  
  30.      private String str;  
  31.      private int[] ia;  
  32.      private String[] sa;  
  33.    
  34.      public String[] getSa()  
  35.      {  
  36.          return sa;  
  37.      }  
  38.      public void setSa(String[] sa)  
  39.      {  
  40.          this.sa = sa;  
  41.      }  
  42.      public static int getSi()  
  43.      {  
  44.          return si;  
  45.      }  
  46.      public static void setSi(int si)  
  47.      {  
  48.          C.si = si;  
  49.      }  
  50.      public int getFi()  
  51.      {  
  52.          return fi;  
  53.      }  
  54.      public String getStr()  
  55.      {  
  56.          return str;  
  57.      }  
  58.      public void setStr(String str)  
  59.      {  
  60.          this.str = str;  
  61.      }  
  62.      public int[] getIa()  
  63.      {  
  64.          return ia;  
  65.      }  
  66.      public void setIa(int[] ia)  
  67.      {  
  68.          this.ia = ia;  
  69.      }  
  70.      public int getI()  
  71.      {  
  72.          return i;  
  73.      }  
  74.      public void setI(int i)  
  75.      {  
  76.          this.i = i;  
  77.      }  
  78.      public Double getL()  
  79.      {  
  80.          return l;  
  81.      }  
  82.      public void setL(Double l)  
  83.      {  
  84.          this.l = l;  
  85.      }  
  86.      public Date getDt()  
  87.      {  
  88.          return dt;  
  89.      }  
  90.      public void setDt(Date dt)  
  91.      {  
  92.          this.dt = dt;  
  93.      }      
  94.  } 

老规矩,想看完整代码者请轻轻 Touch 一下:  Source Code ^_^ 

原文链接:http://www.cnblogs.com/ldcsaa/archive/2012/02/16/2353030.html

【编辑推荐】

  1. Play!在云端:Java PaaS平台入门
  2. Java generic中通配符的几点理解
  3. Java中泛型创建数组的总结
  4. Java Socket超时浅析
  5. Java Socket重要参数讲解
责任编辑:林师授 来源: ~怪^_*兽~的博客
相关推荐

2015-11-30 11:14:59

C++对象池自动回收

2010-02-02 13:22:06

Python面向对象

2010-05-18 13:02:30

2010-03-01 17:40:29

Python面向对象语

2010-01-22 14:59:40

VB.NET表单自动提

2016-11-25 20:52:14

Linux

2023-02-21 15:26:26

自动驾驶特斯拉

2024-10-10 12:12:45

SpringAI版本

2009-10-22 10:10:20

VB.NET Proc

2010-01-06 10:42:18

JSON协议

2011-02-23 14:57:41

webweb开发HTML

2022-09-27 18:56:28

ArrayList数组源代码

2024-02-05 19:06:04

DartVMGC流程

2024-10-23 16:06:50

2022-08-08 07:33:11

自动装配Java容器

2012-05-11 10:38:15

Cloud Found

2010-01-08 14:06:49

JSON 形式

2010-03-01 16:48:02

Python模块

2016-12-06 10:39:54

剖析建模开源工具

2015-01-21 10:45:57

灾难恢复云应用云灾难恢复
点赞
收藏

51CTO技术栈公众号