Home >类库下载 >java类库 >Use Dozer to elegantly convert DO to VO

Use Dozer to elegantly convert DO to VO

高洛峰
高洛峰Original
2016-10-15 13:42:362813browse

What are DO, DTO and VO

Various model concepts in Java have been introduced in the concepts of VO, PO, DO, DTO, BO, QO, DAO and POJO in Java.
Here is a brief summary:

In daily project development, VO corresponds to the data (form) that needs to be displayed on the page, DO corresponds to the data stored in the database (data table), and DTO corresponds to the other than the two. Data that needs to be transferred externally.

Many people may not be so familiar with VO and DTO, but are more familiar with DO. That is because in many projects we only use DO for various reasons. The reasons may be as follows:

1. The project is too Small, for a business entity, it is enough to encapsulate it into a DO.

2. I am not familiar with DTO and VO, let alone the difference between them.

3. I know the difference between DODTOVO, but I am too lazy to use it.

So, here, the blogger will explain why so many concepts are introduced, and why I recommend that you use these entity objects in your projects.

Why can’t we just use one DO

Let’s look at such an example. Suppose there is an entity like User in our project. When we create the User table, we generally include the following attributes:

Use Dozer to elegantly convert DO to VO

For this entity, we usually need to create a DO class to encapsulate this User entity.

public class UserDO {
    private Integer id;                 //唯一主键
    private Date createdTime;           //创建时间
    private Date updatedTime;           //最后更新时间
    private String name;                //姓名
    private Integer age;                //年龄
    private String gender;              //性别
    private String address;             //住址
    private String password;            //密码
    private String nickName;            //昵称
    private Date birthday;              //生日
    private String politicalStatus;     //政治面貌,1表示群众,2表示团员,3表示党员,4表示其他,100表示未知
    private Integer companyId;          //公司的ID
    private Integer status;             //数据状态,1表示可用,0表示不可用
 
    //setter and getter
}

Then, in the code, from DAO to front-end display, we transmit data through the object of this UserDO class. Are there any problems with doing this?

Unnecessary fields are also passed to the front-end page.

For fields such as password, createdTime, updatedTime and status, we may not need to display them on the front end at all, but these fields may also be passed to the front end (unless we do not query the corresponding fields during SQL query). This not only increases the amount of data transmission, but may also cause security issues.

Some fields need to be converted, but cannot be supported.

For the political appearance field in the above example, we store numbers in the database, but what I want to display on the front-end page is a Chinese description. This situation can only be displayed on a case-by-case basis through if/else on the front end.

Some fields want to be displayed, but they do not want to appear in the database

In the User table, we only save the companyId of this user, and we need to query the company table at the same time to find out more detailed information about the company. For the User object, what if we want to display the company he belongs to at the same time on the front end and want to find out all of them through one query? There are several simple solutions. The first one is to let UserDO contain an attribute of the Company class and pass it through this attribute. Another option is to write the Company attributes we want to pass to the front end into UserDO. However, if this is really done, can UserDO still be called DO?

There are still many questions, so I won’t go into details here.

It can be seen that using one DO from beginning to end (from database to front-end page) is not a good design.

How to use DO, DTO, VO correctly

For the above example, we can design it into the following class. Since the model is not complicated, we only need to introduce VO here.

UserDO already corresponds to the database field one-to-one, no modification is needed here.

public class UserDO {
    private Integer id;                 //唯一主键
    private Date createdTime;           //创建时间
    private Date updatedTime;           //最后更新时间
    private String name;                //姓名
    private Integer age;                //年龄
    private String gender;              //性别
    private String address;             //住址
    private String password;            //密码
    private String nickName;            //昵称
    private Date birthday;              //生日
    private String education;           //学历
    private String politicalStatus;     //政治面貌,1表示群众,2表示团员,3表示党员,4表示其他,100表示未知
    private Integer companyId;          //公司的ID
    private Integer status;             //数据状态,1表示可用,0表示不可用
 
    //setter and getter
}

Introduces UserVO to encapsulate the fields that need to be displayed on the front end.

public class UserVO {
    private Integer id;                 //唯一主键
    private String name;                //姓名
    private Integer age;                //年龄
    private String gender;              //性别
    private String address;             //住址
    private String nickName;            //昵称
    private Date birthday;              //生日
    private String education;           //学历
    private String politicalStatus;     //政治面貌,群众、团员、党员等
    private Company company;            //公司
 
    //setter and getter
}

UserVO only contains the fields required for display, and fields that are not required for display do not need to be included here.

After introducing this class, we can use UserDO when performing database queries, and then convert DO to VO when it needs to be passed to the front end.

Summary

Seeing this, you may have discovered that UserDO and UserVO contain a large number of the same fields. Is it really necessary to design a separate VO? What I can tell you clearly is that when your system becomes larger and larger and there are more and more fields in the table, it is absolutely beneficial to use concepts such as DODTOVO for hierarchical processing. As for how to effectively convert between different entity classes, I will introduce it next.

