对象转换(VO、DTO、PO、DO通用转换)多种方式

1:实体对象的转换

①:使用到的jar包

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--hutool jar-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.0.7</version>
        </dependency>

        <!--dozer jar-->
        <dependency>
            <groupId>net.sf.dozer</groupId>
            <artifactId>dozer</artifactId>
            <version>5.4.0</version>
        </dependency>


        <!-- mapStruct 对象转换 -->
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-jdk8</artifactId>
            <version>1.2.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>1.2.0.Final</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.18</version>
        </dependency>

②:工具类

package com.itsource.enjoy.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.itsource.enjoy.domain.entity.Score;
import com.itsource.enjoy.domain.entity.Student;
import com.itsource.enjoy.domain.vo.ScoreVo;
import com.itsource.enjoy.domain.vo.StudentVo;
import org.dozer.DozerBeanMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.cglib.beans.BeanCopier;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;


/**
 * 对象属性赋值的多种方式
 */

public class BeanCopyTemplateUtils {

    /**
     * apache的BeanUtil.copyProperties 可以实现,但是性能差而且容易出异常,很多规范严禁使用这种途径
     * 大多数情况下 MapStruct 性能最高。类似于lombok ,Mapstruct都是在编译期进行实现,所以一般不存在运行时性能问题,mapStruct 最终调用的是setter和getter 方法,而非反射。这也是其性能比较好的原因之一
     * get set 的方式进行转换的方式很简单,但是有一个很验证的问题就是会导致代码过于臃肿,会出现大量的属性值赋值,大量的get set方法充斥着业务逻辑
     * BeanCopier是cglib包下的一个类,默认的情况下,它会进行同名,同类型属性的copier,如果类型不同,或者名称不同的化,会报错,我们可以通过实现自定义Convert的形式进行类型转换
     *
     * @param args
     */

    public static void main(String[] args) {
        //将studentVo中的属性赋值给student
        StudentVo studentVo = new StudentVo()
                .setName("小花")
                .setAge(18)
                .setType("1")
                .setSex(false)
                .setBirthDay(DateUtil.date())
                .setScores(new ArrayList<Score>() {{
                    add(new Score().setSubjectType("语文").setSubjectScore(131.0));
                    add(new Score().setSubjectType("英语").setSubjectScore(111.0));
                }});

//        //方式一:使用hutool中的convert  (属性相同的情况下不论是集合还是属性都能赋值,不同的属性需要手动赋值)
        Student student1 = Convert.convert(Student.class, studentVo)
                .setStatus(studentVo.getType());
//        //打印结果 Student(name=小花, age=18, sex=false, birthDay=2021-11-15 10:49:23, scores=[Score(subjectScore=131.0, subjectType=语文), Score(subjectScore=111.0, subjectType=英语)], status=1)


//        //方式二:使用Spring的BeanUtils  (属性相同的情况下不论是集合还是属性都能赋值,不同的属性需要手动映射)  源对象, 目标对象
        Student student2 = new Student();
        BeanUtils.copyProperties(studentVo,student2.setStatus(studentVo.getType()));
//        //Student(name=小花, age=18, sex=false, birthDay=2021-11-15 11:26:37, scores=[Score(subjectScore=131.0, subjectType=语文, hasExam=null), Score(subjectScore=111.0, subjectType=英语, hasExam=null)], status=1)


        //方式三: 使用 hutool中的JSONUtil 将对象转为json字符串然后再转对象
        final Student student3 = JSONUtil.toBean(JSONUtil.toJsonStr(studentVo), Student.class);
        //Student(name=小花, age=18, sex=false, birthDay=Mon Nov 15 12:10:20 CST 2021, scores=[Score(subjectScore=131.0, subjectType=语文, hasExam=null), Score(subjectScore=111.0, subjectType=英语, hasExam=null)], status=null)


        //方式四  使用dozer,推土机    会打印很多日志
        DozerBeanMapper beanMapper = new DozerBeanMapper();
        Student student4 = new Student();
        beanMapper.map(studentVo,student4);
        //Student(name=小花, age=18, sex=false, birthDay=Mon Nov 15 13:25:22 CST 2021, scores=[Score(subjectScore=131.0, subjectType=语文, hasExam=null), Score(subjectScore=111.0, subjectType=英语, hasExam=null)], status=null)


        //方式五  BeanCopier(不建议使用) Spring的cglib包下
        Student student5 = new Student();
        BeanCopier copier = BeanCopier.create(StudentVo.class, Student.class, false);
        copier.copy(studentVo, student5, null);


        //方式六:MapStruct 附上部分代码


        //方式七:直接getter、setter方法
        Student student7 = new Student()
                .setName(studentVo.getName())
                .setAge(studentVo.getAge())
                .setScores(studentVo.getScores());



        //延伸集合赋值
        List<Score> scores = new ArrayList<Score>() {{
            add(new Score().setSubjectType("语文").setSubjectScore(131.0).setHasExam(true));
            add(new Score().setSubjectType("英语").setSubjectScore(111.0).setHasExam(false));
        }};
        //也能实现转成list集合
        //Collection<?> scoreVos = Convert.toCollection(List.class, ScoreVo.class, scores);
        List<ScoreVo> scoreVos = Convert.toList(ScoreVo.class, scores);
        //属性名称不一样 [ScoreVo(subjectScore=131.0, subjectType=语文, enableExam=null), ScoreVo(subjectScore=111.0, subjectType=英语, enableExam=null)]
        scoreVos.forEach(scoreVo -> {
        scores.forEach(score -> {
                if(Objects.equals(scoreVo.getSubjectType(),score.getSubjectType())){
                    scoreVo.setEnableExam(score.getHasExam());
                }
            });
        });
        //属性名称不一样 手动赋值 [ScoreVo(subjectScore=131.0, subjectType=语文, enableExam=true), ScoreVo(subjectScore=111.0, subjectType=英语, enableExam=false)]
        System.err.println(scoreVos);

    }
}

