目录
- 前言
- 1. 基本知识
- 2. 同属性Demo
- 3. 不同属性Demo
- 4. 实战场景
前言
基本知识推荐阅读:
- 浅拷贝和深拷贝的深度理解
- java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)
- 【Java项目】实战CRUD的功能整理(持续更新)
1. 基本知识
BeanCopier是一个Java库,用于在Java Bean之间进行属性复制,它可以自动将一个Java Bean对象的属性值复制到另一个Java Bean对象中,而无需手动编写属性复制的代码
作用 | 优点 | 缺点 |
---|---|---|
简化属性复制: BeanCopier能够自动将一个Java Bean对象的属性值复制到另一个Java Bean对象中,省去了手动编写属性复制代码的繁琐工作 提高效率: 由于BeanCopier利用了反射机制,因此能够实现高效的属性复制,避免了手动编写大量的getter和setter方法的耗时工作 灵活性: BeanCopier可以根据需求灵活地配置属性复制的行为,例如可以选择性地复制某些属性,或者自定义属性复制的规则 | 简单易用: BeanCopier提供了简单易用的API,使得属性复制变得非常简单 高效性能: 利用了反射机制,能够实现高效的属性复制,提高了程序的执行效率 灵活性: 可以根据需求灵活配置属性复制的行为,使得其适用于各种不同的场景 | 不支持复杂属性: BeanCopier虽然能够处理简单的属性复制,但是对于复杂的属性,例如嵌套对象或集合对象,可能需要额外的处理 不支持类型转换: BeanCopier在属性复制时不支持类型转换,如果源对象和目标对象的属性类型不一致,可能需要额外的类型转换处理 不支持属性名称不同的情况: 如果源对象和目标对象的属性名称不一致,BeanCopier无法自动匹配属性,需要手动指定属性映射关系 |
2. 同属性Demo
package com.example.test;
import org.springframework.cglib.beans.BeanCopier;
public class test {
static class SourceBean {
private String name;
private int age;
// getters and setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
static class TargetBean {
private String name;
private int age;
// getters and setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
public static void main(String[] args) {
// 创建BeanCopier对象
BeanCopier copier = BeanCopier.create(SourceBean.class, TargetBean.class, false);
// 创建源对象
SourceBean source = new SourceBean();
source.setName("码农研究僧");
source.setAge(18);
// 创建目标对象
TargetBean target = new TargetBean();
// 属性复制
copier.copy(source, target, null);
// 打印目标对象属性值
System.out.println("Name: " + target.getName()); // 输出:Name: John
System.out.println("Age: " + target.getAge()); // 输出:Age: 30
}
}
截图如下:
3. 不同属性Demo
这是不同属性,但不需要转换的Demo
package com.example.test;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
// 定义一个源对象类
class CheckOrder implements Serializable {
private String orderId;
public CheckOrder() {
}
public CheckOrder(String orderId) {
this.orderId = orderId;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
}
// 定义一个目标对象类,继承自源对象类
class CheckOrderVO extends CheckOrder implements Serializable {
private String orderName;
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
}
// 模拟BeanUtil工具类
class BeanUtil {
private static final Map<BeanCopierKey, BeanCopier> BEAN_COPIER_MAP = new HashMap<>();
public static <T> T copy(Object source, Class<T> clazz) {
return source == null ? null : copy(source, source.getClass(), clazz);
}
public static <T> T copy(Object source, Class sourceClazz, Class<T> targetClazz) {
if (source == null) {
return null;
} else {
BeanCopier copier = BeanCopier.create(sourceClazz, targetClazz, false);
T to = newInstance(targetClazz);
copier.copy(source, to, null);
return to;
}
}
public static <T> T newInstance(Class<T> clazz) {
try {
return clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
// 模拟BeanCopier类
class BeanCopier {
public static BeanCopier create(Class source, Class target, boolean useConverter) {
return create(source, target, useConverter, false);
}
public static BeanCopier create(Class source, Class target, boolean useConverter, boolean nonNull) {
return new BeanCopier();
}
public void copy(Object source, Object target, Object converter) {
if (source == null || target == null) {
throw new IllegalArgumentException("Source and target objects cannot be null.");
}
Field[] sourceFields = source.getClass().getDeclaredFields();
Field[] targetFields = target.getClass().getDeclaredFields();
Map<String, Field> targetFieldMap = new HashMap<>();
for (Field sourceField : sourceFields) {
sourceField.setAccessible(true);
targetFieldMap.put(sourceField.getName(), sourceField);
}
for (Field sourceField : sourceFields) {
sourceField.setAccessible(true);
Field targetField = targetFieldMap.get(sourceField.getName());
if (targetField != null && sourceField.getType().equals(targetField.getType())) {
try {
Object value = sourceField.get(source);
targetField.set(target, value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
System.out.println("Copying from " + source + " to " + target);
}
}
class BeanCopierKey {
private Class<?> source;
private Class<?> target;
private boolean useConverter;
private boolean nonNull;
public BeanCopierKey(Class<?> source, Class<?> target, boolean useConverter, boolean nonNull) {
this.source = source;
this.target = target;
this.useConverter = useConverter;
this.nonNull = nonNull;
}
public Class<?> getSource() {
return source;
}
public Class<?> getTarget() {
return target;
}
public boolean isUseConverter() {
return useConverter;
}
public boolean isNonNull() {
return nonNull;
}
}
public class Demo {
public static void main(String[] args) {
// 创建一个源对象
CheckOrder checkOrder = new CheckOrder("12345");
// 使用BeanUtil进行对象拷贝
CheckOrderVO checkOrderVOCopy = BeanUtil.copy(checkOrder, CheckOrderVO.class);
// 手动设置目标对象的属性
checkOrderVOCopy.setOrderName("码农研究僧");
// 输出拷贝后的目标对象的属性值
System.out.println("Copied order ID: " + checkOrderVOCopy.getOrderId());
// 因为目标对象类继承自源对象类,所以也可以访问源对象的属性
System.out.println("Copied order name: " + checkOrderVOCopy.getOrderName());
}
}
截图如下:
如果需要用到转换,可以看如下函数:
class BeanCopier {
public static BeanCopier create(Class source, Class target, boolean useConverter) {
return create(source, target, useConverter, false);
}
public static BeanCopier create(Class source, Class target, boolean useConverter, boolean nonNull) {
return new BeanCopier();
}
public void copy(Object source, Object target, Object converter) {
if (source == null || target == null) {
throw new IllegalArgumentException("Source and target objects cannot be null.");
}
Field[] sourceFields = source.getClass().getDeclaredFields();
Field[] targetFields = target.getClass().getDeclaredFields();
Map<String, Field> targetFieldMap = new HashMap<>();
for (Field targetField : targetFields) {
targetField.setAccessible(true);
targetFieldMap.put(targetField.getName(), targetField);
}
// 修改变动位置
Converter customConverter = (Converter) converter;
for (Field sourceField : sourceFields) {
sourceField.setAccessible(true);
Field targetField = targetFieldMap.get(sourceField.getName());
if (targetField != null && sourceField.getType().equals(targetField.getType())) {
try {
Object value = sourceField.get(source);
// 修改变动位置
if (customConverter != null) {
value = customConverter.convert(value, targetField.getType(), null);
}
targetField.set(target, value);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
System.out.println("Copying from " + source + " to " + target);
}
}
4. 实战场景
实战中的运用如下:
数据库的字段等都建立好了,并且其实体类如下:
使用过程中,可能还需要添加额外的字段,但又不影响到数据库,只想显示在前端而已,可以通过如下
最后结合工具类来复刻整个数据库拥有的属性,并添加新的字段值,并返回给前端操作