Elegantly convert DO to VO

Dozer is an object conversion tool.

Dozer可以在JavaBean到JavaBean之间进行递归数据复制,并且这些JavaBean可以是不同的复杂的类型。
所有的mapping,Dozer将会很直接的将名称相同的fields进行复制,如果field名不同,或者有特别的对应要求,则可以在xml中进行定义。

前面我们介绍的DO\DTO\VO不就是JavaBean嘛。正好可以使用Dozer进行转换呀。
除了使用Dozer,当然你还由其他选择:

典型的解决方案就是手动拷贝,弊端很明显,代码中充斥大量Set 和Get方法,真正的业务被埋藏值与值的拷贝之中。

另一种方案就是使用BeanUtil,但BeanUtil不够很好的灵活性,又时候还不得不手动拷贝。Dozer可以灵活的对对象进行转换,且使用简单。

Dozer 支持的转换类型

Primitive 基本数据类型 , 后面带 Wrapper 是包装类 Complex Type 是复杂类型

•   Primitive to Primitive Wrapper 
•   Primitive to Custom Wrapper 
•   Primitive Wrapper to Primitive Wrapper 
•   Primitive to Primitive 
•   Complex Type to Complex Type 
•   String to Primitive 
•   String to Primitive Wrapper 
•   String to Complex Type if the Complex Type contains a String constructor 
•   String 到复杂类型 , 如果复杂类型包含一个 String 类型的构造器 
•   String to Map 
•   Collection to Collection 
•   Collection to Array 
•   Map to Complex Type 
•   Map to Custom Map Type 
•   Enum to Enum 
•   Each of these can be mapped to one another: java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp, java.util.Calendar, java.util.GregorianCalendar 
•   String to any of the supported Date/Calendar Objects. 
•   Objects containing a toString() method that produces a long representing time in (ms) to any supported Date/Calendar object.

在普通Java项目中使用Dozer

在pom.xml中增加依赖

<dependency>
  <groupId>net.sf.dozer</groupId>
  <artifactId>dozer</artifactId>
  <version>5.5.1</version>
</dependency>

使用Dozer进行类转换

public class Main {
 
    public static void main(String[] args) {
        DozerBeanMapper mapper = new DozerBeanMapper();
        UserDO userDO = new UserDO();
        userDO.setName("hollis");
        userDO.setAddress("hz");
        userDO.setAge(25);
        userDO.setCompanyId(1);
        userDO.setBirthday(new Date());
        userDO.setGender("male");
        userDO.setEducation("1");
        userDO.setNickName("hollis");
        userDO.setPoliticalStatus("3");
        UserVO userVO = (UserVO) mapper.map(userDO, UserVO.class);
        System.out.println(userVO);
    }
}

特殊的字段转换
在使用mapper进行转换前,设置一个或多个mapping文件

List myMappingFiles = new ArrayList();    
myMappingFiles.add("dozer-mapping.xml");    
mapper.setMappingFiles(myMappingFiles);

配置dozer-mapping.xml文件

数据类型不一致,或者名称不相同或者有级联关系等情况下,可以通过文件dozer-mapping.xml来进行定制Bean的转换

<?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">
 
    <mapping>
        <class-a>com.hollis.lab.UserDO</class-a>
        <class-b>com.hollis.lab.UserVO</class-b>
    </mapping>
</mappings>

在JavaWeb项目中使用Dozer

在pom.xml中增加依赖

<dependency>
  <groupId>net.sf.dozer</groupId>
  <artifactId>dozer</artifactId>
  <version>5.5.1</version>
</dependency>

使用Spring集成dozer

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="baseMapper" class="org.dozer.spring.DozerBeanMapperFactoryBean">
        <property name="mappingFiles">
            <list>
                <value>classpath:mapping/dozer-mapping.xml</value>
            </list>
        </property>
    </bean> 
</beans>

使用baseMapper进行Bean的转换

@Autowired
private Mapper baseMapper;
private UserVO doToVo(UserDO userDO){
    if(userDO == null) return null;
    UserVO vo = baseMapper.map(userDO, UserVO.getClass());
    if(userDO.getCompanyId != null) getCompany(vo);
    return vo;
}

通过以上的代码加配置,我们就实现了从DO转换到VO的部分操作,之所以说是部分操作,是因为我们在dozer-mapping.xml并没有做多余的配置,只是使用dozer将DO中和VO中共有的属性转换了过来。对于其他的类型不同或者名称不同等的转换可以参考官网例子通过设置dozer-mapping.xml文件来实现。

上面还有一个getCompany()没有实现。这个方法其实就是通过companyId查询出company实体然后在赋值给UserVO中的company属性。

在使用了dozer之后,我们可以把UserDO中的部分属性赋值到UserVO中,其实,转化的过程是通过调用UserDO中的getter方法和UserVO中的setter方法来实现的。读者可以做个实验,对于UserVO中的部分属性不写Setter方法看看还能不能把属性值转换过来,博主已经测试过了,是不能的。


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn