使用JPA自定义VO类型转换(EntityUtils工具类)

目录

  • JPA自定义VO类型转换(EntityUtils工具类)
  • dto,vo,po,bo等实体转换工具类
    • 下面宣布这次的主角:dozer

JPA自定义VO类型转换(EntityUtils工具类) 在JPA查询中,如果需要返回自定义的类,可以使用EntityUtils工具类,该类源码:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author 954L * @create 2019/10/30 17:27 */public class EntityUtils { private static final Logger log = LoggerFactory.getLogger(EntityUtils.class); /*** 将数组数据转换为实体类* 此处数组元素的顺序必须与实体类构造函数中的属性顺序一致** @param list数组对象集合* @param clazz 实体类* @param 实体类* @param model 实例化的实体类* @return 实体类集合*/public static List castEntity(List list, Class clazz, Object model) {List returnList = new ArrayList(); if (list.isEmpty()) return returnList; Object[] co = list.get(0); List attributeInfoList = getFiledsInfo(model); Class[] c2 = new Class[attributeInfoList.size()]; if (attributeInfoList.size() != co.length) {return returnList; }for (int i = 0; i < attributeInfoList.size(); i++) {c2[i] = (Class) attributeInfoList.get(i).get("type"); }try {for (Object[] o : list) {Constructor constructor = clazz.getConstructor(c2); returnList.add(constructor.newInstance(o)); }} catch (Exception ex) {log.error("实体数据转化为实体类发生异常:异常信息:{}", ex.getMessage()); return returnList; }return returnList; } private static Object getFieldValueByName(String fieldName, Object modle) {try {String firstLetter = fieldName.substring(0, 1).toUpperCase(); String getter = "get" + firstLetter + fieldName.substring(1); Method method = modle.getClass().getMethod(getter, new Class[]{}); Object value = https://www.it610.com/article/method.invoke(modle, new Object[]{}); return value; } catch (Exception e) {return null; }} private static List getFiledsInfo(Object model) {Field[] fields = model.getClass().getDeclaredFields(); List list = new ArrayList(fields.length); Map infoMap = null; for (int i = 0; i < fields.length; i++) {infoMap = new HashMap(3); infoMap.put("type", fields[i].getType()); infoMap.put("name", fields[i].getName()); infoMap.put("value", getFieldValueByName(fields[i].getName(), model)); list.add(infoMap); }return list; } }

使用原生sql查询:
/*** 根据公司名称查询岗位* @param name 公司名称* @returnList*/@Query(value = "https://www.it610.com/article/select id, position, salary, people, experience, address, update_time from employment_position where company_name = ?1 and is_delete is false ORDER BY sort asc", nativeQuery = true)List findByCompanyName(String name);

使用类型转换:
@Overridepublic List findByCompanyName(String name) {List objects = employmentPositionRepository.findByCompanyName(name); return EntityUtils.castEntity(objects, EmploymentPositionVO.class, new EmploymentPositionVO()); }

VO类如下:
import lombok.Data; import java.math.BigInteger; import java.sql.Timestamp; /** * @website https://el-admin.vip * @description / * @author budezhenjia * @date 2021-02-08 **/@Datapublic class EmploymentPositionVO { /** ID */private BigInteger id; /** 岗位名称 */private String position; /** 月薪 */private String salary; /** 人数 */private Integer people; /** 工作经验 */private String experience; /** 工作地点 */private String address; /** 更新时间 */private Timestamp updateTime; public EmploymentPositionVO(BigInteger id, String position, String salary, Integer people, String experience, String address, Timestamp updateTime) {this.id = id; this.position = position; this.salary = salary; this.people = people; this.experience = experience; this.address = address; this.updateTime = updateTime; } public EmploymentPositionVO() {}}

注意!
查询sql语句所查询出来的字段应与VO类中属性顺序一致,类型也需要一致!!
例如ID这个字段MySQL中类型为bigint,VO类中的类型为bigInteger

dto,vo,po,bo等实体转换工具类 3层开发以及不是多么新颖的开发思想了,但是呢,苦于开发的程序猿们,经常会被各个实例之间的转换弄得晕头转向,尤其是转换的次数多了,一下就蒙了,不知道转到哪里去了,博主也有这种困难,于是在网上到处找,找到了一些方法,并结合自身的开发使用,填补一些坑,希望对大家有所帮助!

下面宣布这次的主角:dozer
他是谁,一看英文名就不懂吧,其实他是一个大家都知道的一个角色,spring里面他可是家喻户晓的一个主角,没错就是beanUtils(其实,就是他的替身!)主要作用就是用来复制 JavaBean 属性的类库,什么叫复制,没错,就一模一样的再来一份,但是这样有一点点小小的区别,那就是,在使用的时候,需要指定一个“容器”(瞎说的,就是一个映射接受对象,也可以叫做目标)来存放,不然,复制到哪去,是不是。
这个时候呀,就有一个经纪人的出现,需要通过“经纪人”去代理复制,才能叫这个替身出来呀(专业替身30年,必须要有经纪人)
net.sf.dozerdozer5.5.1

好了,经纪人的名片已经发出,这个时候,找到剧组,咱们看看这个替身能不能胜任,能应用在哪些剧组,哪些场景!
第一种场景,完全一样:(咦,度一样了,那肯定好弄,又看不出来区别)
在各个实体是一样的情况下,是很容易的,直接上不就行啦,也不用做啥处理是不是:
直接是用原始替身(API方法)
Mapper mapper = new DozerBeanMapper(); DestinationObject destObject =mapper.map(sourceObject, DestinationObject.class);

嘿嘿,换一下衣服,直接OK了(也就是使用mapper转换复制)
第二种场景,完全不一样:
求乞,完全不一样,这咋的弄呀,肯定得换替身,是不是!最起码找个相似的嘛(不用担心,咱们有化妆师呀,化妆走起!)
@Datapublic class UserVo{@Mapping("userName")private String name; @Mapping("password")private String pwd; }

看一下,是不是这个东西,好眼熟,没错,是咱们的vo
@Data@TableName("user")public class UserEntity implements Serializable {@ApiModelProperty(value = "https://www.it610.com/article/id")@TableId(value = "https://www.it610.com/article/id", type = IdType.INPUT)private String id; @ApiModelProperty(value = "https://www.it610.com/article/用户名")@Mapping("name")private String userName; @ApiModelProperty(value = "https://www.it610.com/article/密码")@Mapping("pwd")private String password; @ApiModelProperty(value = "https://www.it610.com/article/登录名")private String loginName; @ApiModelProperty(value = "https://www.it610.com/article/创建时间")private Date createTime; @ApiModelProperty(value = "https://www.it610.com/article/修改时间")private Date updateTime; @ApiModelProperty(value = "https://www.it610.com/article/版本号")private Integer version; @ApiModelProperty(value = "https://www.it610.com/article/作废标记")private Integer deleted; }

这个呢,是咱们的实体对象(也就是数据库对象了)
看一下,是不是发小完全不一样呀!
这里呢,@Mappin充当了化妆品的角色,将每一个不同的细节进行遮盖,使其成为和原来的实例一模一样(也就是做了映射了)
@Mapping("userName") private String name;

上面就是一个化妆处理,将name映射为userName
每一个地方处理完成后,直接上剧组,看看能不能不被发现
/*** 转换实体为另一个指定的实体* 任意一个参数为NULL时 会抛出NPE** @param source 源实体 不能为NULL* @param clazz 目标实体 不能为NULL* @param 泛型* @return 转换后的结果*/@NonNullpublic static T convert(@NonNull Object source, @NonNull Class clazz) {returndozerMapper.map(source, clazz); }

实例:
UserEntity userEntity = userMapper.selectOne(wrapper); UserVo convert = null; if(userEntity != null){convert = Dozer.convert(userEntity, UserVo.class); }

没错,这样就完成转换替身的操作了,结果是可以映射上的,各位可以试试哦!
第三种场景,一堆的不相同的替身(好难呀,一堆的不一样,不能找几个差不多的吗?)
针对于这种一堆的不一样的替身,dozer也有办法,通过JAVA8的stream流来进行化妆(化妆师牛,只能这么说)
/*** 转换List实体为另一个指定的实体* source如果为NULL 会使用空集合* 在目标实体为NULL时 会抛出NPE** @param source 源集合 可以为NULL* @param clazz 目标实体 不能为NULL* @param 泛型* @return 转换后的结果*/@Nullablepublic static List convert(@Nullable List source, @NonNull Class clazz) {return Optional.ofNullable(source).orElse(Collections.emptyList()).stream().map(bean -> dozerMapper.map(bean, clazz)).collect(Collectors.toList()); }

看见没,这样一弄,就OK了,咦,是不是发现化妆师dozerMapper从哪来的(这么牛的化妆师,召几个开化妆店去),博主告诉你,这个化妆师呀,并不是越多也好的(大家都知道,一样的对象,建立太多浪费空间),只需要建立一个全局唯一的就行了,博主带你们看一下化妆间就明白了(工具类来了)
package cn.yichehuoban.ycbb.platform.util.beanutils; import org.dozer.Mapper; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @Componentpublic class Dozer {/*** dozer转换的核心mapper对象*/public static final Mapper dozerMapper = new org.dozer.DozerBeanMapper(); /*** 转换实体为另一个指定的实体* 任意一个参数为NULL时 会抛出NPE** @param source 源实体 不能为NULL* @param clazz 目标实体 不能为NULL* @param 泛型* @return 转换后的结果*/@NonNullpublic static T convert(@NonNull Object source, @NonNull Class clazz) {returndozerMapper.map(source, clazz); }/*** 转换List实体为另一个指定的实体* source如果为NULL 会使用空集合* 在目标实体为NULL时 会抛出NPE** @param source 源集合 可以为NULL* @param clazz 目标实体 不能为NULL* @param 泛型* @return 转换后的结果*/@Nullablepublic static List convert(@Nullable List source, @NonNull Class clazz) {return Optional.ofNullable(source).orElse(Collections.emptyList()).stream().map(bean -> dozerMapper.map(bean, clazz)).collect(Collectors.toList()); }}

在给大家看一下我们的替身
@Datapublic class UserVo{@Mapping("userName")private String name; @Mapping("password")private String pwd; private String loginName; private Integer version; private Integer deleted; private String id; }

一样的地方直接就映射上了,不一样的地方使用 @Mapping注解,填写上源指定对象的字段名就行
这只是几种方法,还有其他双向映射,数据拷贝等,可以看看他的官方文档dozer
【使用JPA自定义VO类型转换(EntityUtils工具类)】以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

    推荐阅读