Vo對象,Dao對象,Dto對象的部分屬性複製BeanCopier&BeanUtils

在實際的開發中,存在Vo對象,Dao對象,DTO對象的部分屬性複製的問題
比較笨的辦法 A.setxxx(B.getXXX),費時又費力,怎麼解決這個問題呢?
推薦使用兩種對象屬性複製的辦法:
對象屬性拷貝的兩種方式:
一、BeanUtils(注意BeanUtils使用的是spring的Beanutils的)
二、BeanCopierjava

先準備三個Vo對象,Dao對象,Dto對象,後面咱們對這三個對象進行拷貝和複製。git

@Data
@AllArgsConstructor
public class UserDo {

    private int id;
    private String userName;
    private LocalDateTime gmtBroth;
    private BigDecimal balance;
}
@Data
public class UserDto {
    private int id;
    private String userName;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserVo {
    private int id;
    private String userName;
    private String gmtBroth;
    private String agevo;
}

第一種方式使用BeanUtils進行拷貝github

import org.springframework.beans.BeanUtils;
@Slf4j
public class BeanCopyTest {

     public static void main(String[] args) {
    UserDo userDo=new UserDo(1,"sunyuhau", LocalDateTime.now(),new BigDecimal(100L));
    log.info("拷貝前=="+userDo);
    UserVo userVo=new UserVo();
    BeanUtils.copyProperties(userDo,userVo);
    log.info("拷貝後==="+userVo);
    }
}

輸出結果爲:
在這裏插入圖片描述
可是這種方法耗時比較長,線上有點不能知足需求。因此引出了第二種方案:
BeanCopierspring

long startTime2=System.currentTimeMillis();
        UserDo userDo1=DataUtil.createData();
        log.info("拷貝前 userDo1:{}",userDo1);
        //將userDo拷貝到userdto,false表明是不使用自定義轉化器
        BeanCopier beanCopier=BeanCopier.create(UserDo.class,UserDto.class,false);
        UserDto userDto=new UserDto();
        //不使用conberter方式,僅對兩個bean對象屬性名和類型徹底相同的變量進行拷貝。
        beanCopier.copy(userDo1,userDto,null);
        log.info("拷貝後 :userDto:{}",userDto);
        log.info("耗時:"+(System.currentTimeMillis()-startTime2));

BeanCopier 有兩種方式,一個是conberter,一個是不使用自定義的conberter,上面的不使用自定義器的。緩存

long startTime3=System.currentTimeMillis();
        UserDo userDo2=DataUtil.createData();
        log.info("拷貝前:{}",userDo2);
        BeanCopier.create(UserDo.class,UserVo.class,true);
        UserDo userDo3=DataUtil.createData();
        log.info("拷貝前:userDo:{}",userDo3);
        BeanCopier beanCopier1 = BeanCopier.create(UserDo.class, UserVo.class, true);
        UserConverter userConverter=new UserConverter();
        UserVo uservo3=new UserVo();
        beanCopier1.copy(userDo3,uservo3,userConverter);
        log.info("拷貝後==userDo:{}",uservo3);
        log.info("耗時3:"+(System.currentTimeMillis()-startTime3));
/**
 * 自定義的user對象的轉化器
 * 一旦使用converter,BeanCopier只使用converter定義的規則去拷貝,因此在convert()方法中要考慮全部的屬性
 * 而且converter會是對象拷貝速度變慢。
 *
 */
public class UserConverter implements Converter {

    DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss");
    @Override
    public Object convert(Object o, Class aClass, Object o1) {
        if(o instanceof Integer){
            return o;
        }else if(o instanceof LocalDateTime){
            LocalDateTime date=(LocalDateTime)o;
            return dateTimeFormatter.format(date);
        }else if(o instanceof BigDecimal){
            BigDecimal bigDecimal=(BigDecimal)o;
            return bigDecimal.toPlainString();
        }
        return o;
    }
}

無論使不使用自定義的轉化器,都有還有一個弊端,就是每次都初始化 BeanCopier beanCopier=BeanCopier.create(UserDo.class,UserDto.class,false);
BeanCopier beanCopier1 = BeanCopier.create(UserDo.class, UserVo.class, true);
這個點是沒必要須的。因此能夠將這個初始化到內存中,這樣就沒有必要每次都生成 BeanCopier。
具體的作法以下:ide

import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.beans.BeanCopier;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public  class BeanCopierWithCacheUtil {
    private static  ConcurrentHashMap<String,BeanCopier> BEAN_COPIERS = new ConcurrentHashMap<>() ;

    static void beanCopierWithCache() {
        List<UserDo> userDOList = DataUtil.createDataList(10000);
        long start = System.currentTimeMillis();
        List<UserDto> userDtos = new ArrayList<>();
        userDOList.forEach(userDo -> {
            UserDto userDTO = new UserDto();
            //將userDo對象的參數,複製到userDTO對象
            copy(userDo, userDTO);
            userDtos.add(userDTO);
        });
        log.info("BeanCopier 加緩存後 costTime: {}ms", System.currentTimeMillis() - start);

    }

    /**
     * 將不用類型轉化的copier = BeanCopier.create(srcObj.getClass(), destObj.getClass(), false) 放入內存
     * 第一次初始化的時候將BeanCopier,初始到內存中,下次再次使用時。直接使用。
     * @param srcObj
     * @param destObj
     */
    public static void copy(Object srcObj, Object destObj) {
        String key = genKey(srcObj.getClass(), destObj.getClass());
        BeanCopier copier = null;
        if (!BEAN_COPIERS.containsKey(key)) {
            copier = BeanCopier.create(srcObj.getClass(), destObj.getClass(), false);
            BEAN_COPIERS.put(key, copier);
        } else {
            copier = BEAN_COPIERS.get(key);
        }
        copier.copy(srcObj, destObj, null);
    }

    /**
     * 將轉化的類的名字和被轉化類型的名字做爲key,保存到內存中
     * @param srcClazz
     * @param destClazz
     * @return
     */
    private static String genKey(Class<?> srcClazz, Class<?> destClazz) {
        return srcClazz.getName() + destClazz.getName();
    }

}
log.info("+++++++++++BeanCopier放在緩存中+++++++++++++++");
        //注意第一次是初始化BeanCopier,時間會比較長
        BeanCopierWithCacheUtil beanCopierWithCacheUtil=new BeanCopierWithCacheUtil();
        beanCopierWithCacheUtil.beanCopierWithCache();

這樣耗時就會更短,轉化的效率就更高了。
本篇文章由一文多發平臺ArtiPub自動發佈spa

相關文章
相關標籤/搜索