??xml version="1.0" encoding="utf-8" standalone="yes"?>一区二区三区在线看,免费国产一区,欧美日韩伦理一区二区http://www.aygfsteel.com/sunbaoyu/archive/2005/10/30/17436.htmlblueskyblueskySun, 30 Oct 2005 07:36:00 GMThttp://www.aygfsteel.com/sunbaoyu/archive/2005/10/30/17436.htmlhttp://www.aygfsteel.com/sunbaoyu/comments/17436.htmlhttp://www.aygfsteel.com/sunbaoyu/archive/2005/10/30/17436.html#Feedback0http://www.aygfsteel.com/sunbaoyu/comments/commentRss/17436.htmlhttp://www.aygfsteel.com/sunbaoyu/services/trackbacks/17436.html?Web 应用E序开发中Q页面重载@环是最大的一个用障,对于 Java? 开发h员来说也是一个严ȝ挑战。在q个pd中,作?Philip McCarthy 介绍了一U创建动态应用程序体验的开创性方式。AjaxQ异? JavaScript ?XMLQ是一U编E技术,它允ؓ(f)Z Java ?Web 应用E序?Java 技术、XML ? JavaScript l合hQ从而打破页面重载的范式?/blockquote>

AjaxQ即异步 JavaScript ? XMLQ是一U?Web 应用E序开发的手段Q它采用客户端脚本与 Web 服务器交换数据。所以,不必采用?x)中断交互的完整面hQ就可以动态地更新 Web 面。?AjaxQ可以创建更加丰富、更加动态的 Web 应用E序用户界面Q其x性与可用性甚臌够接q本机桌面应用程序?/p>

Ajax 不是一Ҏ(gu)术,而更像是一?模式 —? 一U识别和描述有用的设计技术的方式。Ajax 是新颖的Q因多开发h员才刚刚开始知道它Q但是所有实?Ajax 应用E序的组仉已经存在若干q了。它目前受到重视是因为在 2004 ?2005 q出C一些基?Ajax 技术的非常的动?Web UIQ最著名的就?Google ?GMail ?Maps 应用E序Q以?qing)照片共享站? Flickr。这些用L(fng)面具有够的开创性,有些开发h员称之ؓ(f)“Web 2.0”,因此?Ajax 应用E序的兴飞速上升?/p>

在这? pd中,提供?Ajax 开发应用程序需要的全部工具 。在W一文章中Q将解释 Ajax 背后的概念,演示为基?Java ?Web 应用E序创徏 Ajax 界面的基本步骤。我用代码示例演C Ajax 应用E序如此动态的服务器端 Java 代码和客L(fng) JavaScript。最后,指?Ajax 方式的一些不I以及(qing)在创?Ajax 应用E序时应当考虑的一些更q的可用性和讉K性问题?/p>

更好的购物R

? 以用 Ajax 增强传统?Web 应用E序Q通过消除面装入从而简化交互。ؓ(f)了演C一点,采用一个简单的购物车示例,在向里面d目Ӟ它会(x)动态更新。这Ҏ(gu)术如果整合到在线? 店,那么用户可以持箋地浏览和向购物R中添加项目,而不必在每次点击之后都等候完整的面更新。虽然这文章中的有些代码特定于购物车示例,但是演示的技 术可以应用于M Ajax 应用E序。清?1 昄了购物RCZ使用的有?HTML 代码Q整文章中都会(x)使用q个 HTML?/p>
清单1. 购物车示例的有关片断

<!-- Table of products from store's catalog, one row per item -->
<th>Name</th> <th>Description</th> <th>Price</th> <th></th>
...
<tr>
<!-- Item details -->
<td>Hat</td> <td>Stylish bowler hat</td> <td>$19.99</td>
<td>
<!-- Click button to add item to cart via Ajax request -->
<button onclick="addToCart('hat001')">Add to Cart</button>
</td>
</tr>
...

<!-- Representation of shopping cart, updated asynchronously -->
<ul id="cart-contents">

<!-- List-items will be added here for each item in the cart -->

</ul>

<!-- Total cost of items in cart displayed inside span element -->
Total cost: <span id="total">$0.00</span>





Ajax 往q过E?/span>

Ajax 交互开始于叫作 XMLHttpRequest ?JavaScript 对象。顾名思义Q它允许客户端脚本执?HTTP hQƈ解析 XML 服务器响应。Ajax 往q过E的W一步是创徏 XMLHttpRequest 的实例。在 XMLHttpRequest 对象上设|请求用的 HTTP Ҏ(gu)Q?code>GET ?POSTQ以?qing)目?URL?/p>

现在Q?zhn)q记?Ajax 的第一?a 是代?异步QasynchronousQ?/i> 吗?在发?HTTP hӞ不想让浏览器挂着{候服务器响应。相反,(zhn)想让浏览器l箋对用户与面的交互进行响应,q在服务器响应到达时再进行处理。ؓ(f)了实现这个要求,可以?XMLHttpRequest 上注册一个回调函敎ͼ然后异步地分z?XMLHttpRequest。然后控制就?x)返回浏览器Q当服务器响应到达时Q会(x)调用回调函数?/p>

?Java Web 服务器上Q请求同其他 HttpServletRequest 一样到达。在解析了请求参C后,servlet 调用必要的应用程序逻辑Q把响应序列化成 XMLQƈ?XML 写入 HttpServletResponse?/p>

回到客户端时Q现在调用注册在 XMLHttpRequest 上的回调函数Q处理服务器q回?XML 文档。最后,Ҏ(gu)服务器返回的数据Q用 JavaScript 操纵面?HTML DOMQ把用户界面更新。图 1 ?Ajax 往q过E的序图?/p>
?1. Ajax 往q过E?/b>
 Ajax 往q过E的序? src=

现在(zhn)对 Ajax 往q过E有了一个高层面的认识。下面我放大其中的每一步骤Q进行更详细的观察。如果过E中q了路,请回头看?1 —?׃ Ajax 方式的异步性质Q所以顺序ƈ非十分简单?/p>



分派 XMLHttpRequest

