对象拷贝,entity与vo的各种类型之间相互转换, 不想写连表查询的解决方案

  • Post author:
  • Post category:其他


编写一个工具类, 用于将实体、集合、page的entity与vo之间的类型转换工具类。

在有使用Mybatis Plus的项目框架中,我们从库中查询出来的数据只能映射到实体类, 不能够很好的适应我们的VO对象,而且有时候分页查询时往往会涉及连表查询等等, 通常得通过写sql来得到VO类型的输出。

如果你不想写sql怎么办?只想通过调用简单快捷的Mybatis Plus的方法进行对表操作, 那么就可以使用这个工具类了。

我工作中追求的是减少复杂的开发过程, 提高开发效率,代码可复用化。

进入正题.

通常copy一个对象简单的方法是使用工具类BeanUtils.copyProperties(), 但是对于我们的集合和Page对象束手无策, 但还是先了解一下copyProperties()的使用

BeanUtils.copyProperties(source, target);

source是被复制的对象,target是被赋值的对象。即将source中的数据拷贝到target对象中, 使用前先得new一个target对象。需要注意的是,两个对象之间只有相同字段和类型的值才能被成功拷贝,否则拷贝后需对不成功的字段进行赋值

完整代码

了解了copyProperties()的使用过程, 我们就可以用它作为copy的基础来编写我们的工具类了。

先上一波完整代码,粘贴到你的util中即可, 可通过实例化工具或者直接使用静态方法两种方式调用。

ModelUtil.java

/**
 * 类型转换
 * entity       <----> entityVO,
 * List<entity> <----> List<entityVO>,
 * Page<entity> <----> Page<entityVO>
 * @author Huzz
 * @created 2021-12-07 9:55
 */
@Component
public class ModelUtil<Source, Target> {

    private static final Logger log = LoggerFactory.getLogger(ModelUtil.class);

    /**
     * 通过静态方法调用(单例模式)
     */
    private static ModelUtil modelUtil = new ModelUtil();

    public ModelUtil(){

    }
    /** -----------------------静态方法方式调用-------------------------------------- */
    /**
     * 转换为目标对象
     * @param source 源对象
     * @param type 目标对象类
     * @return 目标对象
     */
    public static Object toEntityStatic(Object source, Class<?> type){
        return modelUtil.toEntity(source, type);
    }

    /**
     * 转换为目标Page对象
     * @param source 源对象
     * @param type 目标类型
     * @return 目标Page对象
     */
    public static Page<?> toPageEntityStatic(Page<?> source, Class<?> type){
        return modelUtil.toPageEntity(source, type);
    }

    /**
     * 转换为目标List对象
     * @param source 源对象
     * @param type 目标类型
     * @return 目标List对象
     */
    public static List<?> toArrayListEntityStatic(List<?> source, Class<?> type){
        return modelUtil.toArrayListEntity(source, type);
    }
    /** -------------------------------------------------------------------------- */

    /**
     * 转换为实体对象
     *
     * @return Target
     */
    public Target toEntity(Source source, Class<Target> type) {
        Target target = createInstance(type);
        BeanUtils.copyProperties(source, target);
        return target;
    }

    /**
     * 实例化对象
     *
     * @param clazz
     * @return
     */
    private Target createInstance(Class<Target> clazz) {
        Target target = null;
        try {
            target = clazz.newInstance();
        } catch (InstantiationException e) {
            log.info("转换为实体对象错误: 实例化{}失败", clazz);
            e.getMessage();
        } catch (IllegalAccessException e) {
            log.info("转换为实体对象错误: 无权访问指定类{}", clazz);
            e.getMessage();
        }
        return target;
    }

    /**
     * Page类型entity转换
     * @param source
     * @param type
     * @return
     */
    public Page<Target> toPageEntity(Page<Source> source, Class<Target> type) {
        Page<Target> target = new Page<>();
        BeanUtils.copyProperties(source, target);
        target.setRecords(toArrayListEntity(source.getRecords(), type));

        return target;
    }

    /**
     * List类型的数据entity转换
     * @param source
     * @param type
     * @return
     */
    private List<Target> toArrayListEntity(List<Source> source, Class<Target> type) {
        List<Target> target = new ArrayList<>();
        source.forEach(e -> {
            Target instance = createInstance(type);
            BeanUtils.copyProperties(e, instance);
            target.add(instance);
        });

        return target;
    }


}

拷贝对象

   /**
     * 转换为实体对象
     *
     * @return Target
     */
    public Target toEntity(Source source, Class<Target> type) {
        Target target = createInstance(type);
        BeanUtils.copyProperties(source, target);
        return target;
    }

   /**
     * 实例化对象
     *
     * @param clazz
     * @return
     */
    private Target createInstance(Class<Target> clazz) {
        Target target = null;
        try {
            target = clazz.newInstance();
        } catch (InstantiationException e) {
            log.info("转换为实体对象错误: 实例化{}失败", clazz);
            e.getMessage();
        } catch (IllegalAccessException e) {
            log.info("转换为实体对象错误: 无权访问指定类{}", clazz);
            e.getMessage();
        }
        return target;
    }

将实体类转换为VO, 反过来也可以

实例化方式:

ModelUtil<User, UserVO> modelUtil = new ModelUtil<>();
UserVO vo = modelUtil.toEntity(user, userVO.class);

使用静态方法方式:

UserVO vo = ModelUtil.toEntityStatic(user, UserVO.class);

拷贝集合

/**
     * List类型的数据entity转换
     * @param source
     * @param type
     * @return
     */
    private List<Target> toArrayListEntity(List<Source> source, Class<Target> type) {
        List<Target> target = new ArrayList<>();
        source.forEach(e -> {
            Target instance = createInstance(type);
            BeanUtils.copyProperties(e, instance);
            target.add(instance);
        });

        return target;
    }

在方法内,每次循环都会实例化一个目标类的对象, 并将原来集合中的一个对象拷贝给该对象,最后返回新集合,使用方式如下:

// 实例化方式
ModelUtil<User, UserVO> modelUtil = new ModelUtil<>();
List<UserVO> vo = modelUtil.toArrayListEntity(userList, UserVO.class);
// 使用静态方式
List<UserVO> vo = ModelUtil.toArrayListEntityStatic(userList, UserVO.class);

拷贝Page

/**
     * Page类型entity转换
     * @param source
     * @param type
     * @return
     */
    public Page<Target> toPageEntity(Page<Source> source, Class<Target> type) {
        Page<Target> target = new Page<>();
        BeanUtils.copyProperties(source, target);
        target.setRecords(toArrayListEntity(source.getRecords(), type));

        return target;
    }

Page对象的拷贝中, 由于存在某些字段的数据类型不一致, 所以拷贝完共同字段后, 需要对类型不同的字段做单独处理, 以上代码中, 只是处理了分页的数据records。records是一个集合, 我们再调用上面的拷贝集合方法即可完成处理。使用

// 实例化方式
        ModelUtil<User, UserVO> modelUtil = new ModelUtil<>();
        List<UserVO> vo = modelUtil.toPageEntity(userPage, UserVO.class);
        // 使用静态方式
        List<UserVO> vo = ModelUtil.toPageEntityStatic(userPage, UserVO.class);

END

有了这些方法后, 如果我们在用Mybatis Plus写集合查询, 但最终的返回类型还要求有其他非实体类字段,比如连表查询后再查询。 对于这种情况,如果我们不想写sql, 可以先分页查询实体类, 然后转换成voList对象; 然后查询另一张表, 将取出来的数据set到voList就好了。



版权声明:本文为qq_44911340原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。