前言:

我们在开发中会经常遇到对象之间属性的copy,笨一点的可以取出来对象的属性值再给另一个对象赋值,但这并不优雅,代码也不够简洁。所以我们会用到一些copy属性的工具类,比如Spring的BeanUtils,但是原本的Spring的BeanUtils要求copy的属性要大小写一致,但实际开发中两个对象的字段大小写可能不一样,因此可以对本spring提供的工具类BeanUtils进行进一步封装,这篇博客就是分享的封装后的BeanUtils。

正文:

一、首先我们先看下Spring的BeanUtils容易出现的坑

1.对象属性只有首字母大小写不一致的情况,是不影响属性拷贝的

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String name;
private String sex;
private String age;
private String phone;
private String email;
}@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserTwo {
private String Name;
private String Sex;
private String age;
private String phone;
private String email;
}public static void main(String[] args) {
User user = new User();
user.setName("阿达");
user.setSex("男");
UserTwo userTwo = new UserTwo();
System.out.println(user.toString());
System.out.println(userTwo.toString());
BeanUtils.copyProperties(user, userTwo);
System.out.println(userTwo.toString());
}

运行结果:都拷贝成功

User(name=阿达, sex=男, age=null, phone=null, email=null)

UserTwo(Name=null, Sex=null, age=null, phone=null, email=null)

UserTwo(Name=阿达, Sex=男, age=null, phone=null, email=null)

2.对象属性多个字母大小写不一致,影响属性的拷贝@Data

@AllArgsConstructor
@NoArgsConstructor
public class User {
private String sex;
private String age;
private String phone;
private String email;
}@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserTwo {
private String Sex;
private String age;
private String phone;
private String email;
}public static void main(String[] args) {
User user = new User();
user.setNameda("阿达");
user.setSex("男");
System.out.println(user.toString());
UserTwo userTwo = new UserTwo();
System.out.println(userTwo.toString());
BeanUtils.copyProperties(user, userTwo);
System.out.println(userTwo.toString());
}

运行结果:名字属性就没有拷贝成功

User(nameda=阿达, sex=男, age=null, phone=null, email=null)
UserTwo(NameDa=null, Sex=null, age=null, phone=null, email=null)
UserTwo(NameDa=null, Sex=男, age=null, phone=null, email=null)

3.源对象的属性是null值而目标对象对应的属性有值,结果一复制,就给覆盖啦,使得目标对象的属性变成null

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String sex;
private String age;
private String phone;
private String email;
}@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserTwo {
private String Sex;
private String age;
private String phone;
private String email;
}public static void main(String[] args) {
User user = new User();
user.setNameda("阿达");
user.setSex("男");
System.out.println(user.toString());
UserTwo userTwo = new UserTwo();
userTwo.setEmail("ada@126.com");
System.out.println(userTwo.toString());
BeanUtils.copyProperties(user, userTwo);
System.out.println(userTwo.toString());
}

运行结果:源对象属性为null,目标对象对应的字段属性值丢失User(nameda=阿达, sex=男, age=null, phone=null, email=null)

UserTwo(NameDa=null, Sex=null, age=null, phone=null, email=ada@126.com)
UserTwo(NameDa=null, Sex=男, age=null, phone=null, email=null)

二、为了避免上面的坑我们模仿Spring的BeanUtils封装一个工具类BeanUtil

1.需要引入的依赖

org.apache.commons
commons-lang3

3.4

2.封装好的工具类ublic class BeanUtil{

/**
* 大小写可以忽略
* 下划线 _ 被忽略
* NULL值和空字符串不会覆盖新值
*
* @param source
* @param target
* @param 
* @return
*/
public static  T copyPropertiesIgnoreCase(Object source, Object target) {
Map sourceMap = CacheFieldMap.getFieldMap(source.getClass());
CacheFieldMap.getFieldMap(target.getClass()).values().forEach((it) -> {
Field field = sourceMap.get(it.getName().toLowerCase().replace("_", ""));
if (field != null) {
it.setAccessible(true);
field.setAccessible(true);
try {
//忽略null和空字符串
if(field.get(source)!=null&&StringUtils.isBlank(field.get(source).toString()))
it.set(target, field.get(source));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
});
System.out.println(target.toString());
return (T) target;
}
private static class CacheFieldMap {
private static Map> cacheMap = new HashMap<>();
private static Map getFieldMap(Class clazz) {
Map result = cacheMap.get(clazz.getName());
if (result == null) {
synchronized (CacheFieldMap.class) {
if (result == null) {
Map fieldMap = new HashMap<>();
for (Field field : clazz.getDeclaredFields()) {
fieldMap.put(field.getName().toLowerCase().replace("_", ""), field);
}
cacheMap.put(clazz.getName(), fieldMap);
result = cacheMap.get(clazz.getName());
}
}
}
return result;
}
}

3.测试代码

public static void main(String[] args) {
User user = new User();
user.setNameda("阿达");
user.setSex("男");
System.out.println(user.toString());
UserTwo userTwo = new UserTwo();
userTwo.setEmail("ada@126.com");
System.out.println(userTwo.toString());
BeanUtil.copyPropertiesIgnoreCase(user, userTwo);
System.out.println(userTwo.toString());
}

运行结果:都拷贝成功且null值没有覆盖User(nameda=阿达, sex=男, age=null, phone=null, email=null)

UserTwo(NameDa=null, Sex=null, age=null, phone=null, email=ada@126.com)
UserTwo(NameDa=阿达, Sex=男, age=null, phone=null, email=ada@126.com)

总结:

使用工具类的时候一定要注意各种坑的存在,认真检查小细节。

我是阿达,一名喜欢分享知识的程序员,时不时的也会荒腔走板的聊一聊电影、电视剧、音乐、漫画,这里将来会有N位小伙伴在等你们,感兴趣的就赶紧来点击关注我把,哪里有不明白或有不同观点的地方欢迎留言。