使用JPA自定義VO類型轉(zhuǎn)換(EntityUtils工具類)
JPA自定義VO類型轉(zhuǎn)換(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);
/**
* 將數(shù)組數(shù)據(jù)轉(zhuǎn)換為實體類
* 此處數(shù)組元素的順序必須與實體類構(gòu)造函數(shù)中的屬性順序一致
*
* @param list 數(shù)組對象集合
* @param clazz 實體類
* @param <T> 實體類
* @param model 實例化的實體類
* @return 實體類集合
*/
public static <T> List<T> castEntity(List<Object[]> list, Class<T> clazz, Object model) {
List<T> returnList = new ArrayList<T>();
if (list.isEmpty()) return returnList;
Object[] co = list.get(0);
List<Map> 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<T> constructor = clazz.getConstructor(c2);
returnList.add(constructor.newInstance(o));
}
} catch (Exception ex) {
log.error("實體數(shù)據(jù)轉(zhuǎn)化為實體類發(fā)生異常:異常信息:{}", 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<Map> getFiledsInfo(Object model) {
Field[] fields = model.getClass().getDeclaredFields();
List<Map> 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查詢:
/**
* 根據(jù)公司名稱查詢崗位
* @param name 公司名稱
* @return List<EmploymentPosition>
*/
@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<Object[]> findByCompanyName(String name);
使用類型轉(zhuǎn)換:
@Override
public List<EmploymentPositionVO> findByCompanyName(String name) {
List<Object[]> 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;
/** 人數(shù) */
private Integer people;
/** 工作經(jīng)驗 */
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語句所查詢出來的字段應(yīng)與VO類中屬性順序一致,類型也需要一致!!
例如ID這個字段MySQL中類型為bigint,VO類中的類型為bigInteger
dto,vo,po,bo等實體轉(zhuǎn)換工具類
3層開發(fā)以及不是多么新穎的開發(fā)思想了,但是呢,苦于開發(fā)的程序猿們,經(jīng)常會被各個實例之間的轉(zhuǎn)換弄得暈頭轉(zhuǎn)向,尤其是轉(zhuǎn)換的次數(shù)多了,一下就蒙了,不知道轉(zhuǎn)到哪里去了,博主也有這種困難,于是在網(wǎng)上到處找,找到了一些方法,并結(jié)合自身的開發(fā)使用,填補一些坑,希望對大家有所幫助!
下面宣布這次的主角:dozer
他是誰,一看英文名就不懂吧,其實他是一個大家都知道的一個角色,spring里面他可是家喻戶曉的一個主角,沒錯就是beanUtils(其實,就是他的替身!)主要作用就是用來復(fù)制 JavaBean 屬性的類庫,什么叫復(fù)制,沒錯,就一模一樣的再來一份,但是這樣有一點點小小的區(qū)別,那就是,在使用的時候,需要指定一個“容器”(瞎說的,就是一個映射接受對象,也可以叫做目標(biāo))來存放,不然,復(fù)制到哪去,是不是。
這個時候呀,就有一個經(jīng)紀(jì)人的出現(xiàn),需要通過“經(jīng)紀(jì)人”去代理復(fù)制,才能叫這個替身出來呀(專業(yè)替身30年,必須要有經(jīng)紀(jì)人)
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>5.5.1</version>
</dependency>
好了,經(jīng)紀(jì)人的名片已經(jīng)發(fā)出,這個時候,找到劇組,咱們看看這個替身能不能勝任,能應(yīng)用在哪些劇組,哪些場景!
第一種場景,完全一樣:(咦,度一樣了,那肯定好弄,又看不出來區(qū)別)
在各個實體是一樣的情況下,是很容易的,直接上不就行啦,也不用做啥處理是不是:
直接是用原始替身(API方法)
Mapper mapper = new DozerBeanMapper();
DestinationObject destObject =
mapper.map(sourceObject, DestinationObject.class);
嘿嘿,換一下衣服,直接OK了(也就是使用mapper轉(zhuǎn)換復(fù)制)
第二種場景,完全不一樣:
求乞,完全不一樣,這咋的弄呀,肯定得換替身,是不是!最起碼找個相似的嘛(不用擔(dān)心,咱們有化妝師呀,化妝走起?。?/p>
@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 = "創(chuàng)建時間")
private Date createTime;
@ApiModelProperty(value = "修改時間")
private Date updateTime;
@ApiModelProperty(value = "版本號")
private Integer version;
@ApiModelProperty(value = "作廢標(biāo)記")
private Integer deleted;
}
這個呢,是咱們的實體對象(也就是數(shù)據(jù)庫對象了)
看一下,是不是發(fā)小完全不一樣呀!
這里呢,@Mappin充當(dāng)了化妝品的角色,將每一個不同的細(xì)節(jié)進行遮蓋,使其成為和原來的實例一模一樣(也就是做了映射了)
@Mapping("userName")
private String name;
上面就是一個化妝處理,將name映射為userName
每一個地方處理完成后,直接上劇組,看看能不能不被發(fā)現(xiàn)
/**
* 轉(zhuǎn)換實體為另一個指定的實體
* 任意一個參數(shù)為NULL時 會拋出NPE
*
* @param source 源實體 不能為NULL
* @param clazz 目標(biāo)實體 不能為NULL
* @param <T> 泛型
* @return 轉(zhuǎn)換后的結(jié)果
*/
@NonNull
public static <T> T convert(@NonNull Object source, @NonNull Class<T> clazz) {
return dozerMapper.map(source, clazz);
}
實例:
UserEntity userEntity = userMapper.selectOne(wrapper);
UserVo convert = null;
if(userEntity != null){
convert = Dozer.convert(userEntity, UserVo.class);
}
沒錯,這樣就完成轉(zhuǎn)換替身的操作了,結(jié)果是可以映射上的,各位可以試試哦!
第三種場景,一堆的不相同的替身(好難呀,一堆的不一樣,不能找?guī)讉€差不多的嗎?)
針對于這種一堆的不一樣的替身,dozer也有辦法,通過JAVA8的stream流來進行化妝(化妝師牛,只能這么說)
/**
* 轉(zhuǎn)換List實體為另一個指定的實體
* source如果為NULL 會使用空集合
* 在目標(biāo)實體為NULL時 會拋出NPE
*
* @param source 源集合 可以為NULL
* @param clazz 目標(biāo)實體 不能為NULL
* @param <T> 泛型
* @return 轉(zhuǎn)換后的結(jié)果
*/
@Nullable
public static <T> List<T> convert(@Nullable List<?> source, @NonNull Class<T> clazz) {
return Optional.ofNullable(source)
.orElse(Collections.emptyList())
.stream()
.map(bean -> dozerMapper.map(bean, clazz))
.collect(Collectors.toList());
}
看見沒,這樣一弄,就OK了,咦,是不是發(fā)現(xiàn)化妝師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轉(zhuǎn)換的核心mapper對象
*/
public static final Mapper dozerMapper = new org.dozer.DozerBeanMapper();
/**
* 轉(zhuǎn)換實體為另一個指定的實體
* 任意一個參數(shù)為NULL時 會拋出NPE
*
* @param source 源實體 不能為NULL
* @param clazz 目標(biāo)實體 不能為NULL
* @param <T> 泛型
* @return 轉(zhuǎn)換后的結(jié)果
*/
@NonNull
public static <T> T convert(@NonNull Object source, @NonNull Class<T> clazz) {
return dozerMapper.map(source, clazz);
}
/**
* 轉(zhuǎn)換List實體為另一個指定的實體
* source如果為NULL 會使用空集合
* 在目標(biāo)實體為NULL時 會拋出NPE
*
* @param source 源集合 可以為NULL
* @param clazz 目標(biāo)實體 不能為NULL
* @param <T> 泛型
* @return 轉(zhuǎn)換后的結(jié)果
*/
@Nullable
public static <T> List<T> convert(@Nullable List<?> source, @NonNull Class<T> 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注解,填寫上源指定對象的字段名就行
這只是幾種方法,還有其他雙向映射,數(shù)據(jù)拷貝等,可以看看他的官方文檔dozer
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot實現(xiàn)application.yml文件敏感信息加密
本文主要介紹了SpringBoot實現(xiàn)application.yml文件敏感信息加密,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
spring依賴注入成功但在調(diào)用接口的時候拿到的依賴卻是null問題
這篇文章主要介紹了spring依賴注入成功但在調(diào)用接口的時候拿到的依賴卻是null問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12
Java 實現(xiàn)一個漢諾塔實戰(zhàn)練習(xí)
漢諾塔是源于印度一個古老傳說的益智玩具。大梵天創(chuàng)造世界時做了三根石柱,在一根柱子上從下往上按大小順序摞著64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。并且規(guī)定,在小圓盤上不能放大圓盤,三根柱子之間一次只能移動一個圓盤2021-10-10
超級詳細(xì)Java?JDK環(huán)境配置教程(Mac?版)
這篇文章詳細(xì)講解了在MacOS上安裝JDK及配置Java環(huán)境的步驟,包括下載JDK安裝包、安裝JDK、查詢安裝路徑以及配置環(huán)境變量,旨在為初學(xué)者提供一份保姆級的安裝指南,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2024-10-10
Spring 中 BeanFactoryPostProcessor 的作用和示例源碼分析
Spring的BeanFactoryPostProcessor是容器初始化的擴展接口,允許在Bean實例化前修改或擴展Bean的配置元數(shù)據(jù),本文給大家介紹Spring 中 BeanFactoryPostProcessor 的作用和示例源碼分析,感興趣的朋友一起看看吧2025-03-03
使用@Service注解出現(xiàn)No bean named 'xxxx'&
這篇文章主要介紹了使用@Service注解出現(xiàn)No bean named 'xxxx' available]錯誤的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08
Java中將base64編碼字符串轉(zhuǎn)換為圖片的代碼
這篇文章主要介紹了Java中將base64編碼字符串轉(zhuǎn)換為圖片,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03

