DTO对象的使用场景和 orika-mapper 框架的使用

对于项目而言, 我们一般会有DAO->Service->Controller分层设计, 这些层次体现了每层的作用, 而层次之间的数据传递对象设计很少被提及, 下面是一个相对完整的数据转换过程:
Table层--(DO对象)-->DAO层--(DO对象)-->Service层--(DTO对象)-->Controller层--(VO对象)-->Web Template层

DO(domain object) 领域对象, 或者叫做 entity object:
1. 一般DO类和数据表是一一对应, 属性和字段也是一一对应的.
2. 对于 relationship 表, 一般也需要有一个对应的 DO 类.
3. DO 类中不应该包含复杂的逻辑, 仅仅是一些简单的 setter() 和 getter() 方法.
4. 比如 user 表有一个 deptId 字段, user entity 类必须有一个 deptId 属性, 不推荐有一个对应的 dept Entity 对象, 当然更不应该直接包含 dept entity 对象的属性, 比如 deptName 等.
5. 多个 DO 类之间的关系和数据模型一样, 是满足第三范式.
6. DO类名: 可以以Entity/DO作为后缀, 或者不加Entity/DO这样的后缀.

DTO(Data Transfer Object) 数据传输对象:
1. 用于"跨进程或远程"传输, 对象的序列化/反序列化的网络开销较大, 这时就需要加入 DTO 对象, 典型的使用场景是用来封装Rest API接口. 如果是一个单体应用, 专门维护一套DTO类, 成本和收益相比, 引入DTO意义就不大了.
2. DTO 是一个贫血对象, 它不应包含"业务"处理逻辑, 主要是一些属性和getter和setter访问器, 也可包含一些属性重组逻辑.
3. 多个 DTO 类之间的关系一般不再满足第三范式, 而是反范式.
4. DTO类名: 应该以DTO作为后缀.
5. 用于解耦实体对象的存储层和上层, 这包含下面的好处:
(1): 隐藏部分底层表的属性, 以减少网络传输的代价.
(2): 在存储层和上层增加一个隔离, 屏蔽相互之间的影响.
(3): 用来封装多个DTO对象, 比如user DTO对象可以包含一个Dept DTO对象; 或者将Dept DTO某些常用属性直接flatten到User DTO对象上, 方便上层的使用.
(4): 如果没有DTO, 很多时候 Controller 层不得不直接最低层的 Entity 类, 跨层数据对象依赖将使得分层设计大打折扣.

VO(View Object/Value object)视图对象:
专门用于展现层(比如页面展现等).
对于一般的项目, VO 和 DTO 属性基本一致, 没有必要再维护一套VO类.
在前后端分离的大背景下, 即使是大型项目, 也没有必要再维护一套VO类.


Pojo(plain old java object) 普通java对象:
上述的DO/DTO/VO对象都属于Pojo对象. 阿里巴巴规范中有如下要求:
1. Pojo 类属性必须使用包装数据类型, 而不是基本数据类型, 理由是: 数据库中由可能是null值, 如果使用基本类型, 由可能导致自动拆箱异常.
2. 不能为任何属性设定默认值. 理由是: 强制使用者在使用时显式赋值, 任何NPE问题都应由使用者来保证.
3. Pojo 类都必须实现 toString() 方法, 可以使用 IDE 的 source/generate toString() 功能
4. Pojo 类都必须实现 Serializable 接口.

=====================================
object-object mapping framework 清单
=====================================
正如ORM过程, 我们可以手写代码, 也可以使用MyBatis这样的ORM 工具, 对于DO/DTO的转换也是一样, 可以手写代码转换, 也可以使用object-object mapping framework完成自动转换.

当前活跃的框架清单:
https://github.com/mapstruct/mapstruct
https://github.com/DozerMapper/dozer
https://github.com/orika-mapper/orika
https://github.com/modelmapper/modelmapper


性能对比:
https://github.com/arey/java-object-mapper-benchmark
https://www.baeldung.com/java-performance-mapping-frameworks

扫描二维码关注公众号,回复: 4554487 查看本文章

综合考虑性能/流行度/项目活跃程度, mapstruct 明显领先, 不过我这里更推荐使用 orika-mapper, 原因是:
1. 使用 mapstruct的话, IDE中需要引入 mapstruct 编译插件, 我们自己负责编写mapper interface, mapstruct 负责生成mapper实现类的class文件, 工程化成本较高, 可控性较差.
2. orika-mapper 相对更容易推广, mapping 逻辑可控性较强, 性能也算不错.

=====================================
orika-mapper 使用
=====================================
pom.xml 引入依赖

<dependency>
    <groupId>ma.glasnost.orika</groupId>
    <artifactId>orika-core</artifactId>
    <version>${orika.version}</version>
</dependency>


--------------------------------
简单示例:
--------------------------------
只要src/target属性名一致, Orika 能自动完成所有的属性的深拷贝, 甚至是 List<T> 这样的属性.

//准备 src 对象
PersonSource source = new PersonSource();

//生成 MapperFactory 对象, 然后使用 MapperFactory 对象注册 src/target 映射关系, 本例 src/target 的属性名完全一致, 所以不需要再设置映射关系. 
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();

// MapperFacade 对象负责对象之间的映射
MapperFacade mapper = mapperFactory.getMapperFacade();

//完成DO->DTO的映射
PersonDest destination = mapper.map(source, PersonDest.class);


--------------------------------
更复杂的示例:
--------------------------------
如果src/target属性名不一致, 或者要重组DO属性, 这时需要自定义src/target的映射规则.

//自定义 src/target class的映射规则
mapperFactory.classMap( Source.class, Destination.class) 
    .field(......)  //src/target 双向映射
    .fieldAToB(......)  //src->target的单向映射
    .fieldBToA(......)  //target->src的单向映射
    .exclude(......) //不考虑指定的属性
    .byDefault()
    .register();

mapperFactory 除了负责注册src/target 映射规则, 还可以 mapperFactory.getConverterFactory().registerConverter()来注册自定义类型转换器, 比如要将 Date 类型转换为 String类型, 实际项目中, 一般不需要自定义类型转换器, 因为 json 框架也有这样的功能. 

//定义一个类型转换器 MyConverter
public class MyConverter extends CustomConverter<Date,MyDate>{}

//注册类型转换器
mapperFactory.getConverterFactory().registerConverter(new MyConverter());  
    
// 然后仍然通过 mapper 完成src/target对象的深度拷贝. 
MapperFacade mapper = mapperFactory.getMapperFacade();

=====================================
参考
=====================================
https://cloud.tencent.com/developer/article/1110666
http://tech.dianwoda.com/2017/11/04/gao-xing-neng-te-xing-feng-fu-de-beanying-she-gong-ju-orika/?utmsource=tuicool&utmmedium=referral

猜你喜欢

转载自www.cnblogs.com/harrychinese/p/SpringBoot_DTO_Orika.html