?? 面向 java 開發人員的 ajax ajax 的 java 對象序列化.htm
字號:
<TR>
<TD class=code-outline><PRE class=displaycode>
public Element toXml() {
Element elOrder = new Element("order");
elOrder.setAttribute("id",id);
elOrder.setAttribute("cost",getFormattedCost());
Element elDate = new Element("date").addContent(date);
elOrder.addContent(elDate);
Element elItems = new Element("items");
for (Iterator<Item> iter =
items.iterator() ; iter.hasNext() ; ) {
elItems.addContent(iter.next().toXml());
}
elOrder.addContent(elItems);
return elOrder;
}
</PRE></TD></TR></TBODY></TABLE><BR>
<P>在這里可以看到用 JDOM 創建元素、使用屬性和添加元素內容有多么簡單。遞歸地調用復合 JavaBean 的
<CODE>toXml()</CODE> 方法是為了取得它們子圖的 <CODE>Element</CODE>
表示。例如,<CODE>items</CODE> 元素的內容是通過調用 <CODE>Order</CODE> 聚合的每個
<CODE>Item</CODE> 對象上的 <CODE>toXml()</CODE> 得到的。</P>
<P>一旦所有的 JavaBean 都實現了 <CODE>toXml()</CODE> 方法,那么把任意對象圖序列化成 XML
文檔并返回給 Ajax 客戶機就簡單了,如清單 2 所示。</P><BR><BR><A name=code2><B>清單 2. 從
JDOM 元素生成 XML 響應</B></A><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=code-outline><PRE class=displaycode>
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws java.io.IOException, ServletException {
String custId = req.getParameter("username");
Customer customer = getCustomer(custId);
Element responseElem = customer.toXml();
Document responseDoc = new Document(responseElem);
res.setContentType("application/xml");
new XMLOutputter().output(responseDoc,res.getWriter());
}
</PRE></TD></TR></TBODY></TABLE><BR>
<P>JDOM 再次把工作變得非常簡單。只需要在對象圖返回的 XML 元素外面包裝一個
<CODE>Document</CODE>,然后用 <CODE>XMLOutputter</CODE> 把文檔寫入 servlet
響應即可。清單 3 顯示了用這種方式生成的 XML 示例,用 JDOM
<CODE>Format.getPrettyFormat()</CODE> 對 <CODE>XMLOutputter</CODE>
進行初始化,格式化得非常好。在這個示例中,顧客只做了一個訂單,包含兩個商品。</P><BR><BR><A
name=code3><B>清單 3. 代表顧客的 XML 文檔</B></A><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=code-outline><PRE class=displaycode>
<?xml version="1.0" encoding="UTF-8"?>
<customer username="jimmy66">
<realname>James Hyrax</realname>
<orders>
<order id="o-11123" cost="$349.98">
<date>08-26-2005</date>
<items>
<item id="i-55768">
<name>Oolong 512MB CF Card</name>
<description>512 Megabyte Type 1 CompactFlash card.
Manufactured by Oolong Industries</description>
<price>$49.99</price>
</item>
<item id="i-74491">
<name>Fujak Superpix72 Camera</name>
<description>7.2 Megapixel digital camera featuring six
shooting modes and 3x optical zoom. Silver.</description>
<price>$299.99</price>
</item>
</items>
</order>
</orders>
</customer>
</PRE></TD></TR></TBODY></TABLE><BR>
<P><A name=N1011E><SPAN class=smalltitle>自行序列化的不足</SPAN></A></P>
<P>有趣的是,清單 3 中的代碼展示了讓 JavaBean 把自己序列化為 XML
的一個主要不足。假設要用這個文檔表示顧客的訂單歷史視圖。在這種情況下,不太可能要顯示每個歷史訂單中每個商品的完整說明,或者告訴顧客他或她自己的姓名。但是如果應用程序有一個
<CODE>ProductSearch</CODE> 類,它就是以 <CODE>Item</CODE> bean
列表的形式返回搜索結果,那么在 <CODE>Item</CODE> 的 XML
表示中包含說明可能會有幫助。而且,<CODE>Item</CODE>
類上代表當前庫存水平的額外字段,在產品搜索視圖中可能就是需要顯示的有用信息。但是,不管當前的庫存水平是否與當前情況相關(比如對顧客的訂單歷史來說),這個字段都會從包含
<CODE>Item</CODE> 的任何對象圖中序列化出來。</P>
<P>從設計的角度來看,這是數據模型與視圖生成耦合的經典問題。每個 bean 只能用一種途徑序列化自己,一成不變的方式意味著 Ajax
交互最終要交換它們不需要交換的數據,因此造成客戶端代碼要從文檔中找到需要的信息更加困難,而且也會增加帶寬消耗和客戶端的 XML
解析時間。這種耦合的另一個后果就是 XML 的語法不能脫離 Java 類獨立變化。例如,對顧客文檔的方案做修改,可能會影響多個 Java
類,造成它們也不得不做修改和重新編譯。</P>
<P>我稍后會解決這些問題,但是首先來看一個對自行序列化方式的可伸縮性問題的解決方案:XML 綁定框架。</P><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><IMG height=1 alt=""
src="面向 Java 開發人員的 Ajax Ajax 的 Java 對象序列化.files/blue_rule.gif"
width="100%"><BR><IMG height=6 alt=""
src="面向 Java 開發人員的 Ajax Ajax 的 Java 對象序列化.files/c.gif" width=8
border=0></TD></TR></TBODY></TABLE>
<TABLE class=no-print cellSpacing=0 cellPadding=0 align=right>
<TBODY>
<TR align=right>
<TD><IMG height=4 alt=""
src="面向 Java 開發人員的 Ajax Ajax 的 Java 對象序列化.files/c.gif"
width="100%"><BR>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt=""
src="面向 Java 開發人員的 Ajax Ajax 的 Java 對象序列化.files/u_bold.gif"
width=16 border=0><BR></TD>
<TD vAlign=top align=right><A class=fbox
href="http://www.ibm.com/developerworks/cn/java/j-ajax2/#main"><B>回頁首</B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<P><A name=N10141><SPAN class=atitle>XML 綁定框架</SPAN></A></P>
<P>近些年來,已經開發了多個 Java API 來簡化 XML 文檔到 Java 對象圖的綁定過程。多數都提供了 XML
編排和拆解;也就是說,它們可以在 Java 對象圖和 XML 之間執行雙向會話。這些框架封裝了 XML
處理的全部工作,這意味著應用程序代碼只需要處理普通的 Java
類。它們還希望提供有用的輔助功能,例如文檔驗證。籠統來說,這些框架采用了兩種不同的方式:代碼生成和對象到 XML
映射。我將分別解釋這兩種方式。</P>
<P><A name=N1014A><SPAN class=smalltitle>代碼生成方式</SPAN></A></P>
<P>使用代碼生成的框架包括 XMLBeans、JAXB、Zeus 和 JBind。Castor
也能使用這項技術。這類框架的起點是描述文檔數據類型的 XML 方案。使用框架提供的工具,就可以生成代表這些方案定義類型的 Java
類。最后,用這些生成的類編寫應用程序,表示自己的模型數據,并通過框架提供的一些輔助機制把數據序列化成 XML。</P>
<P>如果應用程序要使用大型 XML 語法,那么代碼生成方式是個很好的方法。在數十個類上編寫定制 XML
序列化代碼的可伸縮性問題由此消除。另一方面,也不再需要定義自己的 JavaBean。框架生成的 Java 類通常非常符合 XML
的結構,所以對它們進行編碼很難。而且,生成的類變成啞數據容器,因為一般不能向它們添加行為。一般來說,在應用程序代碼中要做些妥協,才能很好地處理方案生成的類型。另一個缺陷是如果修改方案,會造成生成的類也要修改,所以也就會對圍繞它們編寫的代碼帶來相應的影響。</P>
<P>這種類型的 XML 綁定框架在數據拆解時最有用(例如,使用 XML 文檔并把它們轉化成 Java
對象)。除非擁有大型數據模型而且有可能從生成的類中獲益,否則基于代碼生成的框架對于 Ajax 應用程序來說可能有很大的殺傷力。</P>
<P><A name=N10159><SPAN class=smalltitle>映射方式</SPAN></A></P>
<P>采用映射方式的框架包括 Castor 和 Apache Commons
Betwixt。映射通常是比代碼生成更靈活和更輕量的解決方案。首先,可以像通常一樣編寫
JavaBean,包括任何行為以及任何自己喜歡的方便的方法。然后,在運行時,調用框架中基于內省的編排器,并根據對象成員的類型、名稱和值生成
XML 文檔。通過定義類的映射文件,可以覆蓋默認的綁定策略,并就類在 XML 中的表示方式對編排器提出建議。</P>
<P>這種方法是在可伸縮性與靈活性之間的良好折中。可以按照自己喜歡的方式編寫 Java 類,編排器負責處理
XML。雖然映射定義文件編寫起來簡單,可伸縮性也足夠好,但是映射規則最多只能改變標準的綁定行為,而且在對象結構和它們的 XML
表示之間總要殘留一些耦合。最終,可能不得不在 Java 表示或 XML 格式之間任選一個做些折中,才能讓映射方法起作用。</P>
<P><A name=N10165><SPAN class=smalltitle>數據綁定總結</SPAN></A></P>
<P>Dennis Sosnoski 就 XML 數據綁定 API
的主題,在代碼生成和代碼映射兩個方面寫了深入的文章。如果想進一步研究這個領域,我推薦他在 Castor
和代碼生成框架方面的精彩文章(請參閱 <A
href="http://www.ibm.com/developerworks/cn/java/j-ajax2/#resources">參考資料</A>
中的鏈接)。</P>
<P>總之,代碼生成方式損失了過多的靈活性和方便性,對于典型的 Ajax
應用程序用處不大。另一方面,基于映射的框架可能工作得很好,但是要恰到好處地調整它們的映射策略,以便從對象生成需要的 XML。</P>
<P>所有的 XML 綁定 API 都具有手工序列化技術的一個主要不足:模型和視圖的耦合。被限制為一個類型一個 XML
表示,就意味著在網絡上總要有冗余數據傳輸。更嚴重的問題是,在情況要求客戶端代碼使用專門視圖時,客戶端代碼卻無法得到它,所以可能要費力地處理給定對象圖的一成不變的視圖。</P>
<P>在傳統的 Web 應用程序開發中,采用頁面模板系統把視圖生成與控制器邏輯和模型數據干凈地分離。這種方法在 Ajax
場景中也會有幫助。</P><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><IMG height=1 alt=""
src="面向 Java 開發人員的 Ajax Ajax 的 Java 對象序列化.files/blue_rule.gif"
width="100%"><BR><IMG height=6 alt=""
src="面向 Java 開發人員的 Ajax Ajax 的 Java 對象序列化.files/c.gif" width=8
border=0></TD></TR></TBODY></TABLE>
<TABLE class=no-print cellSpacing=0 cellPadding=0 align=right>
<TBODY>
<TR align=right>
<TD><IMG height=4 alt=""
src="面向 Java 開發人員的 Ajax Ajax 的 Java 對象序列化.files/c.gif"
width="100%"><BR>
<TABLE cellSpacing=0 cellPadding=0 border=0>
<TBODY>
<TR>
<TD vAlign=center><IMG height=16 alt=""
src="面向 Java 開發人員的 Ajax Ajax 的 Java 對象序列化.files/u_bold.gif"
width=16 border=0><BR></TD>
<TD vAlign=top align=right><A class=fbox
href="http://www.ibm.com/developerworks/cn/java/j-ajax2/#main"><B>回頁首</B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<P><A name=N1017B><SPAN class=atitle>頁面模板系統</SPAN></A></P>
<P>任何通用目的的頁面模板技術都可以用來生成 XML,從而使 Ajax 應用程序根據自己的數據模型生成任何 XML
響應文檔。額外收獲是:模板可以用簡單的、表現力強的標記語言編寫,而不是用一行行的 Java 代碼編寫。清單 5 是一個 JSP
頁面,采用了 <CODE>Customer</CODE> bean 并表示出定制的 XML
視圖,適合客戶端代碼生成訂單歷史組件。</P><BR><BR><A name=code4><B>清單 4. 生成訂單歷史文檔的
JSP</B></A><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=code-outline><PRE class=displaycode>
<?xml version="1.0"?>
<%@ page contentType="application/xml" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:set var="cust" value="${requestScope.customer}"/>
<orderhistory username="${cust.username}">
<c:forEach var="order" items="${cust.orders}">
<order id="${order.id}" cost="${order.formattedCost}">
<date>${order.date}</date>
<items>
<c:forEach var="item" items="${order.items}">
<item id="${item.id}">
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -