commons - BeanUtils简介
jopen
13年前
<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>