我将?Ajax 序列的v点开始:(x)创徏和分z来自浏览器?XMLHttpRequest。不q的是,不同的浏览器创徏 XMLHttpRequest 的方法各不相同。清?2 ?JavaScript 函数消除了这些依赖于览器的技巧,它可以检当前浏览器要用的正确方式Qƈq回一个可以用的 XMLHttpRequest。最好是把它当作辅助代码Q只要把它拷贝到 JavaScript 库,q在需?XMLHttpRequest 的时候用它?yu)可以了?/p>
清单 2. 创徏跨浏览器?XMLHttpRequest

/*
* Returns a new XMLHttpRequest object, or false if this browser
* doesn't support it
*/
function newXMLHttpRequest() {

var xmlreq = false;

if (window.XMLHttpRequest) {

// Create XMLHttpRequest object in non-Microsoft browsers
xmlreq = new XMLHttpRequest();

} else if (window.ActiveXObject) {

// Create XMLHttpRequest via MS ActiveX
try {
// Try to create XMLHttpRequest in later versions
// of Internet Explorer

xmlreq = new ActiveXObject("Msxml2.XMLHTTP");

} catch (e1) {

// Failed to create required ActiveXObject

try {
// Try version supported by older versions
// of Internet Explorer

xmlreq = new ActiveXObject("Microsoft.XMLHTTP");

} catch (e2) {

// Unable to create an XMLHttpRequest with ActiveX
}
}
}

return xmlreq;
}

E后讨论处理那些不支持 XMLHttpRequest 的浏览器的技术。目前,CZ假设清单 2 ?newXMLHttpRequest 函数总能q回 XMLHttpRequest 实例?/p>

q回CZ的购物R场景Q想要当用户在目录项目上点击 Add to Cart 时启?Ajax 交互。名?addToCart() ?onclick 处理函数负责通过 Ajax 调用来更新购物R的状态(请参?清单 1Q。正如清?3 所C,addToCart() 需要做的第一件事是通过调用清单 2 ?newXMLHttpRequest() 函数得到 XMLHttpRequest 对象。接下来Q它注册一个回调函敎ͼ用来接收服务器响应(我稍后再详细解释q一步;请参?清单 6Q?/p>

因ؓ(f)h?x)修?gu)务器上的状态,所以将?HTTP POST 做这个工作。通过 POST 发送数据要求三个步骤。第一Q需要打开与要通信的服务器资源?POST q接 —?在这个示例中Q服务器资源是一个映到 URL cart.do ?servlet。然后,我在 XMLHttpRequest 上设|一个头Q指明请求的内容是表?~码的数据。最后,用表单编码的数据作ؓ(f)h体发送请求?/p>

清单 3 把这些步骤放在了一赗?/p>
清单 3. 分派 Add to Cart XMLHttpRequest

/*
* Adds an item, identified by its product code, to the shopping cart
* itemCode - product code of the item to add.
*/
function addToCart(itemCode) {

// Obtain an XMLHttpRequest instance
var req = newXMLHttpRequest();

// Set the handler function to receive callback notifications
// from the request object
var handlerFunction = getReadyStateHandler(req, updateCart);
req.onreadystatechange = handlerFunction;

// Open an HTTP POST connection to the shopping cart servlet.
// Third parameter specifies request is asynchronous.
req.open("POST", "cart.do", true);

// Specify that the body of the request contains form data
req.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");

// Send form encoded data stating that I want to add the
// specified item to the cart.
req.send("action=add&item="+itemCode);
}

q就是徏?Ajax 往q过E的W一部分Q即创徏和分z来自客h?HTTP h。接下来是用来处理请求的 Java servlet 代码?/p>



servlet h处理

?servlet 处理 XMLHttpRequestQ与处理普通的览?HTTP h一栗可以用 HttpServletRequest.getParameter() 得到?POST h体中发送的表单~码数据。Ajax h被放q与来自应用E序的常?Web h一L(fng) HttpSession 中。对于示例购物R场景来说Q这很有用,因ؓ(f)q可以把购物车状态封装在 JavaBean 中,q在h之间在会(x)话中l持q个状态?/p>

清单 4 是处?Ajax h、更新购物R的简?servlet 的一部分?code>Cart bean 是从用户?x)话中获得的QƈҎ(gu)h参数更新它的状态。然?Cart 被序列化?XMLQXML 又被写入 ServletResponse。重要的是把响应的内容类型设|ؓ(f) application/xmlQ否?XMLHttpRequest 不会(x)把响应内容解析成 XML DOM?/p>
清单 4. 处理 Ajax h?servlet 代码

public void doPost(HttpServletRequest req, HttpServletResponse res)
throws java.io.IOException {

Cart cart = getCartFromSession(req);

String action = req.getParameter("action");
String item = req.getParameter("item");

if ((action != null)&&(item != null)) {

// Add or remove items from the Cart
if ("add".equals(action)) {
cart.addItem(item);

} else if ("remove".equals(action)) {
cart.removeItems(item);

}
}

// Serialize the Cart's state to XML
String cartXml = cart.toXml();

// Write XML to response.
res.setContentType("application/xml");
res.getWriter().write(cartXml);
}

清单 5 昄?Cart.toXml() Ҏ(gu)生成的示?XML。它很简单。请注意 cart 元素?generated 属性,它是 System.currentTimeMillis() 生成的一个时间戳?/p>
清单 5. Cart 对象的XML 序列化示?

<?xml version="1.0"?>
<cart generated="1123969988414" total="$171.95">
<item code="hat001">
<name>Hat</name>
<quantity>2</quantity>
</item>
<item code="cha001">
<name>Chair</name>
<quantity>1</quantity>
</item>
<item code="dog001">
<name>Dog</name>
<quantity>1</quantity>
</item>
</cart>

如果查看应用E序源代码(可以?下蝲 一节得刎ͼ中的 Cart.javaQ可以看到生?XML 的方式只是把字符串添加在一赗虽然对q个CZ来说_了,但是对于?Java 代码生成 XML 来说则是最差的方式。这个系列的下一期中介绍一些更好的方式?/p>

现在(zhn)已l知道了 CartServlet 响应 XMLHttpRequest 的方式。下一件事是q回客户端,查看如何?XML 响应更新面状态?/p>



?JavaScript q行响应处理

XMLHttpRequest ?readyState 属性是一个数|它指求生命周期的状态。它?0Q代表“未初始化”)变化?4Q代表“完成”)。每?readyState 变化Ӟreadystatechange 事gp发,?onreadystatechange 属性指定的事g处理函数p调用?/p>

