千家信息网

如何使用JPA自定义VO类型转换

发表于:2025-01-19 作者:千家信息网编辑
千家信息网最后更新 2025年01月19日,这篇文章主要介绍如何使用JPA自定义VO类型转换,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!JPA自定义VO类型转换(EntityUtils工具类)在JPA查询中,如果需要返
千家信息网最后更新 2025年01月19日如何使用JPA自定义VO类型转换

这篇文章主要介绍如何使用JPA自定义VO类型转换,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

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 = 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 公司名称     * @return  List     */    @Query(value = "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);

使用类型转换:

@Override    public 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.dozer    dozer    5.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 = "id")    @TableId(value = "id", type = IdType.INPUT)    private String id;    @ApiModelProperty(value = "用户名")    @Mapping("name")    private String userName;    @ApiModelProperty(value = "密码")    @Mapping("pwd")    private String password;    @ApiModelProperty(value = "登录名")    private String loginName;    @ApiModelProperty(value = "创建时间")    private Date createTime;    @ApiModelProperty(value = "修改时间")    private Date updateTime;    @ApiModelProperty(value = "版本号")    private Integer version;    @ApiModelProperty(value = "作废标记")    private Integer deleted;}

这个呢,是咱们的实体对象(也就是数据库对象了)

看一下,是不是发小完全不一样呀!

这里呢,@Mappin充当了化妆品的角色,将每一个不同的细节进行遮盖,使其成为和原来的实例一模一样(也就是做了映射了)

 @Mapping("userName") private String name;

上面就是一个化妆处理,将name映射为userName

每一个地方处理完成后,直接上剧组,看看能不能不被发现

/**     * 转换实体为另一个指定的实体     * 任意一个参数为NULL时 会抛出NPE     *     * @param source 源实体 不能为NULL     * @param clazz 目标实体 不能为NULL     * @param  泛型     * @return 转换后的结果     */    @NonNull    public static  T convert(@NonNull Object source, @NonNull Class clazz) {        return  dozerMapper.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 转换后的结果     */    @Nullable    public 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 转换后的结果     */    @NonNull    public static  T convert(@NonNull Object source, @NonNull Class clazz) {        return  dozerMapper.map(source, clazz);    }    /**     * 转换List实体为另一个指定的实体     * source如果为NULL 会使用空集合     * 在目标实体为NULL时 会抛出NPE     *     * @param source 源集合 可以为NULL     * @param clazz 目标实体 不能为NULL     * @param  泛型     * @return 转换后的结果     */    @Nullable    public 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注解,填写上源指定对象的字段名就行。

以上是"如何使用JPA自定义VO类型转换"这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注行业资讯频道!

实体 化妆 替身 类型 对象 目标 就是 化妆师 结果 查询 场景 实例 工具 经纪人 开发 经纪 一致 也就是 剧组 名称 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 ntp服务器软件 软件开发java宠物商店 csscl数据库的特点 服务器里面没有安全模式怎么办 科技文献数据库对比研究 网络安全知识进校园 ppt 数据库可重复读怎么实现的 软件开发技术的优势 西藏土地资产管理软件开发公司 无锡计算机软件开发 鸠鸠互联网科技图片 微信操作过于频繁是服务器的事吗 网络安全集成服务市场 cs1.5广东服务器 ice在服务器里面什么意思 网络安全监督管理权最低部门 卧龙区委网络安全 魂师对决不同服务器能组队吗 济南市政府网络安全应急预案 滕州市网络安全保障中心属于哪个单位 永兴学计算机软件开发学费多少 泰拉瑞亚服务器白名单怎么设置 idea永久导入数据库 网络安全宣传海报作用 广州众晶悦互联网科技有限公司 数据库 管理文件 株洲天盈软件开发有限公司 数据库及其安全技术 四年级网络安全手抄报简单的 疾风之刃最新服务器
0