0

0

使用Dozer优雅的将DO转换成VO

高洛峰

高洛峰

发布时间:2016-10-15 13:42:36

|

3066人浏览过

|

来源于php中文网

原创

什么是DO、DTO和VO

在java中 vo、 po、do、dto、 bo、 qo、dao、pojo的概念中介绍过java中的各种模型概念。
在这里简单再总结一下:

在日常的项目开发中,VO对应于页面上需要显示的数据(表单),DO对应于数据库中存储的数据(数据表),DTO对应于除二者之外需要进行传递的数据。

很多人可能对VO和DTO并不是那么熟悉,相反对DO却比较熟悉,那是因为在很多项目中由于种种原因我们只使用了DO,原因可能有以下几种:

1、项目太小,对于一种业务实体,封装成一个DO就够了。

2、并不熟悉DTO、VO,更不知道他们之间的区别。

3、了解DO\DTO\VO之间的区别,但是懒得用。

那么,这里,博主再啰嗦一下为什么要引入这么多概念,为什么我要建议大家在自己的项目中使用这些实体对象。

为什么不能只用一个DO

我们来看这样一个例子。假如我们的项目中由User这样一个实体。我们在创建User表的时候一般包含一下属性:

1.png

针对这个实体,我们通常需要创建一个DO类,用来封装这个User实体。

public class UserDO {
    private Integer id;                 //唯一主键
    private Date createdTime;           //创建时间
    private Date updatedTime;           //最后更新时间
    private String name;                //姓名
    private Integer age;                //年龄
    private String gender;              //性别
    private String address;             //住址
    private String password;            //密码
    private String nickName;            //昵称
    private Date birthday;              //生日
    private String politicalStatus;     //政治面貌,1表示群众,2表示团员,3表示党员,4表示其他,100表示未知
    private Integer companyId;          //公司的ID
    private Integer status;             //数据状态,1表示可用,0表示不可用
 
    //setter and getter
}

然后,在代码中,从DAO一直到前端展示,我们都通过这个UserDO类的对象来进行数据传输。这样做会有什么问题嘛?

不需要的字段也会传递到前端页面。

如password、createdTime、updatedTime和status这几个字段我们可能在前端根本不需要展示,但是这些字段有可能也会被传递到前端(除非我们在SQL查询的时候没有查询出对应的字段)。这不仅使数据的传输量增大,还可能有安全性问题。

某些字段需要转换,但是无法支持。

对于上面例子中的政治面貌字段,我们在数据库中存储的是数字,但是在前端页面我要展示的是中文描述。这种情况只能在前端通过if/else的方式来分情况展示。

某些字段要展示,但是并不希望出现在数据库中

在User表中我们只保存了这个用户的companyId,需要同时查询company表来查询出该公司的更多详细信息。对于User对象,如果我们想在前端同时展示他所属的公司,希望通过一次查询全都查出来怎么办?有几个简单的方案,第一个是让UserDO中包含一个Company类的属性,通过这个属性来传递。另外一种是把我们希望传到前端的Company的属性也写到UserDO中。但是,如果真的这么做了,那UserDO还能被称作DO了吗?

还有很多问题,这这里就不详细介绍了。

可见,使用一个DO从头用到尾(从数据库到前端页面)并不是一种好的设计。

如何正确的使用DO、DTO、VO

对于上面的例子,我们可以将他设计成以下类。由于模型并不复杂,这里只需要再引入VO就可以了。

UserDO已经和数据库字段一一对应了,这里不需要修改。

public class UserDO {
    private Integer id;                 //唯一主键
    private Date createdTime;           //创建时间
    private Date updatedTime;           //最后更新时间
    private String name;                //姓名
    private Integer age;                //年龄
    private String gender;              //性别
    private String address;             //住址
    private String password;            //密码
    private String nickName;            //昵称
    private Date birthday;              //生日
    private String education;           //学历
    private String politicalStatus;     //政治面貌,1表示群众,2表示团员,3表示党员,4表示其他,100表示未知
    private Integer companyId;          //公司的ID
    private Integer status;             //数据状态,1表示可用,0表示不可用
 
    //setter and getter
}

引入UserVO,用于封装传递到前端需要展示的字段。

志设AI
志设AI

志设AI是一站式AI设计平台,集“AI生图 + 在线设计 + 素材交易 + 收益分成”于一体。

下载
public class UserVO {
    private Integer id;                 //唯一主键
    private String name;                //姓名
    private Integer age;                //年龄
    private String gender;              //性别
    private String address;             //住址
    private String nickName;            //昵称
    private Date birthday;              //生日
    private String education;           //学历
    private String politicalStatus;     //政治面貌,群众、团员、党员等
    private Company company;            //公司
 
