对象工具类复制方法的推演

175 阅读3分钟

SpringBoot 中BeanUtils.copyProperties方法的详解

前言

开发过程中,讲一个对象的属性和值赋值到另一个对象上,大量使用了get、set方法,看着很臃肿,思考下肯定不只有我有这种想法,所以技术上肯定有方法能解决这个问题,所以查阅了一些资料发现了BeanUtils.copyProperties这个方法以下是这次所有的总结以及使用时的注意事项。 使用org.springframework.beans.BeanUtils.copyProperties方法进行对象之间属性的赋值,避免通过get、set方法一个一个属性的赋值。

一般使用

BeanUtils是这个包里比较常用的一个工具类,该方法定义如下:

public static void copyProperties(java.lang.Object dest,java.lang.Object orig)
   throws java.lang.IllegalAccessException,
      java.lang.reflect.InvocationTargetException

如 果你有两个具有很多相同属性的JavaBean,一个很常见的情况就是Struts里的PO对象(持久对象)和对应的ActionForm,例如 Teacher和TeacherForm。我们一般会在Action里从ActionForm构造一个PO对象,传统的方式是使用类似下面的语句对属性逐 个赋值:

//1得到TeacherForm
TeacherForm teacherForm=(TeacherForm)form;
//2构造Teacher对象
Teacher teacher=new Teacher();
//3赋值
teacher.setName(teacherForm.getName());
teacher.setAge(teacherForm.getAge());
teacher.setGender(teacherForm.getGender());
teacher.setMajor(teacherForm.getMajor());
teacher.setDepartment(teacherForm.getDepartment());
//4持久化Teacher对象到数据库
HibernateDAO=;
HibernateDAO.save(teacher);

而使用BeanUtils后,代码就大大改观了,如下所示:

//1得到TeacherForm
TeacherForm teacherForm=(TeacherForm)form;
//2构造Teacher对象
Teacher teacher=new Teacher();
//3赋值
BeanUtils.copyProperties(teacher,teacherForm);
//4持久化Teacher对象到数据库
HibernateDAO=;
HibernateDAO.save(teacher);

如 果Teacher和TeacherForm间存在名称不相同的属性,则BeanUtils不对这些属性进行处理,需要程序员手动处理。例如 Teacher包含modifyDate(该属性记录最后修改日期,不需要用户在界面中输入)属性而TeacherForm无此属性,那么在上面代码的 copyProperties()后还要加上一句:

teacher.setModifyDate(new Date());

Entity 与 Dto 之间的转换

在项目中,经常会有Entity与Dto之间的转换,例如Bo与Entity之间的转换,具体操作为

public static Entity toEntity(Bo bo){
    Entity e = new Entity();
    BeanUtils.copyProperties(bo,e);
    return e;
}

public static List<Entity> toEntity(List<Bo> boList){
    return boList.stream().map(this::toEntity).collect(Collectors.toList());
}

public static Page<Entity> toEntity(Page<Bo> boList){
    return new PageImpl<>(
            toEntity(boList.getContent()),
            boList.getPageable(),
            boList.getTotalElements()
    );
}

转换方法的封装

因为每有一个Entity,Dto,就要写一遍转换方法,小编觉得有点烦了,而且无法忽略字段,于是就想有么有一个父类,让他们去继承,就省去写那些方法了,于是小编就花半天去研究,发现面向切面可以做出,就编写了一个Basic抽象类,具体操作为

package cn.jenson.common;

import org.springframework.beans.BeanUtils;

import java.util.List;
import java.util.stream.Collectors;

public abstract class BasicBo<E,B> {
    public E toEntity(B b,Class<E> eClass,String... ignoreProperties) throws InstantiationException, IllegalAccessException {
        E e = eClass.newInstance();
        BeanUtils.copyProperties(b,e,ignoreProperties);
        return e;
    }

    public List<E> toEntity(List<B> bList,Class<E> eClass,String... ignoreProperties){
        return bList.stream().map(it -> {
            try {
                return toEntity(it,eClass,ignoreProperties);
            } catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }).collect(Collectors.toList());
    }
}
package cn.jenson.common;

import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;

import java.util.List;
import java.util.stream.Collectors;

public abstract class BasicVo<E,V> {
    public V fromEntity(E e,Class<V> vClass,String... ignoreProperties) throws InstantiationException, IllegalAccessException {
        V v = vClass.newInstance();
        BeanUtils.copyProperties(e,v,ignoreProperties);
        return v;
    }

    public List<V> fromEntity(List<E> eList,Class<V> vClass,String... ignoreProperties){
        return eList.stream().map(it -> {
            try {
                return fromEntity(it,vClass,ignoreProperties);
            } catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }).collect(Collectors.toList());
    }

    public Page<V> fromEntity(Page<E> ePage,Class<V> vClass,String... ignoreProperties){
        return new PageImpl<>(
                fromEntity(ePage.getContent(),vClass,ignoreProperties),
                ePage.getPageable(),
                ePage.getTotalElements()
        );
    }
}

对象工具类复制方法的封装

虽然Basic抽象类可以实现指定的两个对象的转换,但是感觉还是太死板了,而且每用一次方法都要 new 一个对象,于是想能不能有一个工具类,即使静态方法,又能不同对象相同字段间的转换,于是又花了半天时间编写了工具类,具体如下:

package cn.jenson.util;

import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;

import java.util.List;
import java.util.stream.Collectors;

public final class ObjectsUtil {

    public static <O> O copyProperties(Object object, Class<O> oClass, String... ignoreProperties) throws InstantiationException, IllegalAccessException {
        O o = oClass.newInstance();
        BeanUtils.copyProperties(object, o);
        return o;
    }

    public static <O> List<O> copyProperties(List<?> objectList,Class<O> oClass,String... ignoreProperties){
        return objectList.stream().map(it -> {
            try {
                return copyProperties(it,oClass,ignoreProperties);
            } catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }).collect(Collectors.toList());
    }

    public static <O> Page<O> copyProperties(Page<?> objectPage,Class<O> oClass,String... ignoreProperties){
        return new PageImpl<>(
                copyProperties(objectPage.getContent(),oClass,ignoreProperties),
                objectPage.getPageable(),
                objectPage.getTotalElements()
        );
    }
}