呵呵,在《develope J2EE without EJB》中,DTO被狠很地批判了一把,rod說(shuō)這完全是反模式。可實(shí)際項(xiàng)目當(dāng)中,我們還是不得不在使用。VO,PO,一牽扯到概念總是多么復(fù)雜。。。把一個(gè)PO從頭傳到尾??從頁(yè)面到數(shù)據(jù)庫(kù),一捅到底?NO,NO,萬(wàn)一你要顯示給用戶的是幾個(gè)PO的結(jié)合怎么辦?萬(wàn)一我們只是需要某幾個(gè)屬性組合在一起顯示怎么辦?一捅到底的策略是多么丑陋,而且你完全把你的數(shù)據(jù)庫(kù)設(shè)計(jì)模型暴露給用戶。所以我們需要一些map工具來(lái)轉(zhuǎn)換,在這方面,過(guò)去我只知道有個(gè) BeanUtils,不夠靈活,而今天,接觸了下dozer,啊,跟spring一樣的理念!靈活多變,你想怎么映射,想怎么換都可以。看看它支持的轉(zhuǎn)換類(lèi)型:
? 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
? 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 if an explicit date format mapping attribute is
specified.
? Objects containing a toString() method that produces a long representing time in (ms) to any
supported Date/Calendar object.
幾乎我們能想到的,它都提供了方法來(lái)做到。而且dozer可以很容易地跟spring集成。下面舉個(gè)簡(jiǎn)單例子:
定義一個(gè)Book對(duì)象:
package com.denny_blue.dozerdemo;
public class Book {
?private String name;
?private String author;
?
?
?public Book(){
??
?}?
?public void setAuthor(String author) {
??this.author = author;
?}
?public String getAuthor() {
??return (this.author);
?}
?public void setName(String name){
??this.name=name;
?}?
?public String getName(){
??return this.name;
?}
}
簡(jiǎn)單的,我們要實(shí)例化一個(gè)對(duì)象,然后clone此對(duì)象,注意,是clone!
package com.denny_blue.dozerdemo;
import net.sf.dozer.util.mapping.DozerBeanMapper;
import java.util.List;
import java.util.ArrayList;
public class MyFirstDozerDemo {
?public static void main(String args[]){
??Book book1=new Book();
??book1.setAuthor("dennis");
??book1.setName("dozer demo");
??DozerBeanMapper mapper=new DozerBeanMapper();
??Book book2=new Book();
??mapper.map(book1,book2);
? book2=(Book)mapper.map(book1,com.denny_blue.dozerdemo.Book.class);
??System.out.println("book2's name:"+book2.getName());
?????}
}?
OK,如此簡(jiǎn)單,我們把book1的屬性完全復(fù)制給了book2,兩者現(xiàn)在是完全獨(dú)立的對(duì)象。可如果僅僅是這樣,我們用BeanUtils不是也很容易辦到? book2=(Book)BeanUtils.cloneBean(book1);可如果我要把book1映射給一個(gè)完全不同的類(lèi)的對(duì)象怎么辦?而且他們的屬性名也不相同,怎么辦?比如,一個(gè)CookBook類(lèi):
package com.denny_blue.dozerdemo;
public class CookBook {
?private String bookName;
?private String author;
?public CookBook(){}
?public String getBookName() {
??return (this.bookName);
?}
?public void setBookName(String bookName) {
??this.bookName = bookName;
?}
?public String getAuthor() {
??return (this.author);
?}
?public void setAuthor(String author) {
??this.author = author;
?}
}
它的bookName屬性與Book的name屬性名不一樣,我們?cè)撊绾螐?fù)制?dozer通過(guò)xml文件的配置來(lái)靈活地達(dá)到這個(gè)目的。我們配置一個(gè)dozerBeanMapping.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mappings PUBLIC "-//DOZER//DTD MAPPINGS//EN"
"<mappings>
<configuration>
<stop-on-errors>false</stop-on-errors>
<date-format>MM/dd/yyyy HH:mm</date-format>
<wildcard>true</wildcard>
</configuration>
<mapping>
<class-a>com.denny_blue.dozerdemo.Book</class-a>
<class-b>com.denny_blue.dozerdemo.CookBook</class-b>
<field>
<a>name</a>
<b>bookName</b>
</field>
<field>
<a>author</a>
<b>author</b>
</field>
</mapping>
</mappings>
如上所示,<class-a>指定所要復(fù)制的源對(duì)象,<class-b>復(fù)制的目標(biāo)對(duì)象,<a>源對(duì)象的屬性名, <b>目標(biāo)對(duì)象的屬性名。wildcard默認(rèn)為true,在此時(shí)默認(rèn)對(duì)所有屬性進(jìn)行map,如果為false,則只對(duì)在xml文件中配置的屬性進(jìn)行map。此時(shí)的demo 看起來(lái)像這樣:
package com.denny_blue.dozerdemo;
import net.sf.dozer.util.mapping.DozerBeanMapper;
import java.util.List;
import java.util.ArrayList;
public class MyFirstDozerDemo {
?public static void main(String args[]){
??Book book1=new Book();
??book1.setAuthor("dennis");
??book1.setName("dozer demo");
??DozerBeanMapper mapper=new DozerBeanMapper();
? book2=(Book)mapper.map(book1,com.denny_blue.dozerdemo.Book.class);
? CookBook cookBook=new CookBook();
? List myMappingFiles = new ArrayList();
? myMappingFiles.add("dozerBeanMapping.xml");
? mapper.setMappingFiles(myMappingFiles);
? cookBook=(CookBook)mapper.map(book1,CookBook.class);
? System.out.println("cookBook's name:"+?? cookBook.getBookName()+"???? cookBook's author:"+
????????????????????? cookBook.getAuthor());
?}
}
通過(guò)mapper.setMappingFiles()設(shè)置映射文件,可以添加多個(gè)配置文件,也可以把所有的映射寫(xiě)在一個(gè)配置文件里面。??更多復(fù)雜例子請(qǐng)見(jiàn)它自帶的doc。