优雅的拷贝不同层的对象(VO,DO等)

发布于 2020-10-26  370 次阅读


编写代码时,因为分层,所以经常需要VO,DO甚至DTO等层对象进行拷贝,DO是数据库对象,VO是要展示到前端的对象,其实Spring提供的BeanUtils拷贝一般对象够了,但是对于List支持还没有,所以自己稍微对于BeanUtils扩展一下,并且对于拷贝对象添加回调方法,便于不同层转换时及时修改一些有差异的字段。

使用方法

public class TestCopyProperty {

    public static void main(String[] args) {
        UserDO userDO = new UserDO();
        userDO.setUsername("username1");
        userDO.setEmail("asd@asd.com");

        UserVO userVO = BeanCopyUtil.copyProperties(userDO, UserVO::new, (udo, uvo) -> {
            //回调修改vo的role字段
            uvo.setRole("role");
        });
        System.out.println(userVO);

        UserVO userVO1 = BeanCopyUtil.copyProperties(userDO, UserVO::new);
        System.out.println(userVO1);

        List<UserDO> userList = Collections.singletonList(userDO);
        List<UserVO> userVOList = BeanCopyUtil.copyListProperties(userList, UserVO::new, (udo, uvo) -> {
            //回调修改vo的role字段
            uvo.setRole("role list");
        });
        System.out.println(userVOList);

        List<UserVO> userVOList1 = BeanCopyUtil.copyListProperties(userList, UserVO::new);
        System.out.println(userVOList1);
    }
}

//Output
UserVO(username=username1, password=null, email=asd@asd.com, role=role, roleName=)
UserVO(username=username1, password=null, email=asd@asd.com, role=null, roleName=)
[UserVO(username=username1, password=null, email=asd@asd.com, role=role list, roleName=)]
[UserVO(username=username1, password=null, email=asd@asd.com, role=null, roleName=)]

实际场景

比如实际使用时,对于分页数据从DO集合转换到VO集合,同时修改VO其中字段

    default PageResult<?> page(QueryBase queryBase, ProjectRepository projectRepository) {
        Pageable pageable = PageRequest.of(queryBase.getJpaPageIndex(), queryBase.getPageSize(), queryBase.getSort());
        Page<TaskDO> pageResult = findAll(pageable);
        List<TaskVO> result = BeanCopyUtil.copyListProperties(pageResult.getContent(), TaskVO::new, (taskDO, taskVO) -> {
            String projectName = projectRepository.findById(taskDO.getProjectId()).map(ProjectDO::getName).orElse("");
            taskVO.setProjectName(projectName);
        });
        return PageResult.build(result).setRecordsTotal(pageResult.getTotalElements());
    }

回调接口

BeanCopyUtilCallBack

@FunctionalInterface
public interface BeanCopyUtilCallBack <S, T> {

    /**
     * 定义默认回调方法
     * @param source 源数据
     * @param target 目标数据
     */
    void callBack(S source, T target);
}

Bean拷贝工具类代码

BeanCopyUtil

import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

/**
 * Bean拷贝工具类
 *
 * @author LoneKing
 * @date 2020/10/22
 */
public class BeanCopyUtil extends BeanUtils {

    /**
     * 对象数据的拷贝
     *
     * @param source   数据源
     * @param target   目标类::new(eg: UserVO::new)
     * @param callBack 回调
     * @param <S>      源数据类型
     * @param <T>      目标数据类型
     * @return 目标数据
     */
    public static <S, T> T copyProperties(S source, Supplier<T> target, BeanCopyUtilCallBack<S, T> callBack) {
        T t = target.get();
        copyProperties(source, t);
        if (callBack != null) {
            // 回调
            callBack.callBack(source, t);
        }
        return t;
    }

    /**
     * 对象数据的拷贝
     *
     * @param source 数据源
     * @param target 目标类::new(eg: UserVO::new)
     * @param <S>    源数据类型
     * @param <T>    目标数据类型
     * @return 目标数据
     */
    public static <S, T> T copyProperties(S source, Supplier<T> target) {
        return copyProperties(source, target, (BeanCopyUtilCallBack<S, T>) null);
    }

    /**
     * 集合数据的拷贝
     *
     * @param sources: 数据源
     * @param target:  目标类::new(eg: UserVO::new)
     * @param <S>      源数据类型
     * @param <T>      目标数据类型
     * @return List<T>
     */
    public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target) {
        return copyListProperties(sources, target, null);
    }


    /**
     * 带回调函数的集合数据的拷贝(可自定义字段拷贝规则)
     *
     * @param sources:  数据源
     * @param target:   目标类::new(eg: UserVO::new)
     * @param callBack: 回调函数
     * @param <S>       源数据类型
     * @param <T>       目标数据类型
     * @return List<T>
     */
    public static <S, T> List<T> copyListProperties(List<S> sources, Supplier<T> target, BeanCopyUtilCallBack<S, T> callBack) {
        List<T> list = new ArrayList<>(sources.size());
        for (S source : sources) {
            T t = target.get();
            copyProperties(source, t);
            if (callBack != null) {
                // 回调
                callBack.callBack(source, t);
            }
            list.add(t);
        }
        return list;
    }
}


LoneKing