概述
Dozer 是什么?
Dozer 是 Java Bean 到 Java Bean 的映射器,他以递归的方式将数据从一个对象复制到另一个对象。
它支持简单的属性映射,复杂类型映射,双向映射,隐式显式的映射,以及递归映射,使用该映射器可以很方便的在项目中进行 pojo、do、vo 之间的转换。
它支持三种映射方式:注解、API、XML。
它是开源的,遵从 Apache 2.0 协议。
使用
安装
Maven
如果你的项目使用 maven,添加以下依赖到你的 pom.xml 即可:
代码语言:javascript复制<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>${dozer.version}</version>
</dependency>
导入 jar 包
如果不使用 Maven,那么需要引入 Dozer 的 jar 包以及其依赖的第三方 jar 包。
- Dozer
- Dozer 依赖的第三方 jar 包
入门
创建两个 Java Bean 类:
代码语言:javascript复制public class User {
private String name;
private Integer age;
private Date birthday;
// 省略 setter 和 getter 方法
}
代码语言:javascript复制public class UserApiDestinationObject {
private String name;
private String age;
public String birthday;
// 重写 toString 方法,方便测试
@Override
public String toString() {
return "UserApiDestinationObject{"
"name='" name '''
", age='" age '''
", birthday='" birthday '''
'}';
}
// 省略 getter、setter 方法
}
测试:
代码语言:javascript复制@Test
public void apiTest() {
Mapper mapper = new DozerBeanMapper();
User user = new User();
user.setName("sid10t.");
user.setAge(3);
user.setBirthday(new Date());
UserApiDestinationObject destinationObject = mapper.map(user, UserApiDestinationObject.class);
System.out.println(destinationObject);
}
输出:
代码语言:javascript复制UserApiDestinationObject{name='sid10t.', age='3', birthday='Tue Mar 08 10:56:02 CST 2022'}
此时,Dozer 自动完成 User 类到 ApiUserDestination 类的映射。这是 Dozer 的默认映射方式——隐式映射,Dozer 自动的将两个实体类的相同属性名的属性进行映射。如果两个属性的属性名相同,但是类型不同,Dozer 会按照默认的转换规则进行类型的转换,而且不同修饰符的属性也能正常进行映射。
注意:
两个 Java Bean 类都是需要 get 和 set 方法的,上述省略不代表不需要,不然是无法进行映射的;
如果运行时报了这个异常:java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
,则需要导入 slf4j 的 jar 包:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.22</version>
</dependency>
XML 映射
有时候两个 bean 的属性名并不完全相同,这时候通过 Dozer 的隐式映射并不能满足我们的实际需求,这时候就可以通过 Dozer 的另一种映射方式——显示映射进行映射。通过显示映射的方法需要我们自己创建一个 xml 的映射文件来指定两个类的映射关系。这些 xml 配置文件将在运行时由 Dozer 引擎使用。
下面演示 Dozer 的显示映射方式:
新建 UserXmlDestinationObject 类:
代码语言:javascript复制public class UserXmlDestinationObject {
private String username;
private String age;
public String dateOfBirth;
// 省略 setter 和 getter 方法
// 省略 toString 方法
}
在 resource 目录下新建 userMapping.xml 文件,xml 中的配置信息如下:
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<mappings xmlns="http://dozer.sourceforge.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://dozer.sourceforge.net
http://dozer.sourceforge.net/schema/beanmapping.xsd">
<!--全局配置,配置日期的映射格式-->
<configuration>
<date-format>yyyy-MM-dd HH:mm:ss</date-format>
</configuration>
<mapping wildcard="true">
<class-a>User</class-a>
<class-b>UserXmlDestinationObject</class-b>
<field>
<a>name</a>
<b>username</b>
</field>
<field>
<a>birthday</a>
<b>dateOfBirth</b>
</field>
</mapping>
</mappings>
一个 mappings 元素包含多个 mapping 元素,每个 mapping 元素都有类映射声明和字段的映射关系。wildcard 属性默认值为 true,这意味着 Dozer 将会尝试映射两个类的每个字段,当该属性设置为 false 时,Dozer 将仅映射显示定义的字段。也可以在 filed 下的 <a>
或者 <b>
节点下添加配置信息,如:<a date-fomat="MM/dd/yyyy HH:mm">
,此时字段的配置信息优先级别高于全局配置。
测试:
代码语言:javascript复制@Test
public void xmlTest(){
List myMappingFiles = new ArrayList();
myMappingFiles.add("userMapping.xml");
DozerBeanMapper mapper = new DozerBeanMapper();
mapper.setMappingFiles(myMappingFiles);
User user = new User();
user.setName("sid10t.");
user.setAge(3);
user.setBirthday(new Date());
UserXmlDestinationObject destinationObject = mapper.map(user, UserXmlDestinationObject.class);
System.out.println(destinationObject);
}
输出:
代码语言:javascript复制//<mapping wildcard="true">
UserXmlDestinationObject{username='sid10t.', age='3', dateOfBirth='2022-03-08 12:54:14'}
//<mapping wildcard="false">
UserXmlDestinationObject{username='sid10t.', age='null', dateOfBirth='2022-03-08 12:57:09'}
注解映射
从版本 5.3.2 开始,Dozer 也开始提供注解支持,使用注解的明显原因是避免在映射代码中复制字段和方法名称,注解可以放在映射类的属性上,从而减少代码量。但是有些情况应该减少使用注解,甚至无法使用注解,如:
- 你正在映射类时,这些类不在你的控制下,但在库中提供;
- 映射类非常复杂,而且需要许多配置;
新建 UserAnnotationsObject 类:
代码语言:javascript复制public class UserAnnotationsObject {
@Mapping("name")
public String username;
private String age;
@Mapping("birthday")
private String dateOfBirth;
// 省略 getter、setter 方法
// 省略 toString 方法
}
注意:dozer 是双向映射的,无论使用 xml 或者 注解的方式进行映射,都只需要配置一个类的映射关系就行。
测试:
代码语言:javascript复制@Test
public void annotationsTest(){
DozerBeanMapper mapper = new DozerBeanMapper();
User user = new User();
user.setName("sid10t.");
user.setAge(3);
user.setBirthday(new Date());
UserAnnotationsObject destinationObject = mapper.map(user, UserAnnotationsObject.class);
System.out.println(destinationObject);
}
输出:
代码语言:javascript复制UserAnnotationsObject{username='sid10t.', age='3', dateOfBirth='Tue Mar 08 13:03:37 CST 2022'}
通过注解的方式,User 类中的 "name" 属性将映射到 UserAnnotationsObject 类中的 username 属性,不用担心 private 修饰符,Dozer 将会自动处理。目前 Dozer 只提供 @Mapping
这一个注解,后续版本可能会添加新的注解,至于现在,你可以混合 api 方式、xml 方式、注解方式进行类的映射。
注意:对于实际应用程序,建议不要在每次映射对象时创建一个新的 Mapper 实例,而是重新使用上次创建的 Mapper 实例,可以把 Mapper 封装成单例模式使用。
SpringBoot 集成
自从 6.2.0 版本之后,Dozer 提供了 dozer-spring-boot-starter 用于 Spring Boot 的集成,如果使用 Maven 构建的项目,只需要在 pom.xml 文件中引入如下依赖:
代码语言:javascript复制<dependency>
<groupId>com.github.dozermapper</groupId>
<artifactId>dozer-spring-boot-starter</artifactId>
<version>{dozer-version}</version>
</dependency>
新建 DozerMapperConfig 配置类:
代码语言:javascript复制@Configuration
public class DozerMapperConfig {
@Bean
public DozerBeanMapperFactoryBean dozerMapper(@Value("classpath:mapping/*.xml") Resource[] resources) throws IOException {
DozerBeanMapperFactoryBean dozerBeanMapperFactoryBean = new DozerBeanMapperFactoryBean();
dozerBeanMapperFactoryBean.setMappingFiles(resources);
return dozerBeanMapperFactoryBean;
}
}
把 DozerBeanMapperFactoryBean 注入到 IOC 容器中,就能优雅的使用 Dozer 啦,如:
代码语言:javascript复制@SpringBootTest
@RunWith(SpringRunner.class)
public class DozerTest {
@Autowired
private Mapper mapper;
@Test
public void dozerForSbTest(){
User user = new User();
user.setName("hxy");
user.setAge(123);
user.setBirthday(new Date());
UserXmlDestinationObject destinationObject = mapper.map(user, UserXmlDestinationObject.class);
System.out.println(destinationObject);
}
}
结语
感谢你能看到这里,但是很遗憾的告诉你,Dozer 已经停更了,所以本文也只是简单的介绍了一下,因为项目用到了,就简单的记录一下;
Dozer 项目当前不再维护了,并且将来很大可能被弃用,然后新用户不建议使用了,老用户也推荐大家迁移到 MapStruct 和 ModelMapper 等类库上面去。
参考:
- Dozer - 码农教程
- Dozer 使用小结 - 静默虚空