DTO(Data Transfer Object)和 PO(Persistent Object)是两种不同的数据对象,它们在不同的场景下使用。
DTO 用于在不同的应用程序组件之间传输数据。它通常是轻量级的,只包含必要的字段,并且不包含任何业务逻辑。
PO 用于持久化数据到数据库。它通常是重量级的,包含所有必要的字段,并且包含业务逻辑。
1、以下是 DTO 和 PO 的比较
1.1、用途
DTO: 用于在不同的应用程序组件之间传输数据
PO: 用于持久化数据到数据库
1.2、重量
DTO: 轻量级
PO: 重量级
1.3、字段
DTO:只包含必要的字段
PO: 包含所有必要的字段
1.4、业务逻辑
DTO:不包含任何业务逻辑
PO: 包含业务逻辑
2、分层
在实际开发中,我们通常会使用 DTO 和 PO 来分离数据层和业务层。
DTO 位于数据层,用于在不同的应用程序组件之间传输数据。
PO 位于业务层,用于持久化数据到数据库。
3、PO与DTO互转示例
3.1、UserDTO
是用于在不同的应用程序组件之间传输数据的轻量级对象。
public class UserDTO {
private String username;
private String password;
private String email;
public UserDTO(){}
public UserDTO(String username, String password, String email) {
this.username = username;
this.password = password;
this.email = email;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
3.2、UserPO
是用于持久化数据到数据库的重量级对象。
public class UserPO {
private Long id;
private String username;
private String password;
private String email;
public UserPO(){}
public UserPO(Long id, String username, String password, String email) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
4、使用ModelMapper
4.1、在pom.xml文件中,引入ModelMapper依赖
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>3.1.1</version>
</dependency>
4.2、示例
import org.modelmapper.ModelMapper;
public UserPO testModelMapper(){
// 创建一个 ModelMapper 对象
ModelMapper modelMapper = new ModelMapper();
// 创建一个 DTO 对象
UserDTO userDTO = new UserDTO();
userDTO.setUsername("张三");
userDTO.setPassword("123456");
userDTO.setEmail("zhangsan@example.com");
// 将 DTO 对象转换为 PO 对象
UserPO userPO = modelMapper.map(userDTO, UserPO.class);
return userPO;
}
5、使用orika
5.1、在pom.xml文件中,引入orika依赖
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.5.4</version>
</dependency>
5.2、 示例
5.2.1、OrikaUtil 工具类
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.metadata.ClassMapBuilder;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author zhongyushi
* https://www.cnblogs.com/zys2019/p/17005798.html#_label1_2
*/
@Component
public class OrikaUtil {
@Resource
private MapperFactory mapperFactory;
/**
* 字段映射
*
* @param aType 源对象类型
* @param bType 目标对象类型
* @param fields 不同字段映射值
* @param <A>
* @param <B>
*/
private <A, B> void filedMap(Class<A> aType, Class<B> bType, Map<String, String> fields) {
ClassMapBuilder<A, B> mapBuilder = mapperFactory.classMap(aType, bType);
if (fields != null && fields.size() > 0) {
Set<Map.Entry<String, String>> entries = fields.entrySet();
for (Map.Entry<String, String> entry : entries) {
mapBuilder.field(entry.getKey(), entry.getValue());
}
}
mapBuilder.byDefault().register();
}
/**
* 对象的复制
*
* @param aType 源对象类型
* @param bType 目标对象类型
* @param fields 不同字段映射值
* @param source 要复制的对象
* @param <A>
* @param <B>
* @return
*/
public <A, B> B beanCopy(Class<A> aType, Class<B> bType, Map<String, String> fields, A source) {
filedMap(aType, bType, fields);
B target = mapperFactory.getMapperFacade().map(source, bType);
return target;
}
/**
* 对象的复制
*
* @param aType 源对象类型
* @param bType 目标对象类型
* @param source 要复制的对象
* @param <A>
* @param <B>
* @return
*/
public <A, B> B beanCopy(Class<A> aType, Class<B> bType, A source) {
return beanCopy(aType, bType, null, source);
}
/**
* 集合的复制
*
* @param aType 源对象类型
* @param bType 目标对象类型
* @param fields 不同字段映射值
* @param source 要复制的对象
* @param <A>
* @param <B>
* @return
*/
public <A, B> List<B> beanListCopy(Class<A> aType, Class<B> bType, Map<String, String> fields, Iterable<A> source) {
filedMap(aType, bType, fields);
List<B> bList = mapperFactory.getMapperFacade().mapAsList(source, bType);
return bList;
}
/**
* 集合的复制
*
* @param aType 源对象类型
* @param bType 目标对象类型
* @param source 要复制的对象
* @param <A>
* @param <B>
* @return
*/
public <A, B> List<B> beanListCopy(Class<A> aType, Class<B> bType, Iterable<A> source) {
return beanListCopy(aType, bType, null, source);
}
}
5.2.2、配置类
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* orika
*/
@Configuration
public class MapperFactoryAutoConfig {
@Bean
public MapperFactory getFactory(){
return new DefaultMapperFactory.Builder().build();
}
}
5.2.3、测试示例
import cn.example.demo.dto.UserDTO;
import cn.example.demo.dto.UserPO;
import cn.example.demo.utils.OrikaUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StopWatch;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Autowired
private OrikaUtil orikaUtil;
/**
* 单个对象
* @return
*/
public UserPO orika0() {
UserDTO userDto = new UserDTO("orika0", "123", "zhansan@qq.com");
Map<String, String> map = new HashMap<>();
//map.put("password", "password1");//有差异的属性名称
UserPO userPo = orikaUtil.beanCopy(UserDTO.class, UserPO.class, map, userDto);
System.out.println(userPo);
return userPo;
}
/**
* 对象列表转换
* 10万条耗时 583 ms
*/
public List<UserPO> orika1() {
Integer t = 100000;
List<UserDTO> list = new ArrayList<>();
for (int i = 0; i < t; i++) {
UserDTO userDto = new UserDTO("orika" + i, "111"+ i, "orika"+ i+"@qq.com");
list.add(userDto);
}
Map<String, String> map = new HashMap<>();
//map.put("age", "userAge"); //名称不同的属性之间映射
StopWatch watch = new StopWatch();
watch.start("orika");
List<UserPO> poList = orikaUtil.beanListCopy(UserDTO.class, UserPO.class, map, list);
System.out.println(poList);
watch.stop();
System.out.println("orika 复制用时:" + watch.getLastTaskTimeMillis());
return poList;
}
6、使用 dozer
6.1、在pom.xml文件中,引入dozer依赖
<dependency>
<groupId>com.github.dozermapper</groupId>
<artifactId>dozer-core</artifactId>
<version>6.5.0</version>
</dependency>
6.2、示例
import cn.example.demo.dto.UserDTO;
import cn.example.demo.dto.UserPO;
import com.github.dozermapper.core.DozerBeanMapperBuilder;
import com.github.dozermapper.core.Mapper;
import org.springframework.util.StopWatch;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
//参考地址:
//https://dozermapper.github.io/user-guide.pdf
//https://www.jb51.net/article/239801.htm
//https://blog.csdn.net/weixin_33786077/article/details/94759020
public List<UserPO> dozer() {
List<UserDTO> list = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
UserDTO userDto = new UserDTO("dozer" + i, "111"+ i, "dozer"+ i+"@qq.com");
list.add(userDto);
}
List<UserPO> poList = new ArrayList<>();
Mapper mapper = DozerBeanMapperBuilder.buildDefault();
StopWatch watch = new StopWatch();
watch.start("dozer");
list.stream().forEach(item -> {
UserPO userPo = mapper.map(item, UserPO.class);
poList.add(userPo);
System.out.println("userPo:" + item.hashCode());
});
watch.stop();
System.out.println("dozer复制用时:" + watch.getLastTaskTimeMillis());
return poList;
}
7、MapStruct
参考地址:https://mapstruct.org/
8、JMapper
参考地址:https://github.com/jmapper-framework/jmapper-core