?清单 3 中已l看C如何调用 getReadyStateHandler() 函数创徏事g处理函数。然后把q个事g处理函数分配l?onreadystatechange 属性?code>getReadyStateHandler() 利用了这样一个事实:(x)函数?JavaScript 中的一U对象。这意味着函数可以是其他函数的参数Q也可以创徏和返回其他函数?code>getReadyStateHandler() 的工作是q回一个函敎ͼ?XMLHttpRequest 是否已经完成Qƈ?XML 响应传递给调用者指定的事g处理函数。清?6 ?getReadyStateHandler() 的代码?/p>
清单 6. getReadyStateHandler() 函数

/*
* Returns a function that waits for the specified XMLHttpRequest
* to complete, then passes its XML response to the given handler function.
* req - The XMLHttpRequest whose state is changing
* responseXmlHandler - Function to pass the XML response to
*/
function getReadyStateHandler(req, responseXmlHandler) {

// Return an anonymous function that listens to the
// XMLHttpRequest instance
return function () {

// If the request's status is "complete"
if (req.readyState == 4) {

// Check that a successful server response was received
if (req.status == 200) {

// Pass the XML payload of the response to the
// handler function
responseXmlHandler(req.responseXML);

} else {

// An HTTP problem has occurred
alert("HTTP error: "+req.status);
}
}
}
}

HTTP 状态码

在清?6 中,?XMLHttpRequest ? status 属性以查看h是否成功完成?code>status 包含服务器响应的 HTTP 状态码。在执行单的 GET ?POST hӞ可以假设M大于 200 QOKQ的码都是错误。如果服务器发送重定向响应Q例?301 ?302Q,览器会(x)透明地进行重定向q从新的位置获取资源Q?code>XMLHttpRequest 看不到重定向状态码。而且Q浏览器?x)自动添?Cache-Control: no-cache 头到所?XMLHttpRequestQ这样客户代码永q也不用处理 304Q未l修改)服务器响应?/p>

关于 getReadyStateHandler()

getReadyStateHandler() 是段相对复杂的代码,特别是如果?zhn)不?fn)惯阅?JavaScript 的话。但是通过把这个函数放?JavaScript 库中Q就可以处理 Ajax 服务器响应,而不必处?XMLHttpRequest 的内部细节。重要的是要理解如何在自q代码中?getReadyStateHandler()?/p>

?清单 3 中看C getReadyStateHandler() 像这栯调用Q?code>handlerFunction = getReadyStateHandler(req, updateCart)。在q个CZ中,getReadyStateHandler() q回的函数将查在 req 变量中的 XMLHttpRequest 是否已经完成Q然后用响应?XML 调用名ؓ(f) updateCart 的函数?/p>

提取购物车数?/span>

清单 7 ?updateCart() 本n的代码。函数用 DOM 调用查购物R?XML 文档Q然后更?Web 面Q请参阅 清单 1Q,反映新的购物车内宏V这里的重点是用来从 XML DOM 提取数据的调用?code>cart 元素?generated 属性是?Cart 序列化ؓ(f) XML 时生成的一个时间戳Q检查它可以保证新的购物车数据不?x)被旧的数据覆盖。Ajax h天生是异步的Q所以这个检查可以处理服务器响应未按ơ序到达的情c?/p>
清单 7. 更新面Q反映购物R?XML 文档

function updateCart(cartXML) {

// Get the root "cart" element from the document
var cart = cartXML.getElementsByTagName("cart")[0];

// Check that a more recent cart document hasn't been processed
// already
var generated = cart.getAttribute("generated");
if (generated > lastCartUpdate) {
lastCartUpdate = generated;

// Clear the HTML list used to display the cart contents
var contents = document.getElementById("cart-contents");
contents.innerHTML = "";

// Loop over the items in the cart
var items = cart.getElementsByTagName("item");
for (var I = 0 ; I < items.length ; I++) {

var item = items[I];

// Extract the text nodes from the name and quantity elements
var name = item.getElementsByTagName("name")[0]
.firstChild.nodeValue;

var quantity = item.getElementsByTagName("quantity")[0]
.firstChild.nodeValue;

// Create and add a list item HTML element for this cart item
var li = document.createElement("li");
li.appendChild(document.createTextNode(name+" x "+quantity));
contents.appendChild(li);
}
}

// Update the cart's total using the value from the cart document
document.getElementById("total").innerHTML =
cart.getAttribute("total");
}

到此Q整?Ajax 往q过E完成了Q但是?zhn)可能惌?Web 应用E序q行一下查看实际效果(请参?下蝲 一节)。这个示例非常简单,有很多需要改q之处。例如,我包含了从购物R中清除项目的服务器端代码Q但是无法从 UI 讉K它。作Z个好的练?fn),误着在应用程序现有的 JavaScript 代码之上构徏够实现这个功能的代码?/p>



使用 Ajax 的挑?/span>

像M技术一P使用 Ajax 也有许多出错的可能性。我目前在这里讨论的问题q缺乏容易的解决Ҏ(gu)Q但是会(x)随着 Ajax 的成熟而改q。随着开发h员社区增加开?Ajax 应用E序的经验,会(x)记录下最?jng)_践和指南?/p>

XMLHttpRequest 的可用?/span>

Ajax 开发h员面临的一个最大问题是Q在没有 XMLHttpRequest 可用时该如何响应Q虽然主要的C览器都支持 XMLHttpRequestQ但仍然有少数用L(fng)览器不支持Q或者浏览器的安全设|阻止?XMLHttpRequest。如果开发的 Web 应用E序要部|在企业内部|,那么可能拥有指定支持哪种览器的权力Q从而可以认?XMLHttpRequest 总能使用。但是,如果要部|在公共 Web 上,那么必d心,如果假设 XMLHttpRequest 可用Q那么就可能?x)阻止那些用旧的浏览器、残疾h专用览器和手持讑֤上的轻量U浏览器的用户用?zhn)的应用程序?/p>

所以,(zhn)应当努力让应用E序“^E降U”,在没?XMLHttpRequest 支持的浏览器中也能够工作。在购物车的CZ中,把应用程序降U的最好方式可能是?Add to Cart 按钮执行一个常规的表单提交Q刷新页面来反映购物车更新后的状态。Ajax 的行为应当在面装入的时候就通过 JavaScript d到页面,只有?XMLHttpRequest 可用时才?JavaScript 事g处理函数附加到每?Add to Cart 按钮。另一U方式是在用L(fng)录时?XMLHttpRequest 是否可用Q然后相应地提供应用E序?Ajax 版本或基于表单的普通版本?/p>

可用性考虑

关于 Ajax 应用E序的某些可用性问题比较普遍。例如,让用L(fng)道他们的输入已经注册了可能是重要的,因ؓ(f)沙漏光标?spinning 览器的常用反馈机制“throbber”对 XMLHttpRequest 不适用。一U技术是用“Now updating...”类型的信息替换 Submit 按钮Q这L(fng)户在{候响应期间就不会(x)反复单击按钮了?/p>

? 一个问题是Q用户可能没有注意到他们正在查看的页面的某一部分已经更新了。可以用不同的可视技术,把用L(fng)眼球带到面的更新区域,从而缓解这个问题? ?Ajax 更新面造成的其他问题还包括Q“破坏了”浏览器的后退按钮Q地址栏中?URL 也无法反映页面的整个状态,妨碍了设|书{。请参阅 参考资?/a> 一节,获得专门解决 Ajax 应用E序可用性问题的文章?/p>

服务器负?/span>

? Ajax 实现代替普通的Z表单?UIQ会(x)大大提高Ҏ(gu)务器发出的请求数量。例如,一个普通的 Google Web 搜烦Ҏ(gu)务器只有一个请求,是在用户提交搜烦表单时出现的。?Google Suggest 试图自动完成搜烦术语Q它要在用户输入时向服务器发送多个请求。在开?Ajax 应用E序Ӟ要注意将要发送给服务器的h数量以及(qing)由此造成的服务器负荷。降低服务器负蝲的办法是Q在客户Z对请求进行缓冲ƈ且缓存服务器响应Q如果可 能的话)。还应该试?Ajax Web 应用E序设计为在客户Z执行可能多的逻辑Q而不必联l服务器?/p>

处理异步

非常重要的是Q要理解无法保证 XMLHttpRequest ?x)按照分z֮们的序完成。实际上Q应当假讑֮们不?x)按序完成Qƈ且在设计应用E序时把q一点记在心上。在购物车的CZ中,使用最后更新的旉x保新的购物车数据不?x)被旧的数据覆盖Q请参阅 清单 7Q。这个非常基本的方式可以用于购物车场景,但是可能不适合其他场景。所以在设计时请考虑如何处理异步的服务器响应?/p>

bluesky 2005-10-30 15:36 发表评论
]]>
Ajax ?Java 对象序列?转脓(chung))http://www.aygfsteel.com/sunbaoyu/archive/2005/10/30/17435.htmlblueskyblueskySun, 30 Oct 2005 07:32:00 GMThttp://www.aygfsteel.com/sunbaoyu/archive/2005/10/30/17435.htmlhttp://www.aygfsteel.com/sunbaoyu/comments/17435.htmlhttp://www.aygfsteel.com/sunbaoyu/archive/2005/10/30/17435.html#Feedback0http://www.aygfsteel.com/sunbaoyu/comments/commentRss/17435.htmlhttp://www.aygfsteel.com/sunbaoyu/services/trackbacks/17435.html如果(zhn)正在用异?JavaScript ?XMLQAjaxQ进?Java?Web 开发,那么(zhn)最兛_的问题可能就是把数据从服务器传递给客户机。在 面向 Java 开发h员的 Ajax pd的第二篇文章中,Philip McCarthy 介绍?Java 对象序列化的五种方式Qƈ提供了选择最适合应用E序的数据格式和技术所需要的全部信息?/blockquote>

在这个系列的 W一文?/a> 中,我介l了 Ajax 的构造块Q?/p>

q一ơ,l讨?Ajax 开发的基础知识Q但是将侧重于许?Java Web 开发h员最兛_的问题:(x)为客h生成数据?/p>

? ?Java 开发h员已l把模型-视图-控制器(MVCQ模式应用在他们?Web 应用E序上。在传统?Web 应用E序中,视图lg?JSP 或者其他表C技术(例如 Velocity 模板Q构成。这些表C组件动态地生成全新?HTML 面Q替代用户以前正在查看的面Q从而更新用L(fng)面。但是,?Java Web 应用E序使用 Ajax UI 的情况下Q基于从 XMLHttpRequest 的响应接收到的数据,JavaScript 客户端代码对于更新用L(fng)到的内容负有最l责仅R从服务器的角度来看Q视图成为它响应客户求而发送的数据表示?/p>

q? 文章侧重于可以用来生成 Java 对象以数据ؓ(f)中心的视囄技术。我演C可以把 JavaBeans 变成 XML 文档的各U方法,q且讨论每种Ҏ(gu)的优劣。?zhn)看Cؓ(f)什?XML q不L最好的途径Q对于简单的 Ajax h来说Q传输纯文本更好。最后,我将介绍 JavaScript 对象标注QJSONQ。JSON 允许数据以序列化?JavaScript 对象囄形式传输Q在客户端代码中处理序列化的 JavaScript 对象图极为容易?/p>

关于CZ

    使用一个示例应用程序和几个用例来演C里讨论的技术特性和技术。图 1 昄的极为简单的数据模型可以表示CZ用例。这个模型代表在U商店中的顾客帐戗顾客拥有以前订单的集合Q每个订单包含几个商品?/p>
?1. 单的对象模型
代表֮帐户的对象模? src=

虽然 XMLHttpRequest 对于发送数据用的格式没有做Q何限Ӟ但是对于多数目的来说Q只发送传l的表单数据是适合的,所以我的讨论集中在服务器的响应上。响应也可以有基于文本的格式Q但是正如它的名字表C的Q?code>XMLHttpRequest h内置的处?XML 响应数据的能力。这?XML 成ؓ(f) Ajax 响应的默认选择Q所以我们从 XML 格式开始讨论?/p>



?Java cM?XML

? Ajax 响应作ؓ(f) XML 来传递有许多原因Q每个支?Ajax 的浏览器都有D XML 文档的方法,也有许多服务器端技术可以处?XML 数据。通过制定一个方案,描述要交换的文档cdQ在 Ajax 客户端和服务器端之间很容易定义合U,而且如果服务器端架构采用面向服务的方式,那么使用 XML 也可以允?dng)R Ajax 客户Z用?zhn)提供的数据?/p>

    我们?Java 对象产生 XML 数据的三U方法,q讨论每U方法的优劣?/p>



自行q行序列?/span>

首先Q可以从对象图以~程的方式生?XML。这U方式可以简单到只是在每?JavaBean cM实现 toXml() Ҏ(gu)卛_。然后就可以选择合适的 XML APIQ让每个 bean 提供表示自己状态的元素Qƈ递归地对自己的成员调用对象图。显Ӟq种方式无法扩展到大量的c,因ؓ(f)每个c都需要专门编写自q XML 生成代码。从好的斚w来看Q这是一个实现v来简单的方式Q没有额外的配置支出或者更复杂的构E支出,M JavaBean N可以只用几个调用变?XML 文档?/p>

     前一文?/a> 的示例代码中Q把 XML 标记字符串连接在一P实现?toXml() Ҏ(gu)。上ơ我提到过Q这是个p糕的方法,因ؓ(f)它把保标记配对、实体编码等工作的负担放在每?toXml() Ҏ(gu)的代码中。在 Java q_上有几个 XML API 可以替?zhn)做这些工作,q样(zhn)就可以把精力集中在 XML 的内容上。清?1 ?JDOM API 实现了在U商店示例中表示订单的类中的 toXml()Q请参阅 ?1Q?/p>
清单 1. Order cȝ toXml() ?JDOM 实现

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 iter =
items.iterator() ; iter.hasNext() ; ) {
elItems.addContent(iter.next().toXml());
}
elOrder.addContent(elItems);

return elOrder;
}

在这里可以看到用 JDOM 创徏元素、用属性和d元素内容有多么简单。递归地调用复?JavaBean ?toXml() Ҏ(gu)是ؓ(f)了取得它们子囄 Element 表示。例如,items 元素的内Ҏ(gu)通过调用 Order 聚合的每?Item 对象上的 toXml() 得到的?/p>

一旦所有的 JavaBean 都实C toXml() Ҏ(gu)Q那么把L对象囑ֺ列化?XML 文档q返回给 Ajax 客户机就单了Q如清单 2 所C?/p>
清单 2. ?JDOM 元素生成 XML 响应

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());
}

JDOM 再次把工作变得非常简单。只需要在对象图返回的 XML 元素外面包装一?DocumentQ然后用 XMLOutputter 把文档写?servlet 响应卛_。清?3 昄了用q种方式生成?XML CZQ用 JDOM Format.getPrettyFormat() ?XMLOutputter q行初始化,格式化得非常好。在q个CZ中,֮只做了一个订单,包含两个商品?/p>
清单 3. 代表֮?XML 文档



James Hyrax


08-26-2005


Oolong 512MB CF Card
512 Megabyte Type 1 CompactFlash card.
Manufactured by Oolong Industries

$49.99


Fujak Superpix72 Camera
7.2 Megapixel digital camera featuring six
shooting modes and 3x optical zoom. Silver.

$299.99






自行序列化的不

有趣的是Q清?3 中的代码展示了让 JavaBean 把自己序列化?XML 的一个主要不뀂假设要用这个文档表C顾客的订单历史视图。在q种情况下,不太可能要显C每个历史订单中每个商品的完整说明,或者告诉顾客他或她自己的姓名。但是如果应用程序有一?ProductSearch c,它就是以 Item bean 列表的Ş式返回搜索结果,那么?Item ?XML 表示中包含说明可能会(x)有帮助。而且Q?code>Item cM代表当前库存水^的额外字D,在品搜索视图中可能是需要显C的有用信息。但是,不管当前的库存水qx否与当前情况相关Q比如对֮的订单历史来_(d)Q这个字D都?x)从包?Item 的Q何对象图中序列化出来?/p>

? 设计的角度来看,q是数据模型与视囄成耦合的经兔R题。每?bean 只能用一U途径序列化自己,一成不变的方式意味着 Ajax 交互最l要交换它们不需要交换的数据Q因此造成客户端代码要从文档中扑ֈ需要的信息更加困难Q而且也会(x)增加带宽消耗和客户端的 XML 解析旉。这U耦合的另一个后果就?XML 的语法不能脱?Java cȝ立变化。例如,寚w客文档的Ҏ(gu)做修改,可能?x)媄响多?Java c,造成它们也不得不做修改和重新~译?/p>

E后?x)解册些问题,但是首先来看一个对自行序列化方式的可׾~性问题的解决Ҏ(gu)QXML l定框架?/p>



XML l定框架

q? 些年来,已经开发了多个 Java API 来简?XML 文档?Java 对象囄l定q程。多数都提供?XML ~排和拆解;也就是说Q它们可以在 Java 对象囑֒ XML 之间执行双向?x)话。这些框架封装了 XML 处理的全部工作,q意味着应用E序代码只需要处理普通的 Java cR它们还希望提供有用的辅助功能,例如文档验证。笼l来_(d)q些框架采用了两U不同的方式Q代码生成和对象?XML 映射。我分别解释这两种方式?/p>

代码生成方式

? 用代码生成的框架包括 XMLBeans、JAXB、Zeus ?JBind。Castor 也能使用q项技术。这cL架的L(fng)是描q文档数据类型的 XML Ҏ(gu)。用框架提供的工具Q就可以生成代表q些Ҏ(gu)定义cd?Java cR最后,用这些生成的cȝ写应用程序,表示自己的模型数据,q过框架提供的一些辅助机制把数据序列化成 XML?/p>

