在 Spring 中使用 BeanUtils.copyProperties 複製特定字段
1. 概述
使用 Java 應用程式時,我們經常需要將資料從一個物件複製到另一個物件。 Spring Framework 的BeanUtils.copyProperties
是將屬性從一個 bean 複製到另一個 bean 的流行選擇。但是該方法預設複製所有匹配的屬性。
有時,我們需要複製特定的字段,例如當來源物件和目標物件具有不同的結構時,或者當我們只需要特定操作的字段子集時。為了複製特定字段而不是所有字段,我們需要自訂此行為。
在本教程中,我們將探討僅複製特定欄位及其範例的不同方法。
2.使用ignoreProperties
選項
copyProperties
方法允許第三個參數ignoreProperties,
它指定不應從來源物件複製到目標物件的欄位。我們可以將一個或多個屬性名稱作為可變參數傳遞以進行排除(例如address, age)
。
在這裡,我們將嘗試將屬性從SourceBean
複製到TargetBean:
public class SourceBean {
private String name;
private String address;
private int age;
// constructor and getters/setters here
}
public class TargetBean {
private String name;
private String address;
private int age;
// constructor and getters/setters here
}
讓我們看下面的例子,其中傳遞給BeanUtils.copyProperties
第三個參數address
表示**sourceBean
中的address
屬性不應該複製到****targetBean** :
public class BeanUtilsCopyPropertiesUnitTest {
@Test
public void givenObjects_whenUsingIgnoreProperties_thenCopyProperties() {
SourceBean sourceBean = new SourceBean("Peter", 30, "LA");
TargetBean targetBean = new TargetBean();
BeanUtils.copyProperties(sourceBean, targetBean, "address");
assertEquals(targetBean.getName(), sourceBean.getName());
assertEquals(targetBean.getAge(), sourceBean.getAge());
assertNull(targetBean.getAddress());
}
}
在上面的範例中, targetBean
物件中的address
欄位為null.
3. 使用自訂包裝器
我們可以建立一個實用方法,讓我們可以提及想要複製的特定欄位。此方法將包裝BeanUtils.copyProperties
並允許我們指定要複製的字段,同時排除其他字段:
public static void copySpecifiedProperties(Object source, Object target, Set<String> props) {
String[] excludedProperties = Arrays.stream(BeanUtils.getPropertyDescriptors(source.getClass()))
.map(PropertyDescriptor::getName)
.filter(name -> !props.contains(name))
.toArray(String[]::new);
BeanUtils.copyProperties(source, target, excludedProperties);
}
在下面的範例中,目標是將name
和age
欄位從sourceBean
複製到targetBean
,並排除複製address
欄位:
@Test
public void givenObjects_whenUsingCustomWrapper_thenCopyProperties() {
SourceBean sourceBean = new SourceBean("Peter", 30, "LA");
TargetBean targetBean = new TargetBean();
BeanUtilsCopyProperties .copySpecifiedProperties(sourceBean, targetBean, new HashSet<>(Arrays.asList("name", "age")));
assertEquals(targetBean.getName(), sourceBean.getName());
assertEquals(targetBean.getAge(), sourceBean.getAge());
assertNull(targetBean.getAddress());
}
4.使用中間 DTO 對象
這種方法涉及建立一個中間 DTO 對象,以便在將特定欄位複製到目標物件之前從來源物件中過濾它們。我們首先將欄位從來源物件複製到中間 DTO 對象,這是一個經過篩選的表示形式。然後,我們將過濾後的欄位從中間 DTO 物件複製到目標物件。
我們來看看中間物件TempDTO
的結構:
public class TempDTO {
public String name;
public int age;
}
現在,我們首先將特定欄位從sourceBean
複製到tempDTO,
然後從tempDTO
到targetBean:
@Test
public void givenObjects_whenUsingIntermediateObject_thenCopyProperties() {
SourceBean sourceBean = new SourceBean("Peter", 30, "LA");
TempDTO tempDTO = new TempDTO();
BeanUtils.copyProperties(sourceBean, tempDTO);
TargetBean targetBean = new TargetBean();
BeanUtils.copyProperties(tempDTO, targetBean);
assertEquals(targetBean.getName(), sourceBean.getName());
assertEquals(targetBean.getAge(), sourceBean.getAge());
assertNull(targetBean.getAddress());
}
5. 結論
在本文中,我們探討了使用 Java 中的BeanUtils.copyProperties
複製特定欄位的各種方法。 ignoreProperties
參數提供了一個簡單的解決方案,而自訂包裝器和中間物件方法為處理要忽略的長屬性清單提供了更大的靈活性。
中間物件方法運行速度稍慢,因為它執行兩次複製操作,但它確保關注點的乾淨分離,防止不必要的資料複製,並允許靈活和選擇性的欄位映射。
與往常一樣,本文中使用的程式碼可以在 GitHub 上找到。