若依VO类返回给前端项目,copy不同类型的list
首先简述一下VO包的作用
他是后端打包数据发给前端的一种方式
应用场景比如后台会储存的数据比较全 然后前端显示的数据没必要创建时间,修改时间,创建人等等的数据都取到!
这个时候VO就出场了
你可以把你的类简化版存成VO包里然后用vo打包发给前端
这个时候不想修改mapper文件了(这种做法是偷懒!没有减轻对数据库的压力,只是减轻了数据传输的压力)
然后从数据库取出的类型比如是List<SysUnify> 里面什么信息都有
然而前端只需要List<SysUnifyCounselorVo>中的数据
这个是时候就要考虑怎么能快速的把List<SysUnify>中List<SysUnifyCounselorVo>有的字段copy进去
使用for while 。。。。
其实都行但是写一大堆就没必要了
而且我有很多这种类型要转换 麻烦死了 这个时候主教登场了
orika:
简介:Orika是java Bean映射框架,可以实现从一个对象递归拷贝数据至另一个对象。在开发多层应用程序中非常有用。在这些层之间交换数据时,通常为了适应不同API需要转换一个实例至另一个实例。
使用之前maven需要引入
<dependency>
<groupId>com.gitlab.haynes</groupId>
<artifactId>orika-spring-boot-starter</artifactId>
<version>1.26.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>3.4.3.4</version>
</dependency>
前面那个引入可以理解但事后面那个在util中有用到所以这里也一并引入了
说到util累了那肯定就是Orika有自己的工具类
package com.ruoyi.system.utils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.SneakyThrows;
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.MappingContext;
import ma.glasnost.orika.converter.BidirectionalConverter;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import ma.glasnost.orika.metadata.ClassMapBuilder;
import ma.glasnost.orika.metadata.Type;
import ma.glasnost.orika.metadata.TypeFactory;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* 实体类转互相转换工具
* @author xuxilan
*/
public class OrikaUtils {
/**
* 获取默认字段工厂
*/
private static final MapperFactory MAPPER_FACTORY;
/**
* 默认字段实例
*/
private static final MapperFacade MAPPER_FACADE;
/**
* 默认字段实例集合
*/
private static final Map<String, MapperFacade> CACHE_MAPPER_FACADE_MAP;
static {
// mapNulls 表示 原对象中的null不会拷贝到目标对象
MAPPER_FACTORY = new DefaultMapperFactory.Builder().mapNulls(false).build();
MAPPER_FACTORY.getConverterFactory().registerConverter(new DateToString());
MAPPER_FACTORY.getConverterFactory().registerConverter(new TimestampToString());
MAPPER_FACADE = MAPPER_FACTORY.getMapperFacade();
CACHE_MAPPER_FACADE_MAP = new ConcurrentHashMap<>();
}
/**
* 映射实体(默认字段)
* 这种映射就是DTO字段名称和实体对象PO之间字段名称一致
* @param source 数据(对象)DO对象
* @param toClass 映射类对象 DTO对象
* @return 映射类对象
*/
public static <S, D> D convert(S source, Class<D> toClass) {
return MAPPER_FACADE.map(source, toClass);
}
/**
* 映射实体(自定义配置)
* @param targetClass 映射类对象
* @param source 数据(对象)
* @param configMap 自定义配置不同字段的对应关系
* @param <S> 源对象类型
* @param <D> 目标对象类型
* @return 映射类对象
*/
public static <S, D> D convert(S source, Class<D> targetClass, Map<String, String> configMap) {
MapperFacade mapperFacade = getMapperFacade(targetClass, source.getClass(), configMap);
return mapperFacade.map(source, targetClass);
}
/**
* 将源对象的值拷贝到目标对象中,源对象中的null属性不拷贝到目标对象。
* @param source 源对象
* @param target 目标对象
* @param <S> 源对象类型
* @param <D> 目标对象类型
*/
public static <S, D> void copy(S source, D target) {
MAPPER_FACADE.map(source, target);
}
/**
* 映射集合(默认字段)
* 映射为集合的形式
* @param targetClass 映射类对象 DTO对象
* @param sources 数据(集合) DO对象
* @return 映射类对象
*/
public static <S, D> List<D> converts(Iterable<S> sources, Class<D> targetClass) {
return MAPPER_FACADE.mapAsList(sources, targetClass);
}
/**
* 映射 mybatis 分页字段集合,需要字段一样
* 映射为集合的形式
* @param targetClass 映射类对象 DTO对象
* @param source 数据(集合) DO对象
* @return 映射类对象
*/
public static <S, D> Page<D> page(Page<S> source, Class<D> targetClass) {
Page<D> dPage = convert(source, Page.class);
dPage.setRecords(converts(source.getRecords(), targetClass));
return dPage;
}
/**
* 映射集合(自定义配置)
* @param targetClass 映射类
* @param source 数据(集合)
* @param configMap 自定义配置不同字段的对应关系
* @return 映射类对象
*/
public static <S, D> List<D> converts(Collection<S> source, Class<D> targetClass, Map<String, String> configMap) {
if (source.iterator().next() == null) {
return null;
}
/*S t = source.stream().findFirst().orElseThrow(() -> new WqException(CodeEnum.ERROR));
MapperFacade mapperFacade = getMapperFacade(targetClass, t.getClass(), configMap);*/
MapperFacade mapperFacade = getMapperFacade(targetClass, source.iterator().next().getClass(), configMap);
return mapperFacade.mapAsList(source, targetClass);
}
/**
* 映射集合(自定义配置)
* @param source 数据(集合)
* @param sourceClass 数据源映射类
* @param targetClass 目标映射类
* @param configMap 自定义配置不同字段的对应关系
* @return 映射类对象
*/
public static <S, D> List<D> converts(Collection<S> source, Class<S> sourceClass, Class<D> targetClass, Map<String, String> configMap) {
MapperFacade mapperFacade = getMapperFacade(targetClass, sourceClass, configMap);
return mapperFacade.mapAsList(source, targetClass);
}
/**
* 获取自定义映射
* @param sourceClass 映射类
* @param targetClass 数据映射类
* @param configMap 自定义配置
* @return 映射类对象
*/
private static <S, D> MapperFacade getMapperFacade(Class<S> sourceClass, Class<D> targetClass, Map<String, String> configMap) {
String mapKey = targetClass.getCanonicalName() + "_" + sourceClass.getCanonicalName();
MapperFacade mapperFacade = CACHE_MAPPER_FACADE_MAP.get(mapKey);
if (Objects.isNull(mapperFacade)) {
ClassMapBuilder<D, S> classMapBuilder = classMap(sourceClass, targetClass);
configMap.forEach(classMapBuilder::field);
classMapBuilder.byDefault().register();
mapperFacade = MAPPER_FACTORY.getMapperFacade();
CACHE_MAPPER_FACADE_MAP.put(mapKey, mapperFacade);
}
return mapperFacade;
}
/**
* 简单复制出新对象列表到数组
* 通过source.getComponentType() 获得源Class
* destinationType
* @param <S> 源对象类型
* @param <D> 目标对象类型
* @param target 目标对象数组
* @param source 源对象数组
* @param targetClass 目标类型
* @return 目标对象对象数组
*/
public static <S, D> D[] convertArray(final S[] source, final D[] target, final Class<D> targetClass) {
return MAPPER_FACADE.mapAsArray(target, source, targetClass);
}
/**
*
* @param source 源对象
* @param target 目标对象
* @param <S> 源对象类型
* @param <D> 目标对象类型
* @return 处理的目标对象
*/
public static <S, D> ClassMapBuilder<D, S> classMap(Class<S> source, Class<D> target) {
return MAPPER_FACTORY.classMap(target, source);
}
/**
* 预先获取orika转换所需要的Type,避免每次转换.
* @param <S> 对象类型
* @param rawType 要转换的类型
* @return 转换后的类型
*/
public static <S> Type<S> getType(final Class<S> rawType) {
return TypeFactory.valueOf(rawType);
}
/**
* Date 转为 yyyy-MM-dd HH:mm:ss 时间格式
*/
static class DateToString extends BidirectionalConverter<Date, String> {
@Override
public String convertTo(Date date, Type<String> type, MappingContext mappingContext) {
//可以转成你想要的格式 yyyy/MM/dd HH:mm:ss 等等
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return format.format(date);
}
@SneakyThrows
@Override
public Date convertFrom(String s, Type<Date> type, MappingContext mappingContext) {
/*SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return format.parse(s);*/
return null;
}
}
/**
* Timestamp 转为 yyyy-MM-dd HH:mm:ss 时间格式
*/
static class TimestampToString extends BidirectionalConverter<Timestamp, String> {
@Override
public String convertTo(Timestamp date, Type<String> type, MappingContext mappingContext) {
//可以转成你想要的格式 yyyy/MM/dd HH:mm:ss 等等
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return format.format(date);
}
@SneakyThrows
@Override
public Timestamp convertFrom(String s, Type<Timestamp> type, MappingContext mappingContext) {
return null;
}
}
}
拿去抄上就行了
使用的就可以
使用前先引入:
@Autowired
private MapperFacade mapperFacade;
List<SysUnify> list = sysUnifyService.selectSysUnifyListByProjectType(sysUnify);
List<SysUnifyCounselorVo> listVo;
//copy不同类型但是有相同字段的list
listVo = mapperFacade.mapAsList(list, SysUnifyCounselorVo.class);
这样就完成了
注意
目前还有点问题,目前自动复制不支持albaba的json2类型直接复制过去!
来看看效果 这是类处理前的
这是处理后的
没对比就没伤害
其实还有更上一层楼的做法这里简单演示一下
mapper文件原本是这样的
<sql id="selectSysUnifyVo">
select id, img_path, title, url_path, text_content, name_content, work_type,
phone, age, immigrant_nation, immigrant_type, apply_time, approve_time,
lead_content, urls, created_at, updated_at, deleted_at, project_status,
project_type, create_user, unify_sort
from sys_unify
</sql>
<select id="selectSysUnifyList" parameterType="SysUnify" resultMap="SysUnifyResult">
<include refid="selectSysUnifyVo"/>
<where>
<if test="imgPath != null and imgPath != ''"> and img_path = #{imgPath}</if>
<if test="title != null and title != ''"> and title = #{title}</if>
<if test="urlPath != null and urlPath != ''"> and url_path = #{urlPath}</if>
<if test="textContent != null and textContent != ''"> and text_content = #{textContent}</if>
<if test="nameContent != null and nameContent != ''"> and name_content = #{nameContent}</if>
<if test="workType != null "> and work_type = #{workType}</if>
<if test="phone != null and phone != ''"> and phone = #{phone}</if>
<if test="age != null and age != ''"> and age = #{age}</if>
<if test="immigrantNation != null and immigrantNation != ''"> and immigrant_nation = #{immigrantNation}</if>
<if test="immigrantType != null and immigrantType != ''"> and immigrant_type = #{immigrantType}</if>
<if test="applyTime != null "> and apply_time = #{applyTime}</if>
<if test="approveTime != null "> and approve_time = #{approveTime}</if>
<if test="leadContent != null and leadContent != ''"> and lead_content = #{leadContent}</if>
<if test="urls != null and urls != ''"> and urls = #{urls}</if>
<if test="createdAt != null "> and created_at = #{createdAt}</if>
<if test="updatedAt != null "> and updated_at = #{updatedAt}</if>
<if test="deletedAt != null "> and deleted_at = #{deletedAt}</if>
<if test="createUser != null "> and create_user = #{createUser}</if>
and project_status != 1
<if test="projectType != null "> and project_type = #{projectType}</if>
<if test="createUser != null "> and create_user = #{createUser}</if>
<if test="unifySort != null "> and unity_sort = #{unifySort}</if>
</where>
order by unify_sort asc
</select>
咱们可以修改这里:
<sql id="selectSysUnifyVo">
select id, img_path, name_content, work_type,
created_at, updated_at, deleted_at, project_status,
project_type, create_user, unify_sort
from sys_unify
</sql>
<select id="selectSysUnifyList" parameterType="SysUnify" resultMap="SysUnifyResult">
<include refid="selectSysUnifyVo"/>
<where>
and project_status != 1
<if test="projectType != null "> and project_type = #{projectType}</if>
</where>
order by unify_sort asc
</select>
上面是若依自动生成的代码,很全面,if(一级)判断多了点但是不影响性能
if条件改不改都无所谓 最主要的是前面的SQL返回字段的个数减少了不需要的
数据库的数据条数少的情况下少返回几个字段没意义,但是数据多了百万级数据,计算多返回一个字段会慢 0.000001秒的话,请求一次就会慢5秒左右!所以是大数据量是很有必要的
这里我需要修改的请求太多了 公司里的数据还不是很多这样的意义不是很大 工时又很紧 所以我就不“更上一层楼”了 快速交付任务才是王道!