iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java对象转换的方案分享
  • 123
分享到

Java对象转换的方案分享

2024-04-02 19:04:59 123人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

目录前言为什么模型要分这么多层?模型之间的转换建议不要用的方式常用的方式使用方式定义对象BeanCopier最简单的使用方式创建可复用的BeanCopier工具类MapStruct引

前言

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

常见的一些模型类型:

  • PO、DO:持久层对象,一般和数据库直接打交道。
  • DTO:数据传输对象,系统之间的交互,再服务层提供服务的时候输出到其它系统。
  • VO:视图对象,用于前端模型展示。 当然有时候前端也可以看做另外一个系统,使用DTO模型;
  • BO:业务逻辑对象,比较少用...

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

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

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

举个实际的案例:

  • 数据层一般用DO
  • 现在要透出数据给其他系统,DO中一般都会有创建人,创建时间,修改人,修改时间,当前对象所处的环境等信息; 但是外部的系统需要环境、创建人信息吗? 很多时候不需要,站在数据安全的角度,一般只透出必要的字段就可以; 这些要输出要外部系统的必要字段,一般定义在DTO中。
  • 到前端系统,前端系统展示上所需的逻辑和输出到外部系统的又有点不太一样,前端系统可能要创建人,创建时间,但是不要另外一些东西,或者一些敏感的配置不能透出给前端,这个时候一般也会再定义一个新的对象。

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

模型之间的转换

建议不要用的方式

  • 手写get\set; 虽然性能高,但是费劲并且眼花缭乱,一不小心就写错了,难以维护,复用度不高
  • BeanUtils,apacha和spring包下都有对应的类,但是底层用到的都是反射,性能比较差,大流量的情况下一般不用
  • 直接fastJSONGC会很频繁,而且性能比较差

常用的方式

  • cglib的beanCopier,开销在创建BeanCopier,一般在创建类的时候提前创建好一个,在代码运行的时候直接进行copy,性能接近原生。
  • mapstruct 性能和原生代码一样,支持复杂的转化场景,实现原理同lombok编译的时候生成对应的代码。

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

  • 反射:fastjson,beanutil 都不建议用
  • get\set: beancoper通过字节码进行getset,mapstruct编译的时候生成getset。 性能相对较好。

使用方式

个人觉得,如果说对象比较简单的时候,使用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;

public class BeanCopyUtils {

    
    private static Map<Class<?>, Map<Class<?>, BeanCopier>> beanCopierMap = new ConcurrentHashMap<>();
    
    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);
    }
    
    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注解指定source和target字段名称对应关系, 如果有多个这种属性,那就指定多个@Mapping注解。
  • 忽略某个字段,在@Mapping的时候,加上ignore = true
  • 转化日期格式,字符串到数字的格式,可以使用dateFORMat,numberFormat
  • 如果有自定义转换的需求,写一个简单的Java类即可,然后在方法上打上Mapstruct的注解@Named,在在@Mapper(uses = 自定义的类),然后@Mapping中用上qualifiedByName。
@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;

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));
  }
}

测试结果

  • 可以看出BeanCopier和MapStruct是远远超过其他转换方式的...
  • BeanCopier虽然快,但是比mapstruct还是有20倍的性能差距...

最后

总结下本文的内容:

  • 软件系统一般都会进行分层,领域模型也会随之进行分层,即每层都有自己关注的模型对象; 分层的主要原因是便于维护。
  • 模型之间的对象经常要互相转换,常用的转换实现有反射和get/set,反射的性能很差不建议使用
  • 然后写了基于get/set实现的beancopier和mapstruct使用方式,简单测试了下性能,mapstrcut优于其它各种对象转换方式。并且MapStrcut支持功能更加复杂的对象转换。 性能又好,功能又强大,所以可以考虑优先使用.

到此这篇关于Java对象转换的方案分享的文章就介绍到这了,更多相关Java对象转换内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java对象转换的方案分享

