上一篇内省(Introspector)讲到的是采用JavaAPI中的类来操作bean及其属性,而Apache也开源了第三方框架来简化和丰富了对bean属性的操作,这个框架就是BeanUtils。
使用BeanUtils记得先导入BeanUtils开发包,同时BeanUtils也需要将commons-logging一起导入,具体请看《配置BeanUtils包,同时也是对导入第三包的步骤说明》。
如果我们要设置某个bean的属性,直接使用setProperty(Object bean, String name, Object value)方法即可,第一个参数为要设置的对象,第二个参数为属性名称,第三个参数为属性值。下面是对一个Person这个Bean对象的操作:
1 Person p = new Person(); 2 BeanUtils.setProperty(p, "age", 25); 3 System.out.println(p.getAge());
输出:25
可以看到这个比属性描述器(PropertyDiscreptor)要简单快捷。
BeanUtils的功能不止这一点,它还能将字符串转换为基本数据类型。这点对于接收从表单来的数据(都是字符串)来说实在是太有用了,下面是一个简单的例子:
1 Person p = new Person(); 2 BeanUtils.setProperty(p, "age", "25"); 3 System.out.println(p.getAge());
在这个例子中,Person的age属性类型为“int”,而在调用setProperty 时使用的属性值为字符串,因此BeanUtils就将字符串”25”转换为了整数型25值。
最后再次声明,BeanUtils对于字符串的转换只支持八大基本数据类型!
但是如果在Person中有一个Date类型的属性,简单的BeanUtils是无法做到使某个“1991-7-1”字符串能转换成Date类型的,那么都说了BeanUtils功能很强大,因此可以使用BeanUtils包中的ConvertUtils注册一个转换器,使得字符串能够转换成日期Date类型。
要使用ConvertUtils注册转换器,只需调用register方法即可:
从register方法中可以看出,第二个参数是要转换成的最终目标类型,第一个参数必须是一个Converter类的实例,而我们继续看这个Converter,发现是一个接口,并且在这个接口中只有一个convert方法,因此我们可以使用匿名内部类来实现这个接口,并在实现方法中处理将字符串转换为日期Date类型。
1 Person p = new Person(); 2 ConvertUtils.register(new Converter() { 3 4 @Override 5 public <T> T convert(Class<T> type, Object value) { 6 if(value == null) { 7 return null; 8 } 9 if(!(value instanceof String)) { 10 throw new ConversionException("传入类型错误"); 11 } 12 String dateStr = (String) value; 13 if(dateStr.trim().equals("")) { 14 return null; 15 } 16 17 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); 18 try { 19 return (T)format.parse(dateStr); 20 } catch (ParseException e) { 21 throw new RuntimeException(e); 22 } 23 } 24 25 },Date.class); 26 27 BeanUtils.setProperty(p, "birthday", "1991-7-1"); 28 System.out.println(p.getBirthday());
输出:
当然上面我们使用的是自己来写这个接口,对于Apache的BeanUtils来说,Converter这个接口Apache已经帮我们写好了很多实现Converter接口的类了,因此我们可以使用这些现有的转换器类,比如有关日期的DateConverter或DateLocaleConverter。
对上面的代码进行修改:
1 ConvertUtils.register(new DateLocaleConverter(), Date.class); 2 3 Person p = new Person(); 4 BeanUtils.setProperty(p, "birthday", "1991-7-2"); 5 System.out.println(p.getBirthday());
输出:
可以看到现有的转换器实现类能使我们的功能变得代码简洁。
但是这样的转换器有时候并不能满足我们的需求,比如我们将日期字符串设置为空字符:
1 ConvertUtils.register(new DateLocaleConverter(), Date.class); 2 3 Person p = new Person(); 4 BeanUtils.setProperty(p, "birthday", ""); 5 System.out.println(p.getBirthday());
输出报错:
也就是这个转换器无法判断字符串为空的情况,直接抛出异常,健壮性不如自己写的转换器,当然有时候我们只需要有处理异常的情况也可以使用这个现有转换器,总之灵活应用。
BeanUtils还能将Map集合中的值填充某个对象中的属性,只要Map集合的Key与属性名相同,这点非常适合web中的Request将数据封装到某个bean中。
1 Map<String,String> map = new HashMap<>(); 2 map.put("name", "Ding"); 3 map.put("age", "25"); 4 map.put("birthday", "1991-7-1"); 5 ConvertUtils.register(new DateLocaleConverter(), Date.class); 6 Person p = new Person(); 7 8 BeanUtils.populate(p, map); 9 10 System.out.println(p.getName()); 11 System.out.println(p.getAge()); 12 System.out.println(p.getBirthday());
输出:
最后再说一次,要使用populate方法,Map集合的key值必须要和对象中的属性名一致才行!