📄 面向 java 开发人员的 ajax 构建动态的 java 应用程序.htm
字号:
<TD vAlign=center><IMG height=16 alt=""
src="面向 Java 开发人员的 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-ajax1/#main"><B>回页首</B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<P><A name=N101B2><SPAN class=atitle>用 JavaScript
进行响应处理</SPAN></A></P>
<P><CODE>XMLHttpRequest</CODE> 的 <CODE>readyState</CODE>
属性是一个数值,它指出请求生命周期的状态。它从 0(代表“未初始化”)变化到 4(代表“完成”)。每次
<CODE>readyState</CODE> 变化时,<CODE>readystatechange</CODE> 事件就触发,由
<CODE>onreadystatechange</CODE> 属性指定的事件处理函数就被调用。</P>
<P>在 <A
href="http://www.ibm.com/developerworks/cn/java/j-ajax1/#listing3">清单
3</A> 中已经看到了如何调用 <CODE>getReadyStateHandler()</CODE>
函数创建事件处理函数。然后把这个事件处理函数分配给 <CODE>onreadystatechange</CODE>
属性。<CODE>getReadyStateHandler()</CODE> 利用了这样一个事实:函数是 JavaScript
中的一级对象。这意味着函数可以是其他函数的参数,也可以创建和返回其他函数。<CODE>getReadyStateHandler()</CODE>
的工作是返回一个函数,检查 <CODE>XMLHttpRequest</CODE> 是否已经完成,并把 XML
响应传递给调用者指定的事件处理函数。清单 6 是 <CODE>getReadyStateHandler()</CODE>
的代码。</P><BR><BR><A name=listing6><B>清单 6. getReadyStateHandler()
函数</B></A><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=code-outline><PRE class=displaycode>/*
* 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);
}
}
}
}
</PRE></TD></TR></TBODY></TABLE><BR>
<TABLE cellSpacing=0 cellPadding=0 width="40%" align=right
border=0><TBODY>
<TR>
<TD width=10><IMG height=1 alt=""
src="面向 Java 开发人员的 Ajax 构建动态的 Java 应用程序.files/c.gif"
width=10></TD>
<TD>
<TABLE cellSpacing=0 cellPadding=5 width="100%" border=1>
<TBODY>
<TR>
<TD bgColor=#eeeeee><A name=N101FC><B>HTTP
状态码</B></A><BR>
<P>在清单 6 中,检查 <CODE>XMLHttpRequest</CODE> 的
<CODE>status</CODE> 属性以查看请求是否成功完成。<CODE>status</CODE>
包含服务器响应的 HTTP 状态码。在执行简单的 <CODE>GET</CODE> 和
<CODE>POST</CODE> 请求时,可以假设任何大于 200
(OK)的码都是错误。如果服务器发送重定向响应(例如 301 或
302),浏览器会透明地进行重定向并从新的位置获取资源;<CODE>XMLHttpRequest</CODE>
看不到重定向状态码。而且,浏览器会自动添加 <CODE>Cache-Control:
no-cache</CODE> 头到所有
<CODE>XMLHttpRequest</CODE>,这样客户代码永远也不用处理
304(未经修改)服务器响应。</P></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<P><A name=N10225><SPAN class=smalltitle>关于
getReadyStateHandler()</SPAN></A></P>
<P><CODE>getReadyStateHandler()</CODE> 是段相对复杂的代码,特别是如果您不习惯阅读
JavaScript 的话。但是通过把这个函数放在 JavaScript 库中,就可以处理 Ajax 服务器响应,而不必处理
<CODE>XMLHttpRequest</CODE> 的内部细节。重要的是要理解如何在自己的代码中使用
<CODE>getReadyStateHandler()</CODE>。</P>
<P>在 <A
href="http://www.ibm.com/developerworks/cn/java/j-ajax1/#listing3">清单
3</A> 中看到了 <CODE>getReadyStateHandler()</CODE>
像这样被调用:<CODE>handlerFunction = getReadyStateHandler(req,
updateCart)</CODE>。在这个示例中,<CODE>getReadyStateHandler()</CODE>
返回的函数将检查在 <CODE>req</CODE> 变量中的 <CODE>XMLHttpRequest</CODE>
是否已经完成,然后用响应的 XML 调用名为 <CODE>updateCart</CODE> 的函数。</P>
<P><A name=N10259><SPAN class=smalltitle>提取购物车数据</SPAN></A></P>
<P>清单 7 是 <CODE>updateCart()</CODE> 本身的代码。函数用 DOM 调用检查购物车的 XML
文档,然后更新 Web 页面(请参阅 <A
href="http://www.ibm.com/developerworks/cn/java/j-ajax1/#listing1">清单
1</A>),反映新的购物车内容。这里的重点是用来从 XML DOM 提取数据的调用。<CODE>cart</CODE> 元素的
<CODE>generated</CODE> 属性是在 <CODE>Cart</CODE> 序列化为 XML
时生成的一个时间戳,检查它可以保证新的购物车数据不会被旧的数据覆盖。Ajax
请求天生是异步的,所以这个检查可以处理服务器响应未按次序到达的情况。</P><BR><BR><A name=listing7><B>清单
7. 更新页面,反映购物车的 XML 文档</B></A><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD class=code-outline><PRE class=displaycode>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");
}
</PRE></TD></TR></TBODY></TABLE><BR>
<P>到此,整个 Ajax 往返过程完成了,但是您可能想让 Web 应用程序运行一下查看实际效果(请参阅 <A
href="http://www.ibm.com/developerworks/cn/java/j-ajax1/#download">下载</A>
一节)。这个示例非常简单,有很多需要改进之处。例如,我包含了从购物车中清除项目的服务器端代码,但是无法从 UI
访问它。作为一个好的练习,请试着在应用程序现有的 JavaScript 代码之上构建出能够实现这个功能的代码。</P><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><IMG height=1 alt=""
src="面向 Java 开发人员的 Ajax 构建动态的 Java 应用程序.files/blue_rule.gif"
width="100%"><BR><IMG height=6 alt=""
src="面向 Java 开发人员的 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 构建动态的 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 构建动态的 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-ajax1/#main"><B>回页首</B></A></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<P><A name=N10287><SPAN class=atitle>使用 Ajax 的挑战</SPAN></A></P>
<P>就像任何技术一样,使用 Ajax 也有许多出错的可能性。我目前在这里讨论的问题还缺乏容易的解决方案,但是会随着 Ajax
的成熟而改进。随着开发人员社区增加开发 Ajax 应用程序的经验,将会记录下最佳实践和指南。</P>
<P><A name=N10290><SPAN class=smalltitle>XMLHttpRequest
的可用性</SPAN></A></P>
<P>Ajax 开发人员面临的一个最大问题是:在没有 <CODE>XMLHttpRequest</CODE>
可用时该如何响应?虽然主要的现代浏览器都支持
<CODE>XMLHttpRequest</CODE>,但仍然有少数用户的浏览器不支持,或者浏览器的安全设置阻止使用
<CODE>XMLHttpRequest</CODE>。如果开发的 Web
应用程序要部署在企业内部网,那么可能拥有指定支持哪种浏览器的权力,从而可以认为 <CODE>XMLHttpRequest</CODE>
总能使用。但是,如果要部署在公共 Web 上,那么就必须当心,如果假设 <CODE>XMLHttpRequest</CODE>
可用,那么就可能会阻止那些使用旧的浏览器、残疾人专用浏览器和手持设备上的轻量级浏览器的用户使用您的应用程序。</P>
<P>所以,您应当努力让应用程序“平稳降级”,在没有 <CODE>XMLHttpRequest</CODE>
支持的浏览器中也能够工作。在购物车的示例中,把应用程序降级的最好方式可能是让 Add to Cart
按钮执行一个常规的表单提交,刷新页面来反映购物车更新后的状态。Ajax 的行为应当在页面装入的时候就通过 JavaScript
添加到页面,只有在 <CODE>XMLHttpRequest</CODE> 可用时才把 JavaScript 事件处理函数附加到每个
Add to Cart 按钮。另一种方式是在用户登录时检测 <CODE>XMLHttpRequest</CODE>
是否可用,然后相应地提供应用程序的 Ajax 版本或基于表单的普通版本。</P>
<P><A name=N102BC><SPAN class=smalltitle>可用性考虑</SPAN></A></P>
<P>关于 Ajax 应用程序的某些可用性问题比较普遍。例如,让用户知道他们的输入已经注册了可能是重要的,因为沙漏光标和
spinning 浏览器的常用反馈机制“throbber”对 <CODE>XMLHttpRequest</CODE>
不适用。一种技术是用“Now updating...”类型的信息替换 Submit
按钮,这样用户在等候响应期间就不会反复单击按钮了。</P>
<P>另一个问题是,用户可能没有注意到他们正在查看的页面的某一部分已经更新了。可以使用不同的可视技术,把用户的眼球带到页面的更新区域,从而缓解这个问题。由
Ajax 更新页面造成的其他问题还包括:“破坏了”浏览器的后退按钮,地址栏中的 URL 也无法反映页面的整个状态,妨碍了设置书签。请参阅
<A
href="http://www.ibm.com/developerworks/cn/java/j-ajax1/#resources">参考资料</A>
一节,获得专门解决 Ajax 应用程序可用性问题的文章。</P>
<P><A name=N102D0><SPAN class=smalltitle>服务器负载</SPAN></A></P>
<P>用 Ajax 实现代替普通的基于表单的 UI,会大大提高对服务器发出的请求数量。例如,一个普通的 Google Web
搜索对服务器只有一个请求,是在用户提交搜索表单时出现的。而 Google Suggest
试图自动完成搜索术语,它要在用户输入时向服务器发送多个请求。在开发 Ajax
应用程序时,要注意将要发送给服务器的请求数量以及由此造成的服务器负荷。降低服务器负载的办法是,在客户机上对请求进行缓冲并且缓存服务器响应(如果可能的话)。还应该尝试将
Ajax Web 应用程序设计为在客户机上执行尽可能多的逻辑,而不必联络服务器。</P>
<P><A name=N102D9><SPAN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -