commons - BeanUtils简介

jopen 12年前
     <p><span style="background-color:#ffffff;"><a href="/misc/goto?guid=4959500937909635109" target="_blank"><span class="hilite1">Beanutils</span></a>用了魔术般的反射技术,实现了很多夸张有用的功能,都是C/C++时代不敢想的。无论谁的项目,始终一天都会用得上它。我算是后知后觉了,第一回看到它的时候居然错过。   </span></p>    <p><span style="background-color:#ffffff;">  </span></p>    <p><span style="background-color:#ffffff;"><span class="number"><span style="color:#c00000;">1</span></span>.属性的动态getter,setter    </span></p>    <p><span style="background-color:#ffffff;">  </span></p>    <p><span style="background-color:#ffffff;">在这框架满天飞的年代,不能事事都保证执行getter,setter函数了,有时候属性是要需要根据名字动态取得的,就像这样:   </span></p>    <p><span style="background-color:#ffffff;"><span class="hilite1">BeanUtils</span>.getProperty(myBean,<span class="string"><span style="color:#0000ff;">"code"</span></span>);   </span></p>    <p><span style="background-color:#ffffff;">而<span class="hilite1">BeanUtils</span>更强的功能是直接访问内嵌对象的属性,只要使用点号分隔。   </span></p>    <p><span style="background-color:#ffffff;"><span class="hilite1">BeanUtils</span>.getProperty(orderBean, <span class="string"><span style="color:#0000ff;">"address.city"</span></span>);   </span></p>    <p><span style="background-color:#ffffff;">相比之下其他类库的<span class="hilite1">BeanUtils</span>通常都很简单,不能访问内嵌的对象,所以经常要用Commons <span class="hilite1">BeanUtils</span>替换它们。   </span></p>    <p><span style="background-color:#ffffff;"><span class="hilite1">BeanUtils</span>还支持List和Map类型的属性。如下面的语法即可取得顾客列表中第一个顾客的名字   </span></p>    <p><span style="background-color:#ffffff;"><span class="hilite1">BeanUtils</span>.getProperty(orderBean, <span class="string"><span style="color:#0000ff;">"customers[1].name"</span></span>);   </span></p>    <p><span style="background-color:#ffffff;">其中<span class="hilite1">BeanUtils</span>会使用ConvertUtils类把字符串转为Bean属性的真正类型,方便从HttpServletRequest等对象中提取bean,或者把bean输出到页面。   </span></p>    <p><span style="background-color:#ffffff;">而PropertyUtils就会原色的保留Bean原来的类型。   </span></p>    <p><span style="background-color:#ffffff;"><span class="number"><span style="color:#c00000;">2</span></span>.beanCompartor 动态排序    </span></p>    <p><span style="background-color:#ffffff;">  </span></p>    <p><span style="background-color:#ffffff;">还是通过反射,动态设定Bean按照哪个属性来排序,而不再需要在bean的Compare接口进行复杂的条件判断。    </span></p>    <p><span style="background-color:#ffffff;">List peoples = ...; <span class="comment"><span style="color:#008200;">// Person对象的列表 </span></span>  </span></p>    <p><span style="background-color:#ffffff;">Collections.sort(peoples, <span class="keyword"><strong><span style="color:#7f0055;">new</span></strong></span> BeanComparator(<span class="string"><span style="color:#0000ff;">"age"</span></span>));   </span></p>    <p><span style="background-color:#ffffff;">  </span></p>    <p><span style="background-color:#ffffff;">如果要支持多个属性的复合排序,如<span class="string"><span style="color:#0000ff;">"Order By lastName,firstName"</span></span>    </span></p>    <p><span style="background-color:#ffffff;">  </span></p>    <p><span style="background-color:#ffffff;">ArrayList sortFields = <span class="keyword"><strong><span style="color:#7f0055;">new</span></strong></span> ArrayList();   </span></p>    <p><span style="background-color:#ffffff;">sortFields.add(<span class="keyword"><strong><span style="color:#7f0055;">new</span></strong></span> BeanComparator(<span class="string"><span style="color:#0000ff;">"lastName"</span></span>));   </span></p>    <p><span style="background-color:#ffffff;">sortFields.add(<span class="keyword"><strong><span style="color:#7f0055;">new</span></strong></span> BeanComparator(<span class="string"><span style="color:#0000ff;">"firstName"</span></span>));   </span></p>    <p><span style="background-color:#ffffff;">ComparatorChain multiSort = <span class="keyword"><strong><span style="color:#7f0055;">new</span></strong></span> ComparatorChain(sortFields);   </span></p>    <p><span style="background-color:#ffffff;">Collections.sort(rows,multiSort);   </span></p>    <p><span style="background-color:#ffffff;">  </span></p>    <p><span style="background-color:#ffffff;">其中ComparatorChain属于jakata commons-collections包。   </span></p>    <p><span style="background-color:#ffffff;">如果age属性不是普通类型,构造函数需要再传入一个comparator对象为age变量排序。   </span></p>    <p><span style="background-color:#ffffff;">另外, BeanCompartor本身的ComparebleComparator, 遇到属性为<span class="keyword"><strong><span style="color:#7f0055;">null</span></strong></span>就会抛出异常, 也不能设定升序还是降序。   </span></p>    <p><span style="background-color:#ffffff;">这个时候又要借助commons-collections包的ComparatorUtils.   </span></p>    <p><span style="background-color:#ffffff;">  </span></p>    <p><span style="background-color:#ffffff;">   Comparator mycmp = ComparableComparator.getInstance();   </span></p>    <p><span style="background-color:#ffffff;">   mycmp = ComparatorUtils.nullLowComparator(mycmp);  <span class="comment"><span style="color:#008200;">//允许null </span></span>  </span></p>    <p><span style="background-color:#ffffff;">   mycmp = ComparatorUtils.reversedComparator(mycmp); <span class="comment"><span style="color:#008200;">//逆序 </span></span>  </span></p>    <p><span style="background-color:#ffffff;">   Comparator cmp = <span class="keyword"><strong><span style="color:#7f0055;">new</span></strong></span> BeanComparator(sortColumn, mycmp);   </span></p>    <p><span style="background-color:#ffffff;">  </span></p>    <p><span style="background-color:#ffffff;"><span class="number"><span style="color:#c00000;">3</span></span>.Converter 把Request或ResultSet中的字符串绑定到对象的属性    </span></p>    <p><span style="background-color:#ffffff;">   经常要从request,resultSet等对象取出值来赋入bean中,下面的代码谁都写腻了,如果不用MVC框架的绑定功能的话。   </span></p>    <p><span style="background-color:#ffffff;">  </span></p>    <p><span style="background-color:#ffffff;">   String a = request.getParameter(<span class="string"><span style="color:#0000ff;">"a"</span></span>);   </span></p>    <p><span style="background-color:#ffffff;">   bean.setA(a);   </span></p>    <p><span style="background-color:#ffffff;">   String b = ....   </span></p>    <p><span style="background-color:#ffffff;">  </span></p>    <p><span style="background-color:#ffffff;">不妨写一个Binder:   </span></p>    <p><span style="background-color:#ffffff;">  </span></p>    <p><span style="background-color:#ffffff;">     MyBean bean = ...;   </span></p>    <p><span style="background-color:#ffffff;">    HashMap map = <span class="keyword"><strong><span style="color:#7f0055;">new</span></strong></span> HashMap();   </span></p>    <p><span style="background-color:#ffffff;">    Enumeration names = request.getParameterNames();   </span></p>    <p><span style="background-color:#ffffff;">    <span class="keyword"><strong><span style="color:#7f0055;">while</span></strong></span> (names.hasMoreElements())   </span></p>    <p><span style="background-color:#ffffff;">    {   </span></p>    <p><span style="background-color:#ffffff;">      String name = (String) names.nextElement();   </span></p>    <p><span style="background-color:#ffffff;">      map.put(name, request.getParameterValues(name));   </span></p>    <p><span style="background-color:#ffffff;">    }   </span></p>    <p><span style="background-color:#ffffff;">    <span class="hilite1">BeanUtils</span>.populate(bean, map);   </span></p>    <p><span style="background-color:#ffffff;">    其中<span class="hilite1">BeanUtils</span>的populate方法或者getProperty,setProperty方法其实都会调用convert进行转换。   </span></p>    <p><span style="background-color:#ffffff;">    但Converter只支持一些基本的类型,甚至连java.util.Date类型也不支持。而且它比较笨的一个地方是当遇到不认识的类型时,居然会抛出异常来。   </span></p>    <p><span style="background-color:#ffffff;">    对于Date类型,我参考它的sqldate类型实现了一个Converter,而且添加了一个设置日期格式的函数。   </span></p>    <p><span style="background-color:#ffffff;">要把这个Converter注册,需要如下语句:   </span></p>    <p><span style="background-color:#ffffff;">  </span></p>    <p><span style="background-color:#ffffff;">  </span></p>    <p><span style="background-color:#ffffff;">    ConvertUtilsBean convertUtils = <span class="keyword"><strong><span style="color:#7f0055;">new</span></strong></span> ConvertUtilsBean();    DateConverter dateConverter = <span class="keyword"><strong><span style="color:#7f0055;">new</span></strong></span> DateConverter();    convertUtils.register(dateConverter,Date.<span class="keyword"><strong><span style="color:#7f0055;">class</span></strong></span>);     <span class="comment"><span style="color:#008200;">//因为要注册converter,所以不能再使用</span><span class="hilite1">BeanUtils</span><span style="color:#008200;">的静态方法了,必须创建BeanUtilsBean实例    BeanUtilsBean </span><span class="hilite1">beanUtils</span><span style="color:#008200;"> = new BeanUtilsBean(convertUtils,new PropertyUtilsBean());    </span><span class="hilite1">beanUtils</span><span style="color:#008200;">.setProperty(bean, name, value); </span></span>  </span></p>    <p><span style="background-color:#ffffff;"><span class="number"><span style="color:#c00000;">4</span></span> 其他功能    </span></p>    <p><span style="background-color:#ffffff;"><span class="number"><span style="color:#c00000;">4.1</span></span> PropertyUtils,当属性为Collection,Map时的动态读取:   </span></p>    <p><span style="background-color:#ffffff;">    </span></p>    <p><span style="background-color:#ffffff;">Collection: 提供index   </span></p>    <p><span style="background-color:#ffffff;">   <span class="hilite1">BeanUtils</span>.getIndexedProperty(orderBean,<span class="string"><span style="color:#0000ff;">"items"</span></span>,<span class="number"><span style="color:#c00000;">1</span></span>);   </span></p>    <p><span style="background-color:#ffffff;">或者   </span></p>    <p><span style="background-color:#ffffff;">  <span class="hilite1">BeanUtils</span>.getIndexedProperty(orderBean,<span class="string"><span style="color:#0000ff;">"items[1]"</span></span>);   </span></p>    <p><span style="background-color:#ffffff;">  </span></p>    <p><span style="background-color:#ffffff;">Map: 提供Key Value   </span></p>    <p><span style="background-color:#ffffff;">  <span class="hilite1">BeanUtils</span>.getMappedProperty(orderBean, <span class="string"><span style="color:#0000ff;">"items"</span></span>,<span class="string"><span style="color:#0000ff;">"111"</span></span>);<span class="comment"><span style="color:#008200;">//key-value goods_no=111  </span></span>  </span></p>    <p><span style="background-color:#ffffff;">或者   </span></p>    <p><span style="background-color:#ffffff;">  <span class="hilite1">BeanUtils</span>.getMappedProperty(orderBean, <span class="string"><span style="color:#0000ff;">"items(111)"</span></span>)    </span></p>    <p><span style="background-color:#ffffff;">    </span></p>    <p><span style="background-color:#ffffff;"><span class="number"><span style="color:#c00000;">4.2</span></span> PropertyUtils,获取属性的Class类型   </span></p>    <p><span style="background-color:#ffffff;">     <span class="keyword"><strong><span style="color:#7f0055;">public</span></strong></span> <span class="keyword"><strong><span style="color:#7f0055;">static</span></strong></span> Class getPropertyType(Object bean, String name)   </span></p>    <p><span style="background-color:#ffffff;">    </span></p>    <p><span style="background-color:#ffffff;"><span class="number"><span style="color:#c00000;">4.3</span></span> ConstructorUtils,动态创建对象   </span></p>    <p><span style="background-color:#ffffff;">      <span class="keyword"><strong><span style="color:#7f0055;">public</span></strong></span> <span class="keyword"><strong><span style="color:#7f0055;">static</span></strong></span> Object invokeConstructor(Class klass, Object arg)   </span></p>    <p><span style="background-color:#ffffff;"><span class="number"><span style="color:#c00000;">4.4</span></span> MethodUtils,动态调用方法   </span></p>    <p><span style="background-color:#ffffff;">    MethodUtils.invokeMethod(bean, methodName, parameter);   </span></p>    <p><span style="background-color:#ffffff;"><span class="number"><span style="color:#c00000;">4.5</span></span> 动态Bean 见用DynaBean减除不必要的VO和FormBean <br /> </span></p>