若依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秒左右!所以是大数据量是很有必要的
这里我需要修改的请求太多了 公司里的数据还不是很多这样的意义不是很大 工时又很紧 所以我就不“更上一层楼”了 快速交付任务才是王道!

Logo

快速构建 Web 应用程序

更多推荐