在使用JPA来操作数据库时,在遇到复杂查询时(包括JOIN嵌套等),需要使用到@Query来使用原生SQL或者Hibernate的HQL进行查询,Repository中编写如下:
1 2 3 4 5 6 7 8 9 10 11 12 public interface UserRepository extends JpaRepository <User , Integer > { @Query (value = "select * from user as u where u.group_id = :gid" , countQuery = "select count(*) from user as u where u.group_id = :gid" , nativeQuery = true ) Page<Map<String, Object>> findAllUserByGroupId(@Param ("gid" ) Integer groupId, Pageable pageable); @Query (value = "select * from user as u where u.group_id = :gid" , countQuery = "select count(*) from user as u where u.group_id = :gid" , nativeQuery = true ) Page<Object[]> findAllUserByGroupId2(@Param ("gid" ) Integer groupId, Pageable pageable); }
@Query支持使用两种方式进行接收:
Object[]
:
通过使用 Object[0], Object[1]
来获取结果字段值,需要手动将字段转换为对应的Bean字段,非常的不优雅。
Map<String, Object>
:
Map中的Key为对应的数据库字段String名,Object为字段对应的值,通过使用Map.get(key)来获取对应字段的值,相比Object[]
会优雅一些。
那么有没有一种办法,可以将Map转换为对应的Object?
首先会遇到第一个问题,数据库字段和实体类字段命名规则不同,在Hibernate默认模式下,数据库字段为下划线格式,即:
userGroupId => user_group_id
在Map<String,Object>
中,取到的Key是下划线模式(数据库字段名),那么首先要解决的问题,就是将下划线命名,转换为驼峰,参考代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 private static Pattern linePattern = Pattern.compile("_(\\w)" );public static String lineToHump (String str) { str = str.toLowerCase(); Matcher matcher = linePattern.matcher(str); StringBuffer sb = new StringBuffer(); while (matcher.find()) { matcher.appendReplacement(sb, matcher.group(1 ).toUpperCase()); } matcher.appendTail(sb); return sb.toString(); }
通过正则匹配,去掉下划线并且将首字母大写来恢复驼峰命名,注意,这里可以正确转换的前提是,实体类字段名,是规范的驼峰命名法,否则会出现无法转换、匹配异常等问题。
规避掉下划线与驼峰问题之后,就可以通过Spring集成的cglib中的BeanMap来进行对象的转换,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public static <T> List<T> maps2Bean (List<Map<String, Object>> maps, Class clz) throws IllegalAccessException, InstantiationException { BeanMap beanMap; T bean; List<T> list = new ArrayList<>(); for (Map<String, Object> map : maps) { bean = (T) clz.newInstance(); beanMap = BeanMap.create(bean); for (Map.Entry<String, Object> entry : map.entrySet()) { beanMap.put(lineToHump(entry.getKey()), entry.getValue()); } list.add(bean); } return list; }
通过BeanMap将对象进行赋值操作,完成Map到对象的转换,使用方法如下:
1 2 3 4 5 6 try { List<Map<String, Object>> result = userResList.getContent(); List<UserDTO> objects = BeanMapUtil.maps2Bean(result, UserDTO.class); } catch (IllegalAccessException | InstantiationException e) { e.printStackTrace(); }
这样就可以简化Query结果的转换操作了。
参考