③:使用到的实体

package com.itsource.enjoy.domain.entity;

import lombok.Data;
import lombok.experimental.Accessors;

import java.util.Date;
import java.util.List;

/**
 * 学生类
 */
@Accessors(chain = true)
@Data
public class Student {

    /**
     * 姓名
     */
    private String name;
    /**
     * 年龄
     */
    private Integer age;
    /**
     * 性别
     */
    private Boolean sex;

    /**
     * 生日
     */
    private Date birthDay;


    /**
     * 成绩集合
     */
    private List<Score> scores;

    /**
     * 状态类型
     */
    private String status;

}

package com.itsource.enjoy.domain.vo;

import com.itsource.enjoy.domain.entity.Score;
import lombok.Data;
import lombok.experimental.Accessors;

import java.util.Date;
import java.util.List;
@Accessors(chain = true)
@Data
public class StudentVo {

/**
 * 姓名
 */
private String name;
/**
 * 年龄
 */
private Integer age;
/**
 * 性别
 */
private Boolean sex;

/**
 * 生日
 */
private Date birthDay;


/**
 * 成绩集合
 */
private List<Score> scores;

/**
 * 状态类型
 */
private String type;

}

package com.itsource.enjoy.domain.entity;

import lombok.Data;
import lombok.experimental.Accessors;

/**

  • 成绩
    */
    @Accessors(chain = true)
    @Data
    public class Score {

    /**

    • 学科分数
      */
      private Double subjectScore;

    /**

    • 学科类型
      */
      private String subjectType;

    /**

    • 是否必考
      */
      private Boolean hasExam;

}

package com.itsource.enjoy.domain.vo;

import lombok.Data;
import lombok.experimental.Accessors;

/**

  • 成绩
    */
    @Accessors(chain = true)
    @Data
    public class ScoreVo {

    /**

    • 学科分数
      */
      private Double subjectScore;

    /**

    • 学科类型
      */
      private String subjectType;

    /**

    • 是否必考
      */
      private Boolean enableExam;

}

④:方式6的补充

package com.itsource.enjoy.util;


import com.itsource.enjoy.domain.entity.Student;
import com.itsource.enjoy.domain.vo.StudentVo;

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.springframework.stereotype.Component;

@Component
@Mapper(componentModel = "spring")
public interface UtilStruct {


    @Mappings({
            @Mapping(target = "name",source = "name"),
            @Mapping(target = "age",source = "age"),
            @Mapping(source = "sex",target = "sex"),
            @Mapping(target = "birthDay",source = "birthDay"),
            @Mapping(source = "scores",target = "scores"),
            @Mapping(source = "type",target = "status")
    })
     Student convertToStudent(StudentVo studentVo);
}

package com.itsource.enjoy.controller;


import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Lists;
import com.itsource.enjoy.common.ResponseRawBody;
import com.itsource.enjoy.domain.dto.MessageParamDto;
import com.itsource.enjoy.domain.entity.Score;
import com.itsource.enjoy.domain.entity.Student;
import com.itsource.enjoy.domain.vo.MessageResultVo;
import com.itsource.enjoy.domain.vo.StudentVo;
import com.itsource.enjoy.util.UtilStruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 测试MapStruct 
 */
@Validated
@RequestMapping("/message")
@RestController
public class MessageProvideController {

    @Autowired
    private UtilStruct utilStruct;

    @ResponseRawBody
    @GetMapping("/test")
    public Student queryInfo(){
        StudentVo studentVo = new StudentVo()
                .setName("小花")
                .setAge(18)
                .setType("1")
                .setSex(false)
                .setBirthDay(DateUtil.date())
                .setScores(new ArrayList<Score>() {{
                    add(new Score().setSubjectType("语文").setSubjectScore(131.0));
                    add(new Score().setSubjectType("英语").setSubjectScore(111.0));
                }});
         Student student = utilStruct.convertToStudent(studentVo);
        System.err.println(student);
        //Student(name=小花, age=18, sex=false, birthDay=2021-11-15 14:37:29, scores=[Score(subjectScore=131.0, subjectType=语文, hasExam=null), Score(subjectScore=111.0, subjectType=英语, hasExam=null)], status=1)
         return student;
    }
 
}

  • 1
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Java中,BO(Business Object)、VO(Value Object)、DTO(Data Transfer Object)和DO(Domain Object)是常见的数据对象类型,它们之间的转换可以通过以下方式实现: 1. BO转换VO:BO通常包含业务逻辑和数据访问方法,而VO只包含数据字段。因此,BO转换VO需要将BO中的业务逻辑和数据访问方法去除,只保留数据字段。 2. VO转换为BO:VO只包含数据字段,而BO除了数据字段还包含业务逻辑和数据访问方法。因此,VO转换为BO需要将VO中的数据字段赋值给BO,并添加业务逻辑和数据访问方法。 3. DTO转换为BO/VODTO通常用于在不同层之间传递数据,它包含需要传递的数据字段。DTO转换为BO/VO需要将DTO中的数据字段赋值给BO/VO。 4. BO/VO转换DTO:BO/VO包含业务逻辑和数据访问方法,而DTO只包含需要传递的数据字段。因此,BO/VO转换DTO需要将BO/VO中的数据字段赋值给DTO。 5. DO转换为BO/VO/DTO:DO通常用于与数据库交互,它包含数据库表中的字段。DO转换为BO/VO/DTO需要将DO中的字段赋值给BO/VO/DTO。 6. BO/VO/DTO转换为DO:BO/VO/DTO包含业务逻辑和数据访问方法,而DO只包含数据库表中的字段。因此,BO/VO/DTO转换为DO需要将BO/VO/DTO中的字段赋值给DO。 以上是常见的数据对象类型之间的转换方式,根据具体的业务需求和数据结构,可能还需要进行其他类型的转换。 ### 回答2: 在Java中,为了保证业务逻辑和数据持久化之间的解耦,常常要对数据进行转换,这时就用到了BO、VODTO和DO。以下是它们的详细解释和转换方式: 1. BO(Business Object)——业务对象 BO是指业务对象,它主要存储业务领域中的实体类和业务逻辑。我们可以将BO理解为一个中间层,在业务逻辑层中使用。BO中常常包含了多个DO对象(数据对象),他们之间通过相应的转换工具进行转换。 BO转换步骤: a.根据业务需求确定BO对象的属性; b.先将DO(数据对象)利用其构造方法初始化BO对象; c.在BO中实现业务逻辑,对属性进行封装; d.利用VO工具类或其他工具类进行BO到VO转换。 2. VO(Value Object)——值对象 VO是指值对象,它用来封装数据传输过程中的值对象VO中的属性和BO中的属性可一一对应,VO一般用于数据展示和页面传输等操作,只包括BO中特定业务属性的集合。 VO转换步骤: a.先根据实际需求,确定VO所需要封装的BO属性; b.利用VO构造方法,将BO属性值进行封装; c.最后利用 DTO(数据传输对象)将 VO 转换为 DO 对象。 3. DTO (Data Transfer Object)——数据传输对象 DTO是指数据传输对象,它用于在远程调用和分布式架构中传输数据。DTO中包含了多个数据对象(DO),将查询对象中的数据进行封装,以减少对服务器的请求次数。 DTO转换步骤: a.首先,我们需要为DTO 创建对象; b.在DTO中复制 DO(数据对象) 中的属性,作为DTO的属性; c.利用工具类将 DO 对象转换DTO 对象,或将 DTO 对象转换成 DO 对象。 4. DO(Data Object)——数据对象 DO是指数据对象,它直接将数据库中的表结构映射成业务对象。 DO转换步骤: a.将数据库表结构和业务表结构进行对应,定义好DO对象属性; b.利用DAO(数据访问对象)从数据库中查询数据; c.利用工具类将 DO 对象转换成 BO 和 DTO 对象,以实现 BO 和 VO 对象的封装。(PS:不一定全部需要转换) 总结: BO、DTOVO和DO都是Java中非常重要的概念,它们的作用都主要是为了解耦并减少数据层和业务层之间的耦合。业务逻辑通常位于BO中,数据库的存储位置通常位于DO中,而视图展示和页面交互通常位于VO中。DTO是用于远程调用和分布式架构。在使用时,我们不仅要了解它们的作用,还要清楚它们之间的转换方式,使得代码更加清晰、易于维护和扩展。 ### 回答3: 在Java开发中,我们通常会用到BO(Business Object),VO(Value Object),DTO(Data Transfer Object)和DO(Domain Object)等概念。这些概念在业务逻辑中会起到非常关键的作用。接下来,让我们分别来探讨一下这些概念。 BO,即业务对象,说白了就是应用程序中的业务逻辑对象,是一个封装了业务逻辑的对象。它通常对应着业务模块中的一个或多个业务流程,是Java应用程序中最具有业务价值的一个对象。BO通常负责与前端页面交互,包含了业务逻辑处理的一些具体实现。 VO,即值对象,是一种用于表示简单数据结构的对象。它通常包含多个属性,但是没有业务方法。VO的目的是为了将一个或多个值打包,作为一个单独的实体来传递数据的方法。 DTO,即数据传输对象,是一种对象,并不具有业务逻辑。它的主要作用是在服务端和客户端之间数据传输。当一个远程调用发生时,需要从客户端传输数据到服务器端。由于传输的数据可能包含很多参数,使用DTO可以封装这些参数,并且可以封装多个参数,从而简化数据传输过程。 DO,即领域对象,是和数据库表相对应的一种对象。一般可以将数据库中各个表的一行数据映射为DO对象,表达出数据从数据库中取出后的实体对象。DO所扮演的角色类似ORM框架中的实体类,通常需要与数据库进行交互以持久化数据。 在应用程序开发过程中,为了将不同的概念进行区分,通常需要进行不同概念之间的转换。例如,通过DTO对象将数据从后台传输至前台,或者通过VO对象将数据从页面传输至后台,都需要进行相应的转换。这些转换过程可以通过手动编写代码完成,也可以通过一些框架(例如Spring)提供的简化型转换注解来完成相关的转换过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值