亲宝软件园·资讯

展开

Java对象转换

Real_man​​​​​​​ 人气:0

前言

系统变的复杂,系统的层次划分越来越细,边界也越来越明确。 然后每一层之间一般都有自己要处理的领域对象,统称为pojo一般在model或者domain包下(类的后缀不能为pojo)。

常见的一些模型类型:

为什么模型要分这么多层?

在复杂一点的业务中,业务建模是非常有必要的,一定要抽象出业务上常用的领域模型,统一技术和非技术同学的语言。

建完模型之后,在技术的系统中,为了方便维护代码,分离关注点,也会进行再次分层,让每一层解决特定的问题。模型的分层是随着系统的分层而来的;试想所有的模型属性在一个对象中,这个对象你看的懂吗?

举个实际的案例:

简单说就是当我们的系统要输出能力到外部系统的时候,不同系统要的数据不一样,数据安全要求我们不能透出这么多的数据,一定要做一层处理。 另外给另外一个系统关注的数据,而不是一股脑的全部都给对方,对方处理起来也方便。

模型之间的转换

建议不要用的方式

常用的方式

以上从技术分类的角度来看:

使用方式

个人觉得,如果说对象比较简单的时候,使用BeanCopier就可以了,因为spring的aop依赖cglib,默认情况下就已经引入了对应的包了,不需要额外的依赖直接就可以用。

如果很复杂的模型之间的转换,并且对性能有更极致的要求,考虑使用下MapStruct。

定义对象

UserDO

@Data
public class UserDO {
  private Long id;
  private String name;
  private Integer gender;
  private String password;
  private Date gmtCreate;
  private Date gmtModified;
}

UserDTO

@Data
public class UserDTO {
  private Long id;
  private String name;
  private Integer gender;
}

BeanCopier

最简单的使用方式

BeanCopier beanCopier = BeanCopier.create(UserDO.class, UserDTO.class, false); bean.copy即可;

private static void simpleBeanCopy() {
    BeanCopier beanCopier = BeanCopier.create(UserDO.class, UserDTO.class, false);
    UserDO userDO = new UserDO();
    userDO.setId(1L);
    userDO.setName("aihe");
    userDO.setGmtCreate(new Date());
    userDO.setGender(0);
    userDO.setPassword("xxxxxx");
    UserDTO userDTO = new UserDTO();
    beanCopier.copy(userDO, userDTO,null);
    Assert.assertEquals("名称未成功拷贝",userDTO.getName(),"aihe");
    Assert.assertEquals("Id未成功拷贝", 1L, (long)userDTO.getId());
    Assert.assertEquals("性别未成功拷贝", Integer.valueOf(0),userDTO.getGender());
  }

创建可复用的BeanCopier工具类

package me.aihe.daka;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.sf.cglib.beans.BeanCopier;
/**
 * @author : aihe 
 * @date : 2022/9/12 9:21 AM
 * 使用场景:
 * 功能描述:
 */
public class BeanCopyUtils {