    //setter and getter
}

UserVO中只包含了展示所需要的字段,并不需要展示的字段在这里不需要包含。

在引入了这个类之后,我们就可在进行数据库查询的时候使用UserDO,然后再需要传递到前端的时候把DO转换成VO。

总结

看到这里,你可能已经发现,UserDO和UserVO中包含了大量的相同字段。难道真的有必要再单独设计个VO嘛?我可以明确告诉你的是,当你的系统越来越大,表中的字段越来越多的时候,使用DO\DTO\VO等概念进行分层处理是绝对有好处的。至于如何进行有效的在不同的实体类间进行转换是我接下来要介绍的。

优雅的将DO转换成VO

Dozer 是一个对象转换工具。

Dozer可以在JavaBean到JavaBean之间进行递归数据复制,并且这些JavaBean可以是不同的复杂的类型。
所有的mapping,Dozer将会很直接的将名称相同的fields进行复制,如果field名不同,或者有特别的对应要求,则可以在xml中进行定义。

前面我们介绍的DO\DTO\VO不就是JavaBean嘛。正好可以使用Dozer进行转换呀。
除了使用Dozer,当然你还由其他选择:

典型的解决方案就是手动拷贝,弊端很明显,代码中充斥大量Set 和Get方法,真正的业务被埋藏值与值的拷贝之中。

另一种方案就是使用BeanUtil,但BeanUtil不够很好的灵活性,又时候还不得不手动拷贝。Dozer可以灵活的对对象进行转换,且使用简单。

Dozer 支持的转换类型

Primitive 基本数据类型 , 后面带 Wrapper 是包装类 Complex Type 是复杂类型

•   Primitive to Primitive Wrapper 
•   Primitive to Custom Wrapper 
•   Primitive Wrapper to Primitive Wrapper 
•   Primitive to Primitive 
•   Complex Type to Complex Type 
•   String to Primitive 
•   String to Primitive Wrapper 
•   String to Complex Type if the Complex Type contains a String constructor 
•   String 到复杂类型 , 如果复杂类型包含一个 String 类型的构造器 
•   String to Map 
•   Collection to Collection 
•   Collection to Array 
•   Map to Complex Type 
•   Map to Custom Map Type 
•   Enum to Enum 
•   Each of these can be mapped to one another: java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp, java.util.Calendar, java.util.GregorianCalendar 
•   String to any of the supported Date/Calendar Objects. 
•   Objects containing a toString() method that produces a long representing time in (ms) to any supported Date/Calendar object.

在普通Java项目中使用Dozer

在pom.xml中增加依赖

<dependency>
  <groupid>net.sf.dozer</groupid>
  <artifactid>dozer</artifactid>
  <version>5.5.1</version>
</dependency>

使用Dozer进行类转换

public class Main {
 
    public static void main(String[] args) {
        DozerBeanMapper mapper = new DozerBeanMapper();
        UserDO userDO = new UserDO();
        userDO.setName("hollis");
        userDO.setAddress("hz");
        userDO.setAge(25);
        userDO.setCompanyId(1);
        userDO.setBirthday(new Date());
        userDO.setGender("male");
        userDO.setEducation("1");
        userDO.setNickName("hollis");
        userDO.setPoliticalStatus("3");
        UserVO userVO = (UserVO) mapper.map(userDO, UserVO.class);
        System.out.println(userVO);
    }
}

特殊的字段转换
在使用mapper进行转换前,设置一个或多个mapping文件

List myMappingFiles = new ArrayList();    
myMappingFiles.add("dozer-mapping.xml");    
mapper.setMappingFiles(myMappingFiles);

配置dozer-mapping.xml文件

数据类型不一致,或者名称不相同或者有级联关系等情况下,可以通过文件dozer-mapping.xml来进行定制Bean的转换

<?xml  version="1.0" encoding="UTF-8"?>
<mappings http:>
 
    <mapping>
        <class-a>com.hollis.lab.UserDO</class-a>
        <class-b>com.hollis.lab.UserVO</class-b>
    </mapping>
</mappings>

在JavaWeb项目中使用Dozer

在pom.xml中增加依赖

<dependency>
  <groupid>net.sf.dozer</groupid>
  <artifactid>dozer</artifactid>
  <version>5.5.1</version>
</dependency>

使用Spring集成dozer

<?xml  version="1.0" encoding="UTF-8"?>
nbsp;beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean>
        <property>
            <list>
                <value>classpath:mapping/dozer-mapping.xml</value>
            </list>
        </property>
    </bean> 
</beans>

使用baseMapper进行Bean的转换

@Autowired
private Mapper baseMapper;
private UserVO doToVo(UserDO userDO){
    if(userDO == null) return null;
    UserVO vo = baseMapper.map(userDO, UserVO.getClass());
    if(userDO.getCompanyId != null) getCompany(vo);
    return vo;
}

