千家信息网

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

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,这篇文章主要介绍如何使用JPA自定义VO类型转换,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!JPA自定义VO类型转换(EntityUtils工具类)在JPA查询中,如果需要返
千家信息网最后更新 2026年11月02日如何使用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安全错误 数据库的锁怎样保障安全 精品咖啡豆 上海睿民互联网科技有限公司 广州紫鲸互联网科技有限公司 科技平台互联网 互联网为科技 网络科技有限互联网 广州宏创互联网科技 互联网科技上市公司 碳银互联网科技有限公司 哈尔滨新华互联网科技 互联网科技博主是什么意思 常德市电业局互联网科技部 未来五年的互联网科技 内蒙古九一互联网科技 锡山区互联网智能科技产品供应 云南省自由互联网科技有限公司 互联网科技股为什么大涨 广州有谷有贝互联网科技有限公司 中国新注册互联网科技 三亚科技创新互联网基地 金诺互联网科技 互联网科技公司招聘 农村开互联网科技讲堂 哈尔滨新华互联网科技学院 新兴科技互联网创新大赛颁奖典礼 华夏恒生互联网科技013171 为客找房互联网科技公司怎么样 山东星卡互联网科技有限公司官网 广州百诚互联网科技有限公司官网 四川互联网展示科技馆设计
0