參考一
what?
BeanUtils它提供了對java反射和自省API的包裝。它里面還有很多工具類,這里我們介紹一下copyProperties。
why?
我們如果有兩個具有很多相同屬性的JavaBean,一個很常見的情況就是Struts里的PO對象(持久對象)和對應的ActionForm,傳統的方式對屬性逐個賦值:
如果按照上面那種賦值方式,是非常麻煩的,而且代碼梁可以估計會很多
How?
這時候我們如果用copyProperties,直接一行代碼,然后就搞定了。
例如:
但是有幾點我們需要注意:
BeanUtils.copyProperties(a, b);
b中的存在的屬性,a中一定要有,但是a中可以有多余的屬性;
a中與b中相同的屬性都會被替換,不管是否有值;
a、 b中的屬性要名字相同,才能被賦值,不然的話需要手動賦值;
Spring的BeanUtils的CopyProperties方法需要對應的屬性有getter和setter方法;
如果存在屬性完全相同的內部類,但是不是同一個內部類,即分別屬於各自的內部類,則spring會認為屬性不同,不會copy;
spring和apache的copy屬性的方法源和目的參數的位置正好相反,所以導包和調用的時候都要注意一下。
參考二:
1、簡介
BeanUtils提供對Java反射和自省API的包裝。其主要目的是利用反射機制對JavaBean的屬性進行處理。
2、用法
如果有兩個具有很多相同屬性的JavaBean,一個很常見的情況就是Struts里的PO對象(持久對象)和對應的ActionForm。例如:一個用戶注冊頁面,有一個User實體類和一個UserActionForm實體類,我們一般會在Action里從ActionForm構造一個PO對象,傳統的方式是使用類似下面的語句對屬性逐個賦值:
// 獲取 ActionForm 表單數據 UserActionForm uForm = (UserActionForm) form; // 構造一個User對象 User user = new User(); // 逐一賦值 user.setUsername(uForm.getUsername); user.setPassword(uForm.getPassword); user.setAge(uForm.getAge); ........... ........... // 然后調用JDBC、或操作Hibernate 持久化對象User到數據庫 ...
通過這樣的方法如果表單屬性字段很多,達到了100、1000甚至更多,那我們不是要寫100、1000行set、get了。誰都不願意這樣做。
而我們使用 BeanUtils.copyProperties() 方法以后,代碼量大大的減少,而且整體程序看着也簡潔明朗,代碼如下:
// 獲取 ActionForm 表單數據 UserActionForm uForm = (UserActionForm) form; // 構造一個User對象 User user = new User(); // 賦值 BeanUtils.copyProperties(user, uForm); // 然后調用JDBC、或操作Hibernate 持久化對象User到數據庫 .......
注:如果User和UserActionForm 間存在名稱不相同的屬性,則BeanUtils不對這些屬性進行處理,需要手動處理。例如:
User類里面有個createDate 創建時間字段,而UserActionForm里面無此字段。BeanUtils.copyProperties()不會對此字段做任何處理。必須要自己手動處理。
用法總結如下:
[java] view plain copy print? BeanUtils.copyProperties("要轉換的類", "轉換后的類"); [java] view plain copy print? PropertyUtils.copyProperties("要轉換的類", "轉換后的類");
用法其實很簡單,第一個參數是要轉換的類,第二個參數是轉換后的類。
BeanUtils.copyProperties VS PropertyUtils.copyProperties
兩者最大的區別是:
BeanUtils.copyProperties會進行類型轉換,而PropertyUtils.copyProperties不會。
既然進行了類型轉換,那BeanUtils.copyProperties的速度比不上PropertyUtils.copyProperties。
因此,PropertyUtils.copyProperties應用的范圍稍為窄一點,它只對名字和類型都一樣的屬性進行copy,如果名字一樣但類型不一樣,它會報錯。
使用BeanUtils有幾個要注意的地方:
1.對於類型為Boolean/Short/Integer/Float/Double的屬性,它會轉換為0:
public class User { private Integer intVal; private Double doubleVal; private Short shortVal; private Long longVal; private Float floatVal; private Byte byteVal; private Boolean booleanVal; } User src = new User(); User dest = new User(); BeanUtils.copyProperties(dest, src); System.out.println(src); System.out.println(dest); //輸出 User [intVal=null, doubleVal=null, shortVal=null, longVal=null, floatVal=null, byteVal=null, booleanVal=null] User [intVal=0, doubleVal=0.0, shortVal=0, longVal=0, floatVal=0.0, byteVal=0, booleanVal=false]
在stackoverflow上有人解釋說是因為這幾個類型都有對應的基本類型,在進行類型轉換時,有可能遇到類似Integer -> int的轉換,此時顯然不能對int類型的屬性賦值為null,因此統一轉換為0。
如何讓它不要轉為0呢?可以這樣:
import org.apache.commons.beanutils.converters.IntegerConverter; IntegerConverter converter = new IntegerConverter(null); //默認為null,而不是0 BeanUtilsBean beanUtilsBean = new BeanUtilsBean(); beanUtilsBean.getConvertUtils().register(converter, Integer.class);
2.對於java.util.Date/BigDecimal/java.sql.Date/java.sql.Timestamp/java.sql.Time這幾個類,如果值為null,則在copy時會拋異常,需要使用對應的Conveter:
public class User2 { private java.util.Date javaUtilDateVal; private java.sql.Date javaSqlDateVal; private java.sql.Timestamp javaSqlTimeStampVal; private BigDecimal bigDecimalVal; private java.sql.Time javaSqlTime; } User2 src = new User2(); User2 dest = new User2(); BeanUtilsBean beanUtilsBean = new BeanUtilsBean(); //如果沒有下面幾行,則在轉換null時會拋異常,例如:org.apache.commons.beanutils.ConversionException: No value specified for 'BigDecimal' //在org.apache.commons.beanutils.converters這個包下面有很多的Converter,可以按需要使用 beanUtilsBean.getConvertUtils().register(new org.apache.commons.beanutils.converters.BigDecimalConverter(null), BigDecimal.class); beanUtilsBean.getConvertUtils().register(new org.apache.commons.beanutils.converters.DateConverter(null), java.util.Date.class); beanUtilsBean.getConvertUtils().register(new org.apache.commons.beanutils.converters.SqlTimestampConverter(null), java.sql.Timestamp.class); beanUtilsBean.getConvertUtils().register(new org.apache.commons.beanutils.converters.SqlDateConverter(null), java.sql.Date.class); beanUtilsBean.getConvertUtils().register(new org.apache.commons.beanutils.converters.SqlTimeConverter(null), java.sql.Time.class); beanUtilsBean.copyProperties(dest, src); System.out.println(src); System.out.println(dest);
使用BeanUtils還會經常碰到這樣變態的需求:
假設是從A復制到B:
需求1:如果B中某字段有值(不為null),則該字段不復制;也就是B中該字段沒值時,才進行復制,適合於對B進行補充值的情況。
需求2:如果A中某字段沒值(為null),則該字段不復制,也就是不要把null復制到B當中。
對於需求1,可以這樣:
import org.apache.commons.beanutils.BeanUtilsBean; import org.apache.commons.beanutils.PropertyUtils; public class CopyWhenNullBeanUtilsBean extends BeanUtilsBean{ @Override public void copyProperty(Object bean, String name, Object value) throws IllegalAccessException, InvocationTargetException { try { Object destValue = PropertyUtils.getSimpleProperty(bean, name); if (destValue == null) { super.copyProperty(bean, name, value); } } catch (NoSuchMethodException e) { throw new RuntimeException(e); } } }
對於需求2,可以這樣:
import org.apache.commons.beanutils.BeanUtilsBean; public class CopyFromNotNullBeanUtilsBean extends BeanUtilsBean { @Override public void copyProperty(Object bean, String name, Object value) throws IllegalAccessException, InvocationTargetException { if (value == null) { return; } super.copyProperty(bean, name, value); } }
參考:
https://blog.csdn.net/dfshsdr/article/details/90513676
https://www.jb51.net/article/186524.htm
import
org.apache.commons.beanutils.BeanUtilsBean;
public
class
CopyFromNotNullBeanUtilsBean
extends
BeanUtilsBean {
@Override
public
void
copyProperty(Object bean, String name, Object value)
throws
IllegalAccessException, InvocationTargetException {
if
(value ==
null
) {
return
;
}
super
.copyProperty(bean, name, value);
}
}