如果应用E序要用大 ?XML 语法Q那么代码生成方式是个很好的Ҏ(gu)。在数十个类上编写定?XML 序列化代码的可׾~性问题由此消除。另一斚wQ也不再需要定义自q JavaBean。框架生成的 Java c通常非常W合 XML 的结构,所以对它们q行~码很难。而且Q生成的cd成哑数据容器Q因Z般不能向它们d行ؓ(f)。一般来_(d)在应用程序代码中要做些妥协,才能很好地处理方 案生成的cd。另一个缺h如果修改Ҏ(gu)Q会(x)造成生成的类也要修改Q所以也׃(x)对围l它们编写的代码带来相应的媄响?/p>

q种cd?XML l定框架在数据拆解时最有用Q例如,使用 XML 文档q把它们转化?Java 对象Q。除非拥有大型数据模型而且有可能从生成的类中获益,否则Z代码生成的框架对?Ajax 应用E序来说可能有很大的杀伤力?/p>

映射方式

? 用映方式的框架包括 Castor ?Apache Commons Betwixt。映通常是比代码生成更灵zd更轻量的解决Ҏ(gu)。首先,可以像通常一L(fng)? JavaBeanQ包括Q何行Z?qing)Q何自己喜Ƣ的方便的方法。然后,在运行时Q调用框架中Z内省的编排器QƈҎ(gu)对象成员的类型、名U和值生? XML 文档。通过定义cȝ映射文gQ可以覆盖默认的l定{略Qƈq?XML 中的表示方式对编排器提出?/p>

q种Ҏ(gu)是在可׾~性与 灉|性之间的良好折中。可以按照自己喜Ƣ的方式~写 Java c,~排器负责处? XML。虽然映定义文件编写v来简单,可׾~性也_好,但是映射规则最多只能改变标准的l定行ؓ(f)Q而且在对象结构和它们?XML 表示之间总要D留一些耦合。最l,可能不得不在 Java 表示?XML 格式之间任选一个做些折中,才能让映方法v作用?/p>

数据l定ȝ

Dennis Sosnoski ?XML 数据l定 API 的主题,在代码生成和代码映射两个斚w写了深入的文章。如果想q一步研I这个领域,我推荐他?Castor 和代码生成框架方面的_ֽ文章Q请参阅 参考资?/a> 中的链接Q?/p>

MQ代码生成方式损׃q多的灵zL和方便性,对于典型?Ajax 应用E序用处不大。另一斚wQ基于映的框架可能工作得很好,但是要恰到好处地调整它们的映策略,以便从对象生成需要的 XML?/p>

所 有的 XML l定 API 都具有手工序列化技术的一个主要不I(x)模型和视囄耦合。被限制Z个类型一?XML 表示Q就意味着在网l上总要有冗余数据传输。更严重的问题是Q在情况要求客户端代码用专门视图时Q客L(fng)代码却无法得到它Q所以可能要费力地处理给定对 象图的一成不变的视图?/p>

在传l的 Web 应用E序开发中Q采用页面模板系l把视图生成与控制器逻辑和模型数据干净地分R这U方法在 Ajax 场景中也?x)有帮助?/p>



面模板pȝ

M通用目的的页面模板技术都可以用来生成 XMLQ从而 Ajax 应用E序Ҏ(gu)自己的数据模型生成Q?XML 响应文档。额外收hQ模板可以用单的、表现力强的标记语言~写Q而不是用一行行?Java 代码~写。清?5 是一?JSP 面Q采用了 Customer bean q表C出定制?XML 视图Q适合客户端代码生成订单历史组件?/p>
清单 4. 生成订单历史文档?JSP


<%@ page contentType="application/xml" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>





${order.date}




${item.formattedPrice}







q个z的模板只输单历史视N要的数据Q不输出不相关的资料Q例如商品说明)。创Z品搜索视囄定制 XML 应当同样单,q个视图包含每个商品的完整说明和库存水^?/p>

模板的问?/span>

? 一斚wQ现在我需要ؓ(f)每个不同视图创徏一个新 JSPQ而不能仅仅把需要的对象囄lv来ƈ序列化它。从设计的角度来_(d)许多人可能会(x)有争议,认ؓ(f)q无论如何是件好事,因ؓ(f)q意味着正式地考虑服务器要 生成的文档类型。而且Q因为我现在要处理通用的模板环境,而不是特定于 XML ?APIQ所以确保标记匹配、元素和属性的序正确以及(qing) XML 实体Q例?< ?&Q正{义就成了我的责Q。JSP 的核?out 标记使后面这工作变得很Ҏ(gu)Q但是不是所有的模板技术都提供了这L(fng)机制。最后,没有方便的途径可以在服务器端根据方案检验生成的 XML 文档的正性,但这毕竟不是要在生环境中做的事Q可以方便地在开发期间处理它?/p>



不用 XML 的响应数?/span>

q? 今ؓ(f)止,我介l的所有技术都?XML 文档的Ş式生成服务器响应。但是,XML 有一些问题。其中一个就是gq。浏览器不能立即解析 XML 文档q生?DOM 模型Q所以这?x)降低某?Ajax lg需要的“迅捷”感Q特别是在较慢的机器上解析大型文档的时候更是如此。“现场搜索”就是一个示例,在这U搜索中Q当用户输入搜烦术语Ӟ׃(x)从服务器 提取搜烦l果q显C给用户。对于现场搜索组件来_(d)q速地响应输入是非帔R要的Q但是同时它q需要迅速而持l地解析服务器的响应?/p>

延迟是一个重要的考虑因素Q但是避免?XML 的最大原因是差劲的客L(fng) DOM API。清?5 昄了用跨览器兼容的方式通过 DOM 得到某个值的时候,通常不得不面对的困难?/p>
清单 5. ?JavaScript 中导?XML 响应文档

// Find name of first item in customer's last order
var orderHistoryDoc = req.responseXML;

var orders = orderHistoryDoc.getElementsByTagName("order");
var lastOrder = orders[orders.length - 1];

