原文文章: https://blog.csdn.net/luliuliu1234/article/details/84141595
相同属性名时转换:
import org.springframework.beans.BeanUtils; test1 a = new test1(); test2 b = new test2(); BeanUtils.copyProperties(a, b);
封装的Beanutils:
1 package com.zhiwei.common.utils.bean; 2 3 import java.lang.reflect.Method; 4 import java.util.ArrayList; 5 import java.util.List; 6 import java.util.regex.Matcher; 7 import java.util.regex.Pattern; 8 9 /** 10 * Bean 工具类 11 * 12 * @author zhiwei 13 */ 14 public class BeanUtils extends org.springframework.beans.BeanUtils { 15 /** 16 * Bean方法名中属性名开始的下标 17 */ 18 private static final int BEAN_METHOD_PROP_INDEX = 3; 19 20 /** 21 * 匹配getter方法的正则表达式 22 */ 23 private static final Pattern GET_PATTERN = Pattern.compile("get(\p{javaUpperCase}\w*)"); 24 25 /** 26 * 匹配setter方法的正则表达式 27 */ 28 private static final Pattern SET_PATTERN = Pattern.compile("set(\p{javaUpperCase}\w*)"); 29 30 /** 31 * Bean属性复制工具方法。 32 * 33 * @param dest 目标对象 34 * @param src 源对象 35 */ 36 public static void copyBeanProp(Object dest, Object src) { 37 try { 38 copyProperties(src, dest); 39 } catch (Exception e) { 40 e.printStackTrace(); 41 } 42 } 43 44 /** 45 * 获取对象的setter方法。 46 * 47 * @param obj 对象 48 * @return 对象的setter方法列表 49 */ 50 public static List<Method> getSetterMethods(Object obj) { 51 // setter方法列表 52 List<Method> setterMethods = new ArrayList<Method>(); 53 54 // 获取所有方法 55 Method[] methods = obj.getClass().getMethods(); 56 57 // 查找setter方法 58 59 for (Method method : methods) { 60 Matcher m = SET_PATTERN.matcher(method.getName()); 61 if (m.matches() && (method.getParameterTypes().length == 1)) { 62 setterMethods.add(method); 63 } 64 } 65 // 返回setter方法列表 66 return setterMethods; 67 } 68 69 /** 70 * 获取对象的getter方法。 71 * 72 * @param obj 对象 73 * @return 对象的getter方法列表 74 */ 75 76 public static List<Method> getGetterMethods(Object obj) { 77 // getter方法列表 78 List<Method> getterMethods = new ArrayList<Method>(); 79 // 获取所有方法 80 Method[] methods = obj.getClass().getMethods(); 81 // 查找getter方法 82 for (Method method : methods) { 83 Matcher m = GET_PATTERN.matcher(method.getName()); 84 if (m.matches() && (method.getParameterTypes().length == 0)) { 85 getterMethods.add(method); 86 } 87 } 88 // 返回getter方法列表 89 return getterMethods; 90 } 91 92 /** 93 * 检查Bean方法名中的属性名是否相等。<br> 94 * 如getName()和setName()属性名一样,getName()和setAge()属性名不一样。 95 * 96 * @param m1 方法名1 97 * @param m2 方法名2 98 * @return 属性名一样返回true,否则返回false 99 */ 100 101 public static boolean isMethodPropEquals(String m1, String m2) { 102 return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX)); 103 } 104 }
不同属性名时转换:
两种方式,第一种 使用cglib进行动态生成,缺点: 需要手动维护映射关系。
第二种 java8函数式接口,缺点: 不同bean之间进行转换就需要写一个转换方法
第一种方式:
首先加入依赖:
1 <dependency> 2 <groupId>asm</groupId> 3 <artifactId>asm</artifactId> 4 <version>3.3.1</version> 5 </dependency> 6 <dependency> 7 <groupId>asm</groupId> 8 <artifactId>asm-commons</artifactId> 9 <version>3.3.1</version> 10 </dependency> 11 <dependency> 12 <groupId>asm</groupId> 13 <artifactId>asm-util</artifactId> 14 <version>3.3.1</version> 15 </dependency> 16 <dependency> 17 <groupId>cglib</groupId> 18 <artifactId>cglib-nodep</artifactId> 19 <version>2.2.2</version> 20 </dependency>
CglibBean:
1 package com.zhiwei.common.utils.bean; 2 3 import org.springframework.cglib.beans.BeanGenerator; 4 import org.springframework.cglib.beans.BeanMap; 5 6 import java.util.Iterator; 7 import java.util.Map; 8 import java.util.Set; 9 10 /** 11 * CglibBean class 12 * 13 * @author zhiwei 14 * @date 2020/09/28 15 */ 16 public class CglibBean { 17 /** 18 * 实体Object 19 */ 20 public Object object = null; 21 /** 22 * 属性map 23 */ 24 public BeanMap beanMap = null; 25 26 public CglibBean() { 27 } 28 29 public CglibBean(Map<String, Class> propertyMap) { 30 this.object = generateBean(propertyMap); 31 this.beanMap = BeanMap.create(this.object); 32 } 33 34 /** 35 * 给bean属性赋值 36 * 37 * @param property 38 * @param value 39 */ 40 public void setValue(String property, Object value) { 41 beanMap.put(property, value); 42 } 43 44 /** 45 * 通过属性名得到属性值 46 * 47 * @param property 48 * @return 49 */ 50 public Object getValue(String property) { 51 return beanMap.get(property); 52 } 53 54 /** 55 * 得到该实体bean对象 56 * 57 * @return 58 */ 59 public Object getObject() { 60 return this.object; 61 } 62 63 /** 64 * 创建cglib动态代理的bean 65 * 66 * @param propertyMap 通过map创建 67 * @return 返回bean对象 68 */ 69 @SuppressWarnings("rawtypes") 70 private Object generateBean(Map<String, Class> propertyMap) { 71 BeanGenerator generator = new BeanGenerator(); 72 Set keySet = propertyMap.keySet(); 73 for (Iterator i = keySet.iterator(); i.hasNext(); ) { 74 String key = (String) i.next(); 75 generator.addProperty(key, (Class) propertyMap.get(key)); 76 } 77 return generator.create(); 78 } 79 }
CglibBeanUtils:
1 package com.zhiwei.common.utils.bean; 2 3 import com.fasterxml.jackson.databind.DeserializationFeature; 4 import com.fasterxml.jackson.databind.JavaType; 5 import com.fasterxml.jackson.databind.ObjectMapper; 6 import org.apache.commons.beanutils.PropertyUtils; 7 8 import java.io.IOException; 9 import java.lang.reflect.Field; 10 import java.lang.reflect.InvocationTargetException; 11 import java.util.HashMap; 12 import java.util.Map; 13 14 /** 15 * CglibBeanUtils class 16 * 17 * @author zhiwei 18 * @date 2020/09/28 19 */ 20 public class CglibBeanUtils { 21 private static final ObjectMapper mapper = new ObjectMapper(); 22 23 static { 24 mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 25 } 26 27 /** 28 * 根据源对象content转换成目标对象,源对象支持集合类型,但源对象中的实体类和目标对象中的实体类需要属性名相同 29 * 30 * @param content 源对象 31 * @param source 需要转换的目标集合类型 32 * @param param 目标集合类型里封装的实体类 33 * @return 34 */ 35 public static <T> T getCollectionBean(Object content, Class<?> collectionClass, Class<?>... elementClasses) { 36 if (content == null) { 37 return null; 38 } 39 String contentStr = null; 40 try { 41 contentStr = mapper.writeValueAsString(content); 42 JavaType javaType = mapper.getTypeFactory().constructParametricType(collectionClass, elementClasses); 43 return mapper.readValue(contentStr, javaType); 44 } catch (IllegalArgumentException | IOException e) { 45 } 46 return null; 47 } 48 49 /** 50 * 根据源对象obj转换成目标对象,不支持集合类型,源对象和目标对象属性名需要相同 51 * 52 * @param obj源对象 53 * @param valueType需要转换的目标集合类型 54 * @return 55 */ 56 public static <T> T getDataBeanWithType(Object obj, Class<T> valueType) { 57 String dataNode = null; 58 try { 59 dataNode = mapper.writeValueAsString(obj); 60 return mapper.readValue(dataNode, valueType); 61 } catch (IOException e) { 62 } 63 return null; 64 } 65 66 /** 67 * 拷贝bean的不同名称之间属性值, 68 * 需要手工维护一个bean之间不同属性名的映射关系,不支持源对象或目标对象为集合类型 69 * 70 * @param target 目标对象 71 * @param source 源对象 72 * @param param 源对象和目标对象的映射关系,其中key为源对象的属性名,value为目标对象的属性名 73 * @return 目标对象 74 * @throws ClassNotFoundException 75 * @throws IllegalArgumentException 76 * @throws IllegalAccessException 77 * @throws InvocationTargetException 78 * @throws NoSuchMethodException 79 */ 80 @SuppressWarnings("rawtypes") 81 public static Object getObject(Object target, Object source, Map<String, String> param) throws ClassNotFoundException, 82 IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { 83 //获取源对象的属性名和值,属性名作为key,值作为value 84 Map<String, Object> sourceBeanMap = PropertyUtils.describe(source); 85 // 获取实体对象属性名数组 86 Field[] fields = source.getClass().getDeclaredFields(); 87 // 属性名,属性类型 88 Map<String, Class> temp = new HashMap<>(); 89 // 属性名,属性值 90 Map<String, Object> valueParam = new HashMap<>(); 91 for (Field f : fields) { 92 // 设置访问权限,否则不能访问私有化属性 93 f.setAccessible(true); 94 // 若没有映射关系,则跳过继续寻找有映射关系的属性 95 if (null == param.get(f.getName())) 96 continue; 97 temp.put(param.get(f.getName()), Class.forName(f.getType().getName())); 98 for (Map.Entry<String, String> entry : param.entrySet()) { 99 if (entry.getKey().equals(f.getName())) { 100 Object value = sourceBeanMap.get(entry.getKey()); 101 valueParam.put(param.get(f.getName()), value); 102 break; 103 } 104 } 105 } 106 // 根据参数生成CglibBean对象 107 CglibBean cglibBean = new CglibBean(temp); 108 for (Map.Entry<String, Object> entry : valueParam.entrySet()) { 109 cglibBean.setValue(entry.getKey(), entry.getValue()); 110 } 111 Object object = cglibBean.getObject(); 112 /*// 用object给目标对象赋值 113 PropertyUtils.copyProperties(target, object);*/ 114 BeanUtils.copyBeanProp(target, object); 115 return target; 116 } 117 118 public static void main(String[] args) throws ClassNotFoundException, IllegalArgumentException, 119 IllegalAccessException, InvocationTargetException, NoSuchMethodException { 120 Map<String, String> mapping = new HashMap<>(); 121 UserDTO source = new UserDTO(); 122 UserVO target = new UserVO(); 123 source.setUserName("expireDate"); 124 source.setUserAge(11); 125 mapping.put("userName", "name");//source field,target field, 126 mapping.put("userAge", "age"); 127 target = (UserVO) getObject(target, source, mapping); 128 System.out.println(target.toString()); 129 } 130 }
两个实体类:
1 @Data 2 @AllArgsConstructor 3 @NoArgsConstructor 4 @Accessors(chain = true) 5 public class UserDTO { 6 private String userName; 7 private Integer userAge; 8 } 9 10 11 @Data 12 @AllArgsConstructor 13 @NoArgsConstructor 14 @Accessors(chain = true) 15 public class UserVO { 16 private String name; 17 private Integer age; 18 }
第二种方式:
使用jdk8函数式接口:
1 public class UserDTO { 2 private String userName; 3 private Integer userAge; 4 5 public String getUserName() { 6 return userName; 7 } 8 9 public void setUserName(String userName) { 10 this.userName = userName; 11 } 12 13 public Integer getUserAge() { 14 return userAge; 15 } 16 17 public void setUserAge(Integer userAge) { 18 this.userAge = userAge; 19 } 20 21 public UserDTO convert(){ 22 return ((Function<UserDTO,UserVO>) userDto ->{ 23 UserVO userVo = new UserVO(); 24 userVo.setAge(userDto.getUserAge()); 25 userVo.setName(userDto.getUserName()); 26 }) 27 } 28 }