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

网友投稿 1193 2022-11-21

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

使用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 = 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", nahttp://tiveQuery = 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

**/

@Data

public class EmploymentPositionVO {

/** ID */

private BigInteger id;

/** 岗位名称 */

private String position;

/** 月薪 */

private String salary;

/** 人数 */

private Integer people;

/** 工作经验 */

private String experience;

/** 工作地点 */

private String address;

/** 更新时间 */

private Timestamp updatWRkecuOxuveTime;

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转换复制)

第二种场景,完全不一样:

求乞,完全不一样,这咋的弄呀,肯定得换替身,是不是!最起码找个相似的嘛(不用担心,咱们有化妆师呀,化妆走起!)

@Data

public 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;

@Component

public 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());

}

}

在给大家看一下我们的替身

@Data

public 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

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:替代兼容矽力杰SY6982E双电池5V升压锂离子电池充电器充电IC
下一篇:FS2712C筋膜枪单片机方案MCU方案原理图
相关文章

 发表评论

暂时没有评论,来抢沙发吧~