Dozer 轻松高效玩转DTO(Data Transfer Object,属性名不同或相同都可以转换)

tech2025-05-22  9

1.现状

对于分布式系统,需要在不同系统之间传递与转换域对象。因为我们不希望外部公开内部域对象,也不允许外部域对象渗入系统。传统上,数据对象之间的映射通过手工编码(getter/setter)的方式实现,或对象组装器(或转换器)来解决。我们可能会开发某种自定义映射框架来满足我们的映射转换需求,但这一切都显得不够灵巧。

Dozer Dozer 是 Java Bean 到 Java Bean 映射器,它以递归方式将数据从一个对象复制到另一个对象。

通常,这些 Java Bean 将具有不同的复杂类型。Dozer 支持简单属性映射,复杂类型映射,双向映射,隐式和显式映射以及递归映射。 Dozer不仅支持属性名称之间的映射,还支持在类型之间自动转换。大多数转换方案都是开箱即用的,但 Dozer 还允许您通过 XML / API 的方式指定自定义转换。 下图描绘了 Dozer 可以插入到架构中的一些常见区域。请注意,它通常用于边界(进入/退出)。 Dozer 将确保数据库中的内部域对象不会流入外部表示层或外部使用者。它还可以帮助将域对象映射到外部 API 调用,反之亦然,现在不用纠结这个图,看完下面的测试用例回看该图,柳暗花明, 文末有完整测试用例

2.集成 Dozer 使用 Dozer 的方式很简单,如果你使用 Maven,添加依赖到 pom.xml 中即可

<dependency> <groupId>com.github.dozermapper</groupId> <artifactId>dozer-core</artifactId> <version>6.4.0</version> </dependency>

如果你使用 Spring Boot,引入 Dozer starter 即可:

<dependency> <groupId>com.github.dozermapper</groupId> <artifactId>dozer-spring-boot-starter</artifactId> <version>6.2.0</version> </dependency>

3,使用 Dozer 默认使用 Dozer starter 默认为我们注入了 Dozer Mapper,可以直接使用,另外,文章中所有测试用例中使用 Lombok 注解简化代码 3.1)当属姓名不通的,通过直接映射 第1步,不同属性名的在被转换bean上(Do)注解@Mapping(“vo里该字段名称”)

list转换:

package com.xunxiao.common.utils; import com.github.dozermapper.core.DozerBeanMapperBuilder; import com.github.dozermapper.core.Mapper; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; /** * dozer 转换器 * @author zq */ @Component public class GeneralConvertor { //持有Dozer单例, 避免重复创建DozerMapper消耗资源. @Resource public static final Mapper mapper = DozerBeanMapperBuilder.buildDefault(); /** * List 实体类 转换器 * * @param source 原数据 * @param clz 转换类型 * @param <T> * @param <S> * @return */ public <T, S> List<T> convertor(List<S> source, Class<T> clz) { if (source == null) return null; List<T> map = new ArrayList<>(); for (S s : source) { map.add(mapper.map(s, clz)); } return map; } /** * Set 实体类 深度转换器 * * @param source 原数据 * @param clz 目标对象 * @param <T> * @param <S> * @return */ public <T, S> Set<T> convertor(Set<S> source, Class<T> clz) { if (source == null) return null; Set<T> set = new TreeSet<>(); for (S s : source) { set.add(mapper.map(s, clz)); } return set; } /** * 实体类 深度转换器 * * @param source * @param clz * @param <T> * @param <S> * @return */ public <T, S> T convertor(S source, Class<T> clz) { if (source == null) return null; return mapper.map(source, clz); } public void convertor(Object source, Object object) { mapper.map(source, object); } public <T> void copyConvertor(T source, Object object) { mapper.map(source, object); } } List<InterxxxxxxxxxxxxxtItemDo> interestDoList = intxxxxxxxxxxxxxntItemService.getInterexxxxxxxxxst(ixxxxxxxxntItemPage.getIxxxxxxxd()); List<InterxxxxxxxxxxxxxmVo> resultVoList = null; //Do列表不为null,进行Do->Vo转换 if(interestDoList!=null){ resultVoList = this.convertor.convertor(interestDoList, InterestContentItemVo.class); }else{ return CommonPage.failed("xxxxxxxxxx"); }
最新回复(0)