var firstItem = lastOrder.getElementsByTagName("item")[0];
var itemNameElement = firstItem.firstChild;

var itemNameText = itemNameElement.firstChild.data;

当元素中间存在空白时Q情况就变得更加复杂Q因为每个元素的 firstChild l常是个I白文本节点。现在有 JavaScript 库可以缓解处?XML 文档的麻烦。这些库包括 Sarissa Q请参阅 参考资?/a>Q和 Google-ajaXSLTQ这两个库都?XPath 功能dC大多数浏览器中?/p>

但是Q想x代方案还是值得的。除?responseXML 之外Q?code>XMLHttpRequest 对象q提供了名ؓ(f) responseText 的属性,q个属性只是以字符串的方式提供服务器的响应体?/p>

responseText 属?/span>

当服务器需要向客户机发送非常简单的值时Q?code>responseText 特别方便Q它可以避免 XML D的带宽支出和处理支出。例如,单的 true/false 响应可以由服务器以纯文本方式q回Q可以是逗号分隔的简单的名称或数字列表。但是,一般来_(d)最好不要在同一个应用程序中?XML 响应和纯文本响应混合使用Q保持单一数据格式可以让代码抽象和重用更加单?/p>

responseText ? XML 响应数据l合时也?x)有用。在只需要从响应文档中提取单一值的场景中,“欺骗性”地?XML 当作文本字符Ԍ而不把它当作l构化的文档对待Q会(x)更方ѝ例如,清单 6 昄了如何用正则表达式从֮的订单历史中提取W一W订单的日期。不q,q实际是U花招,一般不应当依赖 XML 文档的词汇表达?/p>
清单 6. 用正则表辑ּ处理 XMLHttpRequest ?responseText 对象

var orderHistoryText = req.responseText;
var matches = orderHistoryText.match(/(.*?)<\/date>/);

var date = matches[1];

在某些情况下Q采用即时方式?responseText ?x)比较方ѝ但是,理想情况下,应当有种途径Q可以用一U能够让 JavaScript LD、却没有 XML 处理支出的格式表C复杂的l构化数据。幸q的是,实存在q样一U格式?/p>



JavaScript 对象标注

? 际上QJavaScript 对象的大部分都由联合数组、数字烦引数l、字W串、数字或者这些类型的嵌套l合而成。因为所有类型都可以? JavaScript 直接声明Q所以可以在一条语句中静态地定义对象图。清?7 使用 JSON 语法声明了一个对象,q演CZ如何讉Kq个对象。大括号表示联合数组Q即对象Q,它的?-值组合由逗号分隔。方括号表示数字索引数组?/p>
清单 7. ?JSON ?JavaScript 中直接声明一个简单对?/b>

var band = {
name: "The Beatles",
members: [
{
name: "John",
instruments: ["Vocals","Guitar","Piano"]
},
{
name: "Paul",
instruments: ["Vocals","Bass","Piano","Guitar"]
},
{
name: "George",
instruments: ["Guitar","Vocals"]
},
{
name: "Ringo",
instruments: ["Drums","Vocals"]
}
]
};

// Interrogate the band object
var musician = band.members[3];
alert( musician.name
+ " played " + musician.instruments[0]
+ " with " + band.name );

既然 JSON 是一个有的语言Ҏ(gu),那么它对 Ajax 有什么意义呢Q妙处在于可以用 JSON ?Ajax 服务器响应中通过|络发?JavaScript 对象图。这意味着在客L(fng)可以避免使用W拙?DOM API ?XML q行D —?只需要分?JSON 响应Q就?x)立卛_到可以访问的 JavaScript 对象图。但是,首先需要把 JavaBean 变成 JSON?/p>

?Java cM?JSON

不同 XML 生成技术所h的优~点也适用?JSON 的生。而且可以证明Q存在需要再ơ用表C模板技术的情况。但是,使用 JSON 在理念上更接q于在应用层之间传递序列化的对象,而不是创建应用程序状态的视图。我介l如何用 org.json q个 Java API ?Java cM创徏 toJSONObject() Ҏ(gu)。然后,可以把 JSONObject 单地序列化成 JSON。清?8 反映?清单 1 讨论?XMLQ显CZ OrdertoJSONObject() 实现?/p>
清单 8. Order cȝ toJSONObject() Ҏ(gu)实现

public JSONObject toJSONObject() {

JSONObject json = new JSONObject();
json.put("id",id);
json.put("cost",getFormattedCost());
json.put("date",date);

JSONArray jsonItems = new JSONArray();
for (Iterator iter =
items.iterator() ; iter.hasNext() ; ) {
jsonItems.put(iter.next().toJSONObject());
}
json.put("items",jsonItems);

return json;
}

