当实体类中的属性名和表中的字段名不一样,如何实现对象的封装

本文介绍两种有效的方法来解决SQL查询结果与实体类属性不匹配的问题:一是使用SQL语句定义字段名别名;二是手动映射字段名与实体类属性名。掌握这些技巧,有助于提高代码的可读性和维护性。

方法一:通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。
在这里插入图片描述
方法二:通过来映射字段名和实体类属性名的一一对应的关系
在这里插入图片描述

<think>我们有一个需求:将List<Map<String, Object>>转换为List<实体类>,其中实体类属性名与Map中的相同。 思路: 1. 定义一个实体类,其属性与Map中的键对应(注意属性名一致)。 2. 遍历List中的每个Map,将每个Map转换为一个实体类对象。 3. 将每个实体类对象添加到一个新的List中。 具体步骤: 步骤1:定义实体类。假设Map中有键为"name", "age",那么实体类应该有两个属性:nameage,并提供getter/setter无参构造器(如果有特殊需求,也可以有带参构造器)。 步骤2:使用反射或手动设置属性值。这里我们可以手动设置(因为属性名已知),也可以使用第三方库(如Apache Commons BeanUtils, Spring BeanUtils等)来简化转换过程。 示例代码(手动转换): 假设实体类为Person,属性为nameage。 步骤3:遍历List<Map>,对每个Map,创建一个Person对象,并从Map中取出对应键的值赋给Person对象的属性。 但是,如果Map的键很多,手动转换会很麻烦。因此,推荐使用反射或者工具类。 使用Apache Commons BeanUtils(需要导入jar包): 我们可以使用BeanUtils.populate(Object bean, Map properties)方法,但注意这个方法填充的是JavaBean,所以要求实体类有默认构造器,并且属性有setter方法。 由于问题中没有具体实体类Map结构,我假设一个示例: 实体类Person: ``` public class Person { private String name; private int age; // 无参构造器 public Person() {} // gettersetter 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; } } ``` 转换代码: ``` import org.apache.commons.beanutils.BeanUtils; public List<Person> convert(List<Map<String, Object>> mapList) throws Exception { List<Person> personList = new ArrayList<>(); for (Map<String, Object> map : mapList) { Person person = new Person(); // 使用BeanUtils将map中的键值对填充到person对象中 // 注意:BeanUtils.populate会使用map中的键去匹配person中的属性,并调用setter方法 BeanUtils.populate(person, map); personList.add(person); } return personList; } ``` 但是,如果Map中的实体类属性名一致,则需要额外处理(比如在Map存入时修改键,或者在实体类中使用注解等)。这里假设键属性名一致。 另外,注意类型转换:BeanUtils会自动进行基本类型的转换,但复杂的类型可能需要自定义转换器。 使用Spring BeanUtils(如果项目中有Spring框架): Spring的BeanUtils.copyProperties方法支持直接从Map复制到对象,所以我们可以用另一种方式:使用Jackson库(或Gson)先将Map转为JSON字符串,再将JSON字符串转为对象。 使用Jackson(推荐,更灵活): 添加依赖:jackson-databind 代码示例: ``` import com.fasterxml.jackson.databind.ObjectMapper; public List<Person> convert(List<Map<String, Object>> mapList) { ObjectMapper mapper = new ObjectMapper(); List<Person> personList = new ArrayList<>(); for (Map<String, Object> map : mapList) { Person person = mapper.convertValue(map, Person.class); personList.add(person); } return personList; } ``` 使用Jackson的好处是它可以处理复杂的嵌套结构,并且支持各种注解(如@JsonProperty)来处理键属性名一致的情况。 如果想引入第三方库,也可以使用Java反射,但是代码会相对复杂: ``` public List<Person> convert(List<Map<String, Object>> mapList) throws Exception { List<Person> personList = new ArrayList<>(); for (Map<String, Object> map : mapList) { Person person = new Person(); // 遍历map的每个键值对 for (Map.Entry<String, Object> entry : map.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); // 使用反射给person的属性赋值 Field field = Person.class.getDeclaredField(key); // 获取字段 field.setAccessible(true); // 设置可访问 field.set(person, value); // 赋值 } personList.add(person); } return personList; } ``` 注意:反射方式需要处理类型匹配问题,比如Map中的值是Integer,而实体类属性是int,可以自动转换。但如果类型匹配(比如String赋值给int),则需要转换。另外,如果实体类没有对应的属性,会抛出异常。 根据实际情况选择方法: 1. 如果使用Spring框架,Jackson通常已经存在,推荐使用Jackson。 2. 如果只有简单的Bean,可以使用Apache Commons BeanUtils。 3. 如果想引入额外依赖,且属性数量少,可以手动赋值。 4. 如果属性多且确定,建议使用Jackson。 因此,我们给出两种主要方法:使用Jackson使用Apache Commons BeanUtils。 注意:如果使用Jackson,要确保实体类有无参构造器(或能通过其他方式构造,如@JsonCreator注解)。 示例完整代码(使用Jackson): 假设我们有如下依赖(Maven): ``` <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.3</version> </dependency> ``` 转换方法: ``` import com.fasterxml.jackson.databind.ObjectMapper; import java.util.ArrayList; import java.util.List; import java.util.Map; public class MapListToEntityList { public static void main(String[] args) { // 示例输入:一个Map的List List<Map<String, Object>> mapList = new ArrayList<>(); // ... 假设mapList已经被填充数据 // 转换 List<Person> personList = convertMapListToPersonList(mapList); } public static List<Person> convertMapListToPersonList(List<Map<String, Object>> mapList) { ObjectMapper mapper = new ObjectMapper(); List<Person> personList = new ArrayList<>(); for (Map<String, Object> map : mapList) { Person person = mapper.convertValue(map, Person.class); personList.add(person); } return personList; } } ``` 如果遇到类型匹配的问题,可以通过在实体类中使用注解来处理,例如: ``` public class Person { @JsonProperty("name") // 这个注解可以省略,因为属性名key一致,如果一样则指定 private String name; @JsonProperty("age") private int age; // 省略其他... } ``` 考虑到健壮性,应该处理异常(如转换失败): ``` public static List<Person> convertMapListToPersonList(List<Map<String, Object>> mapList) { ObjectMapper mapper = new ObjectMapper(); List<Person> personList = new ArrayList<>(); for (Map<String, Object> map : mapList) { try { Person person = mapper.convertValue(map, Person.class); personList.add(person); } catch (IllegalArgumentException e) { e.printStackTrace(); // 处理转换异常,比如跳过这个map或者使用默认值等 } } return personList; } ``` 以上是常用且推荐的方法。 如果项目中没有Jackson,也可以使用Gson,方法类似。 使用Gson: ``` import com.google.gson.Gson; public static List<Person> convertMapListToPersonList(List<Map<String, Object>> mapList) { Gson gson = new Gson(); List<Person> personList = new ArrayList<>(); for (Map<String, Object> map : mapList) { // 先将map转为Json字符串,再将字符串转为Person对象 String json = gson.toJson(map); Person person = gson.fromJson(json, Person.class); personList.add(person); } return personList; } ``` 总结:推荐使用Jackson或Gson库,因为它们可以处理复杂的类型转换,并且代码简洁。 根据用户需求,选择其中一种方法即可。 </think>### 如何将Map的List转换为实体类的List 要将`List<Map<String, Object>>`转换为实体类List(实体类属性名与Map键相同),以下是完整的解决方案: #### 核心实现方法 ```java import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.Map; public class MapToEntityConverter { /** * 将Map列转换为实体类 * @param mapList Map数据列 * @param entityClass 目标实体类的Class对象 * @return 转换后的实体类 */ public static <T> List<T> convert(List<Map<String, Object>> mapList, Class<T> entityClass) { List<T> entityList = new ArrayList<>(); try { for (Map<String, Object> map : mapList) { T entity = entityClass.getDeclaredConstructor().newInstance(); setEntityFields(entity, map); entityList.add(entity); } } catch (Exception e) { throw new RuntimeException("转换失败: " + e.getMessage(), e); } return entityList; } /** * 使用反射将Map值注入实体类属性 */ private static <T> void setEntityFields(T entity, Map<String, Object> map) throws IllegalAccessException { Class<?> clazz = entity.getClass(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); // 允许访问私有字段 String fieldName = field.getName(); if (map.containsKey(fieldName)) { Object value = map.get(fieldName); // 类型转换处理(根据实际类型调整) if (value != null && field.getType().isAssignableFrom(value.getClass())) { field.set(entity, value); } } } } } ``` #### 使用示例 ```java // 1. 定义实体类属性名与Map键一致) public class User { private Integer id; private String name; private String email; // 必须有无参构造函数 public User() {} // getters/setters省略... } // 2. 转换操作 List<Map<String, Object>> mapList = new ArrayList<>(); Map<String, Object> map1 = new HashMap<>(); map1.put("id", 101); map1.put("name", "张三"); map1.put("email", "zhangsan@example.com"); Map<String, Object> map2 = new HashMap<>(); map2.put("id", 102); map2.put("name", "李四"); map2.put("email", "lisi@example.com"); mapList.add(map1); mapList.add(map2); // 执行转换 List<User> userList = MapToEntityConverter.convert(mapList, User.class); ``` #### 关键特性说明 1. **反射机制**: - 通过`Class.getDeclaredFields()`获取实体类所有字段 - `Field.setAccessible(true)`解除私有字段访问限制[^1] - 动态匹配字段名与Map键 2. **类型安全处理**: ```java if (value != null && field.getType().isAssignableFrom(value.getClass())) { field.set(entity, value); } ``` 确保值类型与字段类型兼容,避免类型转换异常 3. **异常处理**: - 统一捕获反射操作异常 - 封装为运行时异常便于调用方处理 4. **实体类要求**: - 必须有无参构造函数 - 字段名与Map键严格匹配 - 字段类型应与Map值类型兼容 #### 高级场景处理 ```java // 处理类型匹配问题(如数据库Integer→实体类Long) if (value instanceof Number) { Number number = (Number) value; if (field.getType() == Long.class) { field.set(entity, number.longValue()); } // 其他类型转换... } // 处理嵌套对象 else if (value instanceof Map) { Object nestedEntity = field.getType().newInstance(); setEntityFields(nestedEntity, (Map<String, Object>) value); field.set(entity, nestedEntity); } ``` #### 替代方案比较 | 方法 | 优点 | 缺点 | |------|------|------| | **反射(本方案)** | 无需第三方库,灵活通用 | 性能稍低,需处理类型转换 | | **Jackson库** | 强大的类型转换,支持注解 | 需要添加依赖 | | **Spring BeanUtils** | 简单易用(Spring环境) | 仅支持简单属性复制 | 使用Jackson的示例: ```java ObjectMapper mapper = new ObjectMapper(); List<User> users = mapList.stream() .map(map -> mapper.convertValue(map, User.class)) .collect(Collectors.toList()); ``` #### 性能优化建议 1. 缓存反射信息: ```java // 预缓存字段信息 private static final Map<Class<?>, List<Field>> fieldCache = new ConcurrentHashMap<>(); List<Field> fields = fieldCache.computeIfAbsent(clazz, k -> Arrays.asList(k.getDeclaredFields())); ``` 2. 使用`MethodHandle`替代反射: ```java MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandle setter = lookup.findSetter(clazz, fieldName, fieldType); setter.invoke(entity, value); ``` 3. 对于高性能场景,考虑代码生成工具(如ByteBuddy)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值