    /**
     * beanCopier缓存
     * 由sourceClass和targetClass可以确定一个唯一的BeanCoper,因此使用二级Map;
     */
    private static Map<Class<?>, Map<Class<?>, BeanCopier>> beanCopierMap = new ConcurrentHashMap<>();
    /**
     * 直接指定Bean对象进行拷贝
     * @param sourceBean
     * @param targetBean
     * @param <S>
     * @param <T>
     */
    public static <S,T> void copy(S sourceBean,T targetBean){
        @SuppressWarnings("unchecked")
        Class<S> sourceClass = (Class<S>) sourceBean.getClass();
        @SuppressWarnings("unchecked")
        Class<T> targetClass = (Class<T>) targetBean.getClass();

        BeanCopier beanCopier = getBeanCopier(sourceClass,targetClass);
        beanCopier.copy(sourceBean,targetBean,null);
    }
    /**
     * 转换方法
     * @param sourceBean 原对象
     * @param targetClass 目标类
     * @param <S>
     * @param <T>
     * @return
     */
    public static <S,T> T convert(S sourceBean,Class<T> targetClass){
        try {
            assert sourceBean!=null;
            T targetBean = targetClass.newInstance();
            copy(sourceBean,targetBean);
            return targetBean;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    private static <S,T> BeanCopier getBeanCopier(Class<S> sourceClass, Class<T> targetClass ){
        Map<Class<?>,BeanCopier> map = beanCopierMap.get(sourceClass);
        if(map == null || map.isEmpty()){
            BeanCopier newBeanCopier = BeanCopier.create(sourceClass, targetClass, false);
            Map<Class<?>,BeanCopier> newMap = new ConcurrentHashMap<>();
            newMap.put(targetClass,newBeanCopier);
            beanCopierMap.put(sourceClass,newMap);
            return newBeanCopier;
        }
        BeanCopier beanCopier = map.get(targetClass);
        if(beanCopier == null){
            BeanCopier newBeanCopier = BeanCopier.create(sourceClass, targetClass, false);
            map.put(targetClass,newBeanCopier);

            return newBeanCopier;
        }
        return beanCopier;
    }
}

同上:

UserDO userDO = new UserDO();
    userDO.setId(1L);
    userDO.setName("aihe");
    userDO.setGmtCreate(new Date());
    userDO.setGender(0);
    userDO.setPassword("xxxxxx");
    UserDTO userDTO = new UserDTO();
    BeanCopyUtils.copy(userDO, userDTO);
    Assert.assertEquals("名称未成功拷贝",userDTO.getName(),"aihe");
    Assert.assertEquals("Id未成功拷贝", 1L, (long)userDTO.getId());
    Assert.assertEquals("性别未成功拷贝", Integer.valueOf(0),userDTO.getGender());

MapStruct

案例集:github.com/mapstruct/m…

引入mapstruct

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <org.mapstruct.version>1.5.2.Final</org.mapstruct.version>
        <org.projectlombok.version>1.18.20</org.projectlombok.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${org.mapstruct.version}</version>
        </dependency>

        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>${org.mapstruct.version}</version>
            <!-- IntelliJ does not pick up the processor if it is not in the dependencies.
             There is already an open issue for IntelliJ see https://youtrack.jetbrains.com/issue/IDEA-150621
            -->
            <scope>provided</scope>
        </dependency>
       
         <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${org.projectlombok.version}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

简单Demo

定义Mapper

@Mapper
public interface UserDTOMapper {

    UserDTOMapper MAPPER = Mappers.getMapper( UserDTOMapper.class );
    //@Mapping( source = "test", target = "testing" )
    //@Mapping( source = "test1", target = "testing2" )
    UserDTO toTarget( UserDO s );
}

使用:

public static void main( String[] args ) {
        //simpleDemo();
        UserDO userDO = new UserDO();
        userDO.setId(1L);
        userDO.setName("aihe");
        userDO.setGmtCreate(new Date());
        userDO.setGender(0);
        userDO.setPassword("xxxxxx");
        UserDTO userDTO = UserDTOMapper.MAPPER.toTarget(userDO);
        Assert.assertEquals("名称未成功拷贝",userDTO.getName(),"aihe");
        Assert.assertEquals("Id未成功拷贝", 1L, (long)userDTO.getId());
        Assert.assertEquals("性别未成功拷贝", Integer.valueOf(0),userDTO.getGender());
    }

常见用法

@Mapping(target = "userNick1", source = "userNick")
@Mapping(target = "createTime", source = "createTime", dateFormat = "yyyy-MM-dd")
@Mapping(target = "age", source = "age", numberFormat = "#0.00")
@Mapping(target = "id", ignore = true)
@Mapping(target = "userVerified", defaultValue = "defaultValue-2")
UserDTO toTarget( UserDO s );

性能测试

测试代码

import java.util.Date;
import com.alibaba.fastjson.JSON;
import org.junit.Before;
import org.junit.Test;
/**
 * @author : aihe aihe.ah@alibaba-inc.com
 * @date : 2022/9/12 9:47 AM
 * 使用场景:
 * 功能描述:
 */
public class BenchDemoTest{

  /**
   * 转化对象
   */
  private UserDO userDO;

  /**
   * 转化次数
   */
  private final static int count = 1000000;
  @Before
  public void before() {
    userDO = new UserDO();
    userDO.setId(1L);
    userDO.setName("aihe");
    userDO.setGmtCreate(new Date());
    userDO.setGender(0);
    userDO.setPassword("xxxxxx");
  }
  @Test
  public void mapstruct() {
    long startTime = System.currentTimeMillis();
    for (int i = 1; i <=count; i++) {
      UserDTO userDTO = UserDTOMapper.MAPPER.toTarget(userDO);
    }
    System.out.println("mapstruct time" + (System.currentTimeMillis() - startTime));
  }
  @Test
  public void beanCopier() {
    long startTime = System.currentTimeMillis();
    for (int i = 1; i <= count; i++) {
      UserDTO targetBean = new UserDTO();
      BeanCopyUtils.copy(userDO, targetBean);
    }
    System.out.println("beanCopier time" + (System.currentTimeMillis() - startTime));
  }
  @Test
  public void springBeanUtils(){
    long startTime = System.currentTimeMillis();
    for (int i = 1; i <=count; i++) {
      UserDTO userDTO = new UserDTO();
      org.springframework.beans.BeanUtils.copyProperties(userDO, userDTO);
    }
    System.out.println("springBeanUtils time" + (System.currentTimeMillis() - startTime));
  }
  @Test
  public void fastjson() {
    long startTime = System.currentTimeMillis();
    for (int i = 1; i <= count; i++) {
      JSON.parseObject(JSON.toJSONString(userDO), UserDTO.class);
    }
    System.out.println("fastjson time" + (System.currentTimeMillis() - startTime));
  }
}

测试结果

最后

总结下本文的内容:

加载全部内容

相关教程
猜你喜欢
用户评论