可以看到Q?code>org.json API 非常单?JSONObject 代表 JavaScript 对象Q即联合数组Q,有不同的 put() Ҏ(gu)Q方法接受的 String 键和值是原生cd?code>String cd或其?JSON cd?code>JSONArray 代表索引数组Q所以它?put() Ҏ(gu)只接受一个倹{请注意在清?8 中,创徏 jsonItems 数组Q然后再?put() 把它附加?json 对象上;可以用另外一U方法做q项工作Q就是对每个目调用 json.accumulate("items",iter.next().toJSONObject());?code>accumulate() Ҏ(gu)?put() cMQ区别在于它把值添加到按照键进行识别的索引数组?/p>

清单 9 昄了如何序列化 JSONObject q把它写?servlet 响应?/p>
清单 9. ?JSONObject 生成序列化的 JSON 响应

public void doGet(HttpServletRequest req, HttpServletResponse res)
throws java.io.IOException, ServletException {

String custId = req.getParameter("username");
Customer customer = getCustomer(custId);

res.setContentType("application/x-json");
res.getWriter().print(customer.toJSONObject());
}

可以看到Q它实际上什么也没有做。在q里隐式调用?JSONObject ?toString() Ҏ(gu)做了所有工作。请注意Q?code>application/x-json 内容cdq有一点不定 —?在编写这文章的时候,关于 JSON 应当属于什?MIME cdq没有定论。但是,目前 application/x-json 是合理的选择。清?10 昄了这?servlet 代码的示例响应?/p>
清单 10. Customer bean ?JSON 表示

{
"orders": [
{
"items": [
{
"price": "$49.99",
"description": "512 Megabyte Type 1 CompactFlash card.
Manufactured by Oolong Industries",
"name": "Oolong 512MB CF Card",
"id": "i-55768"
},
{
"price": "$299.99",
"description": "7.2 Megapixel digital camera featuring six
shooting modes and 3x optical zoom. Silver.",
"name": "Fujak Superpix72 Camera",
"id": "i-74491"
}
],
"date": "08-26-2005",
"cost": "$349.98",
"id": "o-11123"
}
],
"realname": "James Hyrax",
"username": "jimmy66"
}

在客L(fng)使用 JSON

处理的最后一步是把在客户端把 JSON 数据变成 JavaScript 对象。这可以通过?eval() 的简单调用实玎ͼq个函数可以x地解释包?JavaScript 表达式的字符丌Ӏ清?11 ?JSON 响应转变?JavaScript 对象图,然后执行清单 5 的Q务,从顾客的最后一ơ订单中得到W一个商品的名称?/p>
清单 11. 评估 JSON 响应

var jsonExpression = "(" + req.responseText + ")";
var customer = eval(jsonExpression);

// Find name of first item in customer's last order
var lastOrder = customer.orders[customer.orders.length-1];
var name = lastOrder.items[0].name;

比较清单 11 ?清单 5 可以发现使用 JSON 的客L(fng)的优ѝ如果在 Ajax 目中要在客L(fng)对许多复杂的服务器响应进行导航,那么 JSON 可能适合(zhn)的需要。JSON ?XMLHttpRequest l合q会(x)?Ajax 交互看v来更?RPC 调用而不?SOA hQ这对应用程序的设计可能?x)有意义。在下一文章中Q我要研I的框架Q就是明地Z?JavaScript 代码Ҏ(gu)务器端对象进行远E方法调用而设计的?/p>

JSON 的不?/span>

JSON 也有它的不。用这里介l的 JSON 方式Q就没有办法针对每个h对对象的序列化进行裁剪,所以不需要的字段可能l常?x)在|络上发送。另外,d toJSONObject() Ҏ(gu)到每?JavaBeanQ可伸羃性不太好Q虽然用内省和标注编写一个通用?JavaBean ?JSON 的序列化器可能很单。最后,如果服务器端代码是面向服务的Q没有单独针对处?Ajax 客户h调整q,那么׃?XML 一致的支持QXML ?x)是更好的选择?/p>



比较序列化技?/span>

? 在已l看C?Java 状态传输到 Ajax 客户端的五种不同技术。我讨论了自行手工编?XML 序列化、通过代码生成?XML l定、通过映射机制?XML l定、基于模板的 XML 生成以及(qing)手工~码?JSON 的序列化。每U技术都有自q优势和不I分别适用于不同的应用E序架构?

Zȝ每种方式的优势与不Q表 1 从六个方面进行了_略的评分:(x)

可׾~?/b>
描述技术适应大量数据cd的容易程度。对于每个附加类型,~码和配|工作量是否?x)增长?/dd>
易于集成
评估把技术集成到目的简单程度。是否需要更加复杂的构徏q程Q是否增加了部v的复杂性?
Java c?API
描述以指定方式处理服务器?Java 对象的容易程度。是可以~写普通的 beanQ还是不得不处理W拙的文档表C?
对输出的控制
描述对类的序列化表示控制的精程度?/dd>
视图灉|?/b>
评估从同一l对象是否可以创Z同的、定制的数据序列化?/dd>
客户端数据访?/b>
描述 JavaScript 代码处理服务器响应数据的难易E度?/dd>
?1. 数据生成技术的相对价?/em>

自行~写 XML通过代码生成?XML l定通过映射?XML l定面模板 XML手工~码?JSON 序列?/th>
可׾~?/td>?/td>?/td>一?/td>一?/td>?/td>
易于集成?/td>?/td>一?/td>一?/td>?/td>
Java c?API?/td>?/td>?/td>?/td>?/td>
对输出的控制?/td>?/td>一?/td>?/td>?/td>
视图灉|?/td>?/td>?/td>?/td>?/td>?/td>
客户端数据访?/td>?/td>?/td>?/td>一?/td>?/td>




l束?/span>

? 1 中的数据q不表明某项序列化技术比其他的技术好。毕竟,六种标准的相寚w要性取决于目的具体情c例如,如果要处理数癄数据cdQ这时想要的是可伸羃 性,那么代码生成可能是最好的选择。如果需要ؓ(f)同一数据模型生成多个不同视图Q那么就应当使用面模板。如果处理的是小规模目Q想降低需要编写的 JavaScript 代码数量Q那么请考虑 JSON?/p>

希望q篇文章为?zhn)提供了选择适合自己应用E序的序列化技术所需要的信息?/p>

bluesky 2005-10-30 15:32 发表评论
]]>
利用JavaScript屏蔽[鼠标右键、Ctrl+N、Shift+F10、Alt+F4、F11、F5h、退格键]http://www.aygfsteel.com/sunbaoyu/archive/2005/10/30/17410.htmlblueskyblueskySun, 30 Oct 2005 02:40:00 GMThttp://www.aygfsteel.com/sunbaoyu/archive/2005/10/30/17410.htmlhttp://www.aygfsteel.com/sunbaoyu/comments/17410.htmlhttp://www.aygfsteel.com/sunbaoyu/archive/2005/10/30/17410.html#Feedback2http://www.aygfsteel.com/sunbaoyu/comments/commentRss/17410.htmlhttp://www.aygfsteel.com/sunbaoyu/services/trackbacks/17410.html<html> 
<head> 
  
<meta http-equiv="Content-Type" content="text/html; charset=gb2312"> 
  
<noscript><meta http-equiv="refresh" content="0;url=about:noscript">noscript> 
  
<title>屏蔽鼠标右键、Ctrl+N、Shift+F10、Alt+F4、F11、F5h、退格键title> 
head> 
<body> 
<script language="Javascript">