本文链接: https://www.lsjlt.com/news/167357.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java对象转换的方案分享
    目录前言为什么模型要分这么多层?模型之间的转换建议不要用的方式常用的方式使用方式定义对象BeanCopier最简单的使用方式创建可复用的BeanCopier工具类MapStruct引...
    99+
    2024-04-02
  • PHP对象转字符的实用案例分享
    PHP是一种广泛应用于Web开发的脚本语言,其面向对象的特性使得开发者可以更加高效地编写和管理代码。在实际开发中,经常会遇到需要将PHP对象转换为字符串的情况,本文将分享一些实用的案例...
    99+
    2024-03-06
    php编程 php对象转字符 实用案例分享 iphone
  • JAVA 对象转换为JSON
    转载:如何把java对象转换为json java对象怎么转成json_clghxq的技术博客_51CTO博客 Java对象列表转换为JSON对象数组,并转为字符串 JSONArray jsonArray = JSONArray.fromOb...
    99+
    2023-09-06
    java json 开发语言
  • Java将json对象转换为map键值对案例详解
      本文的目的是把json串转成map键值对存储,而且只存储叶节点的数据   比如json数据如下:   {responseHeader:{status:0,QTime:0},spe...
    99+
    2024-04-02
  • java泛型转换成对象的方法是什么
    Java中将泛型转换成对象的方法是使用类型擦除和强制类型转换。泛型在编译时会进行类型擦除,即将泛型类型转换成其上界类型(Object...
    99+
    2023-08-16
    java
  • Java中常见的对象转换工具
    目录前言用法介绍mapstructmaven依赖使用介绍插件工具Spring BeanUtilsApache BeanUtils性能分析总结前言 我们在写搬砖的过程中,少不了需要将A...
    99+
    2023-05-17
    Java常见的对象转换工具 Java转换工具
  • java对象与json对象之间互相转换实现方法示例
    本文实例讲述了java对象与json对象之间互相转换实现方法。分享给大家供大家参考,具体如下:import java.util.ArrayList;import java.util.Collection;import java.util.I...
    99+
    2023-05-30
    java json ava
  • java如何将map转换为对象
    要将Map转换为对象,可以使用反射来实现。首先,创建一个空对象,然后遍历Map的键值对,通过反射设置对象的属性值。假设有一个Pers...
    99+
    2023-08-24
    java map
  • java--- xml和对象之间的互相转换
    例子是把xml映射成bean成对象 第一种方法是使用 JAXB(Java Architecture for XML Binding) 实现XML与Bean的相互转换 简介 JAXB是一个业界的标准,是一项可以根据X...
    99+
    2023-08-31
    java
  • 关于Java中的dozer对象转换问题
    目录Java中的dozer对象转换1、dozer介绍2、依赖坐标3、创建测试工厂【dozer_demo】3.1、引入对应的依赖3.2、创建UserDTO和UserEntity3.3、...
    99+
    2024-04-02
  • java对象初始化代码分享
    这篇文章主要讲解了“java对象初始化代码分享”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java对象初始化代码分享”吧!一,实例变量的初始化这里首先介绍下创建对象的过程:类型为Dog的一...
    99+
    2023-05-30
    java
  • Java中JavaBean对象和Map的互相转换方法实例
    目录1.JavaBean转Map1.1.简介1.2.反射知识1.3.简单转换1. 4.属性里面套属性转换1. 5.总结2.Map转JavaBean对象2.1.简介2.2.Intros...
    99+
    2022-11-16
    hashmap转javabean javabean转成map javabean和map互相转换
  • 替换json对象中的key最佳方案
    JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子...
    99+
    2024-04-02
  • 怎么在java中对对象的类型进行转换
    怎么在java中对对象的类型进行转换?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。对象类型转换分为向上转型和向下转型(强制对象转型)。 向上转型是子对象向父对象转型的过程,例如...
    99+
    2023-05-30
    java
  • PHP 编程中月份转换为英文的实现方案分享
    月份在PHP编程中经常需要转换为英文,这在一些项目中尤其常见,比如生成月度报表、展示日历等。下面分享一种实现方案,通过具体的代码示例演示如何将月份转换为英文。 在PHP中,可以通过将月...
    99+
    2024-04-02
  • JS判断对象属性是否存在的五种方案分享
    目录背景检查属性是否存在inReflect.has()hasOwnProperty构造函数法对象字面量缺点不支持create覆盖报错Object.prototype.hasOwnPr...
    99+
    2024-04-02
  • Java 打包对象:学习笔记分享
    Java 是一门面向对象的编程语言,它的面向对象特性使得 Java 开发者可以轻松地组织代码和数据。但是,在编写代码的过程中,我们经常需要将一组相关的对象打包在一起进行处理。这就是 Java 打包对象的重要作用。本文将会分享 Java 打...
    99+
    2023-10-03
    打包 对象 学习笔记
  • fastjson--对象与JSON之间的转换方法
    1、Java对象–>JSON对象: (JSONObject)JSONObject.toJSON(Java对象实例) public class JSON2JavaTest{ public static...
    99+
    2023-09-04
    json java
  • javascript将对象转换为数组的方法
    本篇内容主要讲解“javascript将对象转换为数组的方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“javascript将对象转换为数组的方法”吧!jav...
    99+
    2024-04-02
  • java对象怎么与JSON互相转换
    这篇文章将为大家详细讲解有关java对象怎么与JSON互相转换,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。具体方法如下:import java.beans.IntrospectionExc...
    99+
    2023-05-31
    json java ava
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作