Dozer를 사용하여 DO를 VO로 우아하게 변환

高洛峰
풀어 주다: 2016-10-15 13:42:36
원래의
2786명이 탐색했습니다.

DO, DTO, VO란 무엇인가

Java의 VO, PO, DO, DTO, BO, QO, DAO, POJO 개념에 Java의 다양한 모델 개념이 도입되었습니다.
간단한 요약:

일상 프로젝트 개발에서 VO는 페이지에 표시되어야 하는 데이터(양식)에 해당하고, DO는 데이터베이스에 저장된 데이터(데이터 테이블)에 해당하며, 및 DTO 둘 외에 전송해야 하는 데이터에 해당합니다.

많은 사람들이 VO와 DTO에 익숙하지 않을 수 있지만 DO에는 더 익숙합니다. 그 이유는 다음과 같은 이유로 많은 프로젝트에서 DO만 사용하기 때문입니다.

1. 사업체의 경우 프로젝트가 너무 작습니다.

2. 저는 DTO와 VO에 대해 잘 모릅니다. 차이점은 말할 것도 없습니다.

3. DODTOVO의 차이점을 알지만, 사용하기에는 너무 게으릅니다.

여기서 블로거는 왜 그렇게 많은 개념이 소개되는지, 그리고 왜 이러한 엔터티 개체를 자신의 프로젝트에 사용하도록 권장하는지에 대해 이야기하겠습니다.

DO 하나만 사용하면 어떨까요

이러한 예를 살펴보겠습니다. 우리 프로젝트에 User와 같은 엔터티가 있다고 가정합니다. User 테이블을 생성할 때 일반적으로 다음 속성을 포함합니다.

Dozer를 사용하여 DO를 VO로 우아하게 변환

이 엔터티의 경우 일반적으로 User 엔터티를 캡슐화하기 위해 DO 클래스를 생성해야 합니다.

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
}
로그인 후 복사

그런 다음 코드에서는 DAO에서 프런트엔드 디스플레이까지 이 UserDO 클래스의 개체를 통해 데이터를 전송합니다. 이 작업을 수행하는 데 문제가 있나요?

불필요한 필드도 프런트 엔드 페이지로 전달됩니다.

프런트 엔드에 비밀번호, 생성된 시간, 업데이트된 시간 및 상태와 같은 필드를 전혀 표시할 필요가 없을 수도 있지만 이러한 필드는 프런트 엔드에 전달될 수도 있습니다(실행 중에 해당 필드를 쿼리하지 않는 한). SQL 쿼리) 필드). 이로 인해 데이터 전송량이 늘어날 뿐만 아니라 보안 문제도 발생할 수 있습니다.

일부 필드를 변환해야 하지만 지원되지 않습니다.

위 예의 정치적 외모 필드의 경우 데이터베이스에 숫자를 저장하지만 프런트 엔드 페이지에 표시하고 싶은 내용은 중국어 설명입니다. 이 상황은 프런트 엔드의 if/else를 통해 사례별로만 표시될 수 있습니다.

일부 필드를 표시해야 하지만 데이터베이스에 표시하고 싶지 않습니다.

User 테이블에는 이 사용자의 companyId만 저장하고 회사를 쿼리해야 합니다. 테이블을 동시에 사용하여 회사의 자세한 내용을 쿼리할 수 있습니다. User 객체의 경우, 그 사람이 속한 회사를 프런트엔드에 동시에 표시하고, 하나의 쿼리를 통해 그 회사를 모두 알아보고 싶다면 어떻게 해야 할까요? 몇 가지 간단한 해결책이 있습니다. 첫 번째 방법은 UserDO가 Company 클래스의 속성을 포함하고 이를 이 속성을 통해 전달하도록 하는 것입니다. 다른 하나는 프런트 엔드에 전달하려는 회사 속성을 UserDO에 작성하는 것입니다. 그런데 이것이 실제로 이루어지면 UserDO를 여전히 DO라고 부를 수 있나요?

아직 궁금한 점이 많아 여기서는 자세히 다루지 않겠습니다.

처음부터 끝까지(데이터베이스부터 프런트 엔드 페이지까지) 하나의 DO를 사용하는 것은 좋은 디자인이 아니라는 것을 알 수 있습니다.

DO, DTO, VO를 올바르게 사용하는 방법

위의 예를 다음과 같은 클래스로 설계할 수 있습니다. 모델이 복잡하지 않기 때문에 여기서는 VO만 소개하면 됩니다.

UserDO는 이미 데이터베이스 필드와 일대일로 대응하므로 여기서는 수정할 필요가 없습니다.

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
}
로그인 후 복사

프런트 엔드로 전달될 때 표시해야 하는 필드를 캡슐화하기 위해 UserVO를 도입합니다.

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에는 표시에 필요한 필드만 포함되어 있습니다. 표시에 필요하지 않은 필드는 여기에 포함될 필요가 없습니다.

이 클래스를 도입한 후 데이터베이스 쿼리를 수행할 때 UserDO를 사용할 수 있고, 프런트 엔드에 전달해야 할 때 DO를 VO로 변환할 수 있습니다.

요약

이를 보면 UserDO와 UserVO에 동일한 필드가 많이 포함되어 있다는 것을 알 수 있습니다. 별도의 VO를 디자인하는 것이 꼭 필요한가요? 제가 분명히 말씀드릴 수 있는 것은 시스템이 점점 더 커지고 테이블에 필드가 점점 더 많아지면 계층적 처리에 DODTOVO와 같은 개념을 사용하는 것이 절대적으로 유익하다는 것입니다. 서로 다른 엔터티 클래스 간을 효과적으로 변환하는 방법에 대해서는 다음에 소개하겠습니다.

DO를 VO로 우아하게 변환

Dozer는 객체 변환 도구입니다.

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方法看看还能不能把属性值转换过来,博主已经测试过了,是不能的。


원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