在Java中 VO、 PO、DO、DTO、 BO、 QO、DAO、POJO的概念中介紹過Java中的各類模型概念。
在這裏簡單再總結一下:html
在平常的項目開發中,
VO
對應於頁面上須要顯示的數據(表單),DO
對應於數據庫中存儲的數據(數據表),DTO
對應於除兩者以外須要進行傳遞的數據。前端
不少人可能對VO和DTO並非那麼熟悉,相反對DO卻比較熟悉,那是由於在不少項目中因爲種種緣由咱們只使用了DO,緣由可能有如下幾種:java
一、項目過小,對於一種業務實體,封裝成一個DO就夠了。spring
二、並不熟悉DTO、VO,更不知道他們之間的區別。sql
三、瞭解DO\DTO\VO之間的區別,可是懶得用。數據庫
那麼,這裏,博主再囉嗦一下爲何要引入這麼多概念,爲何我要建議你們在本身的項目中使用這些實體對象。安全
咱們來看這樣一個例子。假如咱們的項目中由User這樣一個實體。咱們在建立User表的時候通常包含一下屬性:app
針對這個實體,咱們一般須要建立一個DO類,用來封裝這個User實體。工具
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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類的對象來進行數據傳輸。這樣作會有什麼問題嘛?測試
if/else
的方式來分狀況展現。還有不少問題,這這裏就不詳細介紹了。
可見,使用一個DO從頭用到尾(從數據庫到前端頁面)並非一種好的設計。
對於上面的例子,咱們能夠將他設計成如下類。因爲模型並不複雜,這裏只須要再引入VO就能夠了。
UserDO已經和數據庫字段一一對應了,這裏不須要修改。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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,用於封裝傳遞到前端須要展現的字段。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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嘛?我能夠明確告訴你的是,當你的系統愈來愈大,表中的字段愈來愈多的時候,使用DO\DTO\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
是複雜類型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
• 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.
|
在pom.xml中增長依賴
1
2
3
4
5
|
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>
5.5
.
1
</version>
</dependency>
|
使用Dozer進行類轉換
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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文件
1
2
3
|
List myMappingFiles =
new
ArrayList();
myMappingFiles.add(
"dozer-mapping.xml"
);
mapper.setMappingFiles(myMappingFiles);
|
配置dozer-mapping.xml文件
數據類型不一致,或者名稱不相同或者有級聯關係等狀況下,能夠經過文件dozer-mapping.xml
來進行定製Bean的轉換
1
2
3
4
5
6
7
8
9
10
|
<?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>
|
在pom.xml中增長依賴
1
2
3
4
5
|
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>
5.5
.
1
</version>
</dependency>
|
使用Spring集成dozer
1
2
3
4
5
6
7
8
9
10
11
|
<?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的轉換
1
2
3
4
5
6
7
8
|
@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方法看看還能不能把屬性值轉換過來,博主已經測試過了,是不能的。