通过以上的代码加配置,我们就实现了从DO转换到VO的部分操作,之所以说是部分操作,是因为我们在dozer-mapping.xml并没有做多余的配置,只是使用dozer将DO中和VO中共有的属性转换了过来。对于其他的类型不同或者名称不同等的转换可以参考官网例子通过设置dozer-mapping.xml文件来实现。

上面还有一个getCompany()没有实现。这个方法其实就是通过companyId查询出company实体然后在赋值给UserVO中的company属性。

在使用了dozer之后,我们可以把UserDO中的部分属性赋值到UserVO中,其实,转化的过程是通过调用UserDO中的getter方法和UserVO中的setter方法来实现的。读者可以做个实验,对于UserVO中的部分属性不写Setter方法看看还能不能把属性值转换过来,博主已经测试过了,是不能的。


本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Golang 测试体系与代码质量保障:工程级可靠性建设
Golang 测试体系与代码质量保障:工程级可靠性建设

Go语言测试体系与代码质量保障聚焦于构建工程级可靠性系统。本专题深入解析Go的测试工具链(如go test)、单元测试、集成测试及端到端测试实践,结合代码覆盖率分析、静态代码扫描(如go vet)和动态分析工具,建立全链路质量监控机制。通过自动化测试框架、持续集成(CI)流水线配置及代码审查规范,实现测试用例管理、缺陷追踪与质量门禁控制,确保代码健壮性与可维护性,为高可靠性工程系统提供质量保障。

43

2026.02.28

Golang 工程化架构设计:可维护与可演进系统构建
Golang 工程化架构设计:可维护与可演进系统构建

Go语言工程化架构设计专注于构建高可维护性、可演进的企业级系统。本专题深入探讨Go项目的目录结构设计、模块划分、依赖管理等核心架构原则,涵盖微服务架构、领域驱动设计(DDD)在Go中的实践应用。通过实战案例解析接口抽象、错误处理、配置管理、日志监控等关键工程化技术,帮助开发者掌握构建稳定、可扩展Go应用的最佳实践方法。

38

2026.02.28

Golang 性能分析与运行时机制:构建高性能程序
Golang 性能分析与运行时机制:构建高性能程序

Go语言以其高效的并发模型和优异的性能表现广泛应用于高并发、高性能场景。其运行时机制包括 Goroutine 调度、内存管理、垃圾回收等方面,深入理解这些机制有助于编写更高效稳定的程序。本专题将系统讲解 Golang 的性能分析工具使用、常见性能瓶颈定位及优化策略,并结合实际案例剖析 Go 程序的运行时行为,帮助开发者掌握构建高性能应用的关键技能。

35

2026.02.28

Golang 并发编程模型与工程实践:从语言特性到系统性能
Golang 并发编程模型与工程实践:从语言特性到系统性能

本专题系统讲解 Golang 并发编程模型,从语言级特性出发,深入理解 goroutine、channel 与调度机制。结合工程实践,分析并发设计模式、性能瓶颈与资源控制策略,帮助将并发能力有效转化为稳定、可扩展的系统性能优势。

20

2026.02.27

Golang 高级特性与最佳实践:提升代码艺术
Golang 高级特性与最佳实践:提升代码艺术

本专题深入剖析 Golang 的高级特性与工程级最佳实践,涵盖并发模型、内存管理、接口设计与错误处理策略。通过真实场景与代码对比,引导从“可运行”走向“高质量”,帮助构建高性能、可扩展、易维护的优雅 Go 代码体系。

18

2026.02.27

Golang 测试与调试专题:确保代码可靠性
Golang 测试与调试专题:确保代码可靠性

本专题聚焦 Golang 的测试与调试体系,系统讲解单元测试、表驱动测试、基准测试与覆盖率分析方法,并深入剖析调试工具与常见问题定位思路。通过实践示例,引导建立可验证、可回归的工程习惯,从而持续提升代码可靠性与可维护性。

3

2026.02.27

漫蛙app官网链接入口
漫蛙app官网链接入口

漫蛙App官网提供多条稳定入口,包括 https://manwa.me、https

235

2026.02.27

deepseek在线提问
deepseek在线提问

本合集汇总了DeepSeek在线提问技巧与免登录使用入口,助你快速上手AI对话、写作、分析等功能。阅读专题下面的文章了解更多详细内容。

11

2026.02.27

AO3官网直接进入
AO3官网直接进入

AO3官网最新入口合集,汇总2026年可用官方及镜像链接,助你快速稳定访问Archive of Our Own平台。阅读专题下面的文章了解更多详细内容。

382

2026.02.27

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号