今天要分享的是映射器-dozer,以往我们在编写代码时总会有对象之间互相转换,比较常规使用的方式是使用工具类进行字段之间的映射或者定义新的类使用get/set方法进行转换,一堆代码看着确实别扭了很多。
DTO:数据传输对象
那么,什么是dozer呢?
Dozer是java Bean到Java Bean的映射器,它以递归的方式将数据从一个对象复制到另外一个对象。
Dozer支持简单属性映射,双向映射,隐形映射以及递归映射。使用dozer映射器可以很方便的在我们的项目中进行
对象之间的转换。
我这里采用springBoot进行整合dozer的方式进行编写和配置dozer,首先我们先看下我们的pom文件吧。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wpw</groupId>
<artifactId>springboot-dozer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-dozer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
</dependency>
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>5.5.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
上面的pom文件仅仅是将项目作为一个web应用程序,引入dozer需要的jar包依赖。
下面,我们先定义一个dozer配置,让其装载入spring容器。
package com.wpw.springbootdozer;
import org.dozer.DozerBeanMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* @author pc
*/
@Configuration
@Scope("singleton")
public class DozerConfig {
@Bean
public DozerBeanMapper mapper(){
DozerBeanMapper mapper=new DozerBeanMapper();
return mapper;
}
}
@Configuration注解,表示这是一个配置类,里面包含了@Component注解,标注这是一个可以用spring管理的对象示例。
@Scope注解,表示实例的作用域,这里使用了singleton表示这是一个单例,想使用多例的可以用prototype。
下面,我们继续看下我们使用dozer需要定义的方法和实现类。
package com.wpw.springbootdozer;
import java.util.List;
import java.util.Set;
/**
* @author pc
*/
public interface DozerInterface {
/**
* 单个对象的深度复制及类型转换
* @param source 数据对象
* @param clazz 复制目标类型
* @param <T>
* @param <S>
*/
<T, S> T convert(S source, Class<T> clazz) ;
/**
* list深度复制
* @param sourceList 数据对象列表
* @param clazz 复制目标类型
* @param <T>
* @param <S>
*/
<T,S> List<T> convert(List<S> sourceList, Class<T> clazz);
/**
* set列表深度复制
* @param sourceSet 数据set集合列表
* @param clazz 复制目标类型
* @param <T>
* @param <S>
* @return
*/
<T,S> Set<T> convert(Set<S> sourceSet, Class<T> clazz);
/**
* 数组深度复制
* @param s 数据对象
* @param clazz 复制目标类型
* @param <T>
* @param <S>
* @return
*/
<T,S> T[] convert(S[] s,Class<T> clazz);
}
上面定义了接口的基本方法,为下面要分享的dozer工具类做下铺垫。
package com.wpw.springbootdozer;
import org.dozer.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.lang.reflect.Array;
import java.util.*;
@Component
@Lazy(value = true)
public class DozerUtil implements DozerInterface {
@Autowired
private Mapper mapper;
@Override
public <T, S> T convert(S source, Class<T> clazz) {
if (Objects.isNull(source)) {
return null;
}
return this.mapper.map(source, clazz);
}
@Override
public <T, S> List<T> convert(List<S> sourceList, Class<T> clazz) {
if (Objects.isNull(sourceList)) {
return null;
}
List<T> list = new ArrayList<>(sourceList.size());
for (S s : sourceList) {
list.add(this.mapper.map(s, clazz));
}
return list;
}
@Override
public <T, S> Set<T> convert(Set<S> sourceSet, Class<T> clazz) {
if (sourceSet==null){
return null;
}
Set<T> set=new HashSet<>(sourceSet.size());
for (S s:sourceSet){
set.add(this.mapper.map(s,clazz));
}
return set;
}
@Override
public <T, S> T[] convert(S[] s, Class<T> clazz) {
if (Objects.isNull(s)){
return null;
}
T[] arr= (T[]) Array.newInstance(clazz,s.length);
for (int i = 0; i <s.length ; i++) {
arr[i]=this.mapper.map(s[i],clazz);
}
return arr;
}
}
基于dozer需要的配置类信息就到这里结束了,我们这里为了演示dozer定义了两个基本类。
package com.wpw.springbootdozer;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @author pc
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Accessors(chain = true)
public class UserDto implements Serializable {
private String userCode;
private String loginName;
private String loginPassword;
private String deviceCode;
private String systemCode;
}
package com.wpw.springbootdozer;
import lombok.Data;
import java.io.Serializable;
@Data
public class UserVo implements Serializable {
private String userCode;
private String loginName;
private String loginPassword;
}
这里自己使用了单元测试的方法进行dozer映射器的测试,实际中也仅仅在业务逻辑层进行对象信息的转换。
package com.wpw.springbootdozer;
import jdk.nashorn.internal.ir.annotations.Ignore;
import org.dozer.Mapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashSet;
import java.util.Set;
@SpringBootTest
class SpringbootDozerApplicationTests {
@Autowired
private DozerUtil dozerUtil;
@Autowired
private Mapper mapper;
@Test
@Ignore
void contextLoads() {
UserDto userDto = UserDto.builder().build().setUserCode("0001").setSystemCode("systemCode").setLoginName("WwpwW").setLoginPassword("123456").setDeviceCode("0001");
UserVo userVo = mapper.map(userDto, UserVo.class);
System.out.println("userVo = " + userVo);
}
@Test
public void test(){
Set<UserDto> dtoSet=new HashSet<>();
UserDto userDto = UserDto.builder().build().setUserCode("0002");
dtoSet.add(userDto);
Set<UserVo> userVoSet = dozerUtil.convert(dtoSet, UserVo.class);
userVoSet.stream().forEach(System.out::println);
}
}
我们可以看下控制台打印的数据信息,UserDto对象的数据是不是已经映射到UserVo对象里面。
UserVo(userCode=0002, loginName=null, loginPassword=null)