在Struts中应用Ajax
来源:百度文库 编辑:神马文学网 时间:2024/04/28 08:14:30
在Struts中应用Ajax
AJAX是“异步的JavaScript和XML”的缩写。这是一项技术,而不是一个如Struts一样的框架。为什么在AJAX周围会有这么多的关注呢?这是因为AJAX使web页面看起来并不像一个平面的文档,而更像用户所期望的如桌面应用的动态GUI应用程序。AJAX技术能在很多的浏览器上使用(包括IE和Netscape/Mozilla)。它已经为Microsoft(用于Outlook的web客户端)和Google(用户Google Maps和Gmail)所使用。 未使用AJAX之前 目前大多数的Struts应用都是标准的“如同一个平面文档的web页面”的结构。如果你想模仿一些桌面应用程序(比如那些使用Java Swing,Visual Basic,或者Delphi建立的应用程序),那么你有两个选择:你可以发送所有的可能作为页面的一部分被请求的信息,使用大量的JavaScript来操作其动态的显示(一个很慢并且非企业级Java的方法);或者你可以不改变形式地提交到后台服务器(一种有效的方法) 。AJAX提高给你了融合前面的最佳解决方案:动态的页面,但是大多数的应用是在你的web服务器的Java程序来处理的。 AJAX 101 AJAX和现有的动态HTML技术非常相似,并在其上增加了一个发送到“后台”服务器的请求来获取需要的新的或者更新的信息。AJAX的机制在其他地方已经有详细的说明――请查看本文后的Resources来获取更多。但是你至少需要知道: 在你的Struts应用中使用AJAX 你阅读了本文,然后你会对使用AJAX来创建动态的web页面感兴趣,并且想知道如何将它加入到你的Struts应用中。这只是选择之一。那么你会如何选择呢? 我们选择在Struts应用中增加AJAX的优势是: 实现方案 我们如何真正的贯彻我们的选择呢?我们首先应该注意一个“标准的”(没有AJAX)Struts应用是如何工作的。在此应用中,一个一般的事件流程如下: 现有的Struts应用 一个演示事件流程的简单Struts应用可以在以下地址下载: struts-non-ajax.zip。此基于Struts的应用,是基于用户的输入显示或者隐藏蓝色和绿色的表格。图1显示了载入初始页面的画面。图2显示了用户输入值并点击了提交后的画面。虽然简单,但它已经足以表示一个Struts的工作流程。 图 1. 没有AJAX的例子:初始屏幕 服务器端的代码是:一个Struts Action使用struts-config.xml 中定义的值转发到(相同的)JSP。这个例子代码中一些需要注意的地方是: 该应用并没有任何“错误”。类似的Struts项目好多年都是这样做的。但是,我们如何在不添加复杂的JavaScript或者频繁的表单提交的前提下,为此应用增加动态的元素呢? 我们的第一个Struts AJAX应用 观察下下面的图3和图4。第一眼看上去,它们和前面的例子没有说明区别。它们的不同之处在于,页面载入后(图3)然后文本框中的值改变了,窗体自动提交而不显示空白的,然后在图4中显示结果。普通的提交按钮仍然在,你也可以选择使用它。 图 3. 页面载入后的AJAX例子 图 4. AJAX调用后的AJAX例子 添加AJAX是出奇的容易。服务器端的代码和前面的例子是一样的: 一个Struts的ActionForm来后去数据,一个Struts的Action来执行需要的任务(例如,存储数据库)然后转发到适当的JSP页面来显示结果。 继续 如果你希望就此停止阅读(跳过这个例子的工作说明),但是这里的是和你需要转换你的Struts应用到一个Struts-AJAX应用同样的风格: JavaScript方法retrieveURL()调用服务器的Struts(通过URL),获取JSP响应,然后更新显示页面中的 标签中的部分。就是这么简单! AJAX解决方案的细节 我们将例子变为AJAX-Struts应用的时候,需要三个变化: 有两个方法(在下面列出)用于发送请求到服务器。 · retrieveURL()方法获得服务器的URL和Struts form。URL用于使用AJAX,form的值用于传递到服务器。 · getFormAsString()方法用于将retrieveURL()中form命名的值组装成查询字符串,并发送到服务器。 使用方法很简单,使用onclick()/onChange()事件来触发retrieveURL()更新显示。 在这两个方法中有一些有趣的东西。 在retrieveURL()方法中,req.onreadystatechange = processStateChange (注意,没有括号)这一行来告诉浏览器在服务器响应到达的时候调用processStateChange()方法(该方法将在后面介绍)。retrieveURL()方法中(现在已经是AJAX的标准了)同样决定是使用IE浏览器(ActiveX)还是使用Netscape/Mozilla (XmlHttpRequest) 来实现跨浏览器兼容。 getFormAsString()方法将HTML form转换成字符串连接在URL后面(这样就允许我们发送HTTP GET请求)。这个字符串是经过转换的(比如,空格转换成%20等),并且是一个Struts能将其组装成ActionForm的格式(并不需要Struts清楚的明白这个是来之AJAX的请求)。注意,在本例中我们使用HTTP GET,使用HTTP POST的方法也是类似的。 function retrieveURL(url,nameOfFormToPost) { //将url转换成字符串 //调用AJAX // 非IE浏览器 req = new ActiveXObject("Microsoft.XMLHTTP"); getFormAsString() 是一个“私有” 方法,在retrieveURL()中使用。 function getFormAsString(formName){ //设置返回字符串 //取得表单的值 //循环数组,组装url for(var i=formElements.length-1;i>=0; --i ){ 根据AJAX的响应更新web页面 到现在为止,我们学习过了使用JavaScript来完成AJAX调用(前面列出),Struts Action,ActionForm以及JSP(基本没有变化,只是增加了标签)。为了完善我们对Struts-AJAX项目的了解,我们需要了解三个用于根据服务器返回的结果而更新页面的JavaScript方法。 function processStateChange() { if (req.readyState == 4) { // 完成 //将响应的文本分割成Span元素 //使用这些Span元素更新页面 } else { function replaceExistingWithNewHtml //循环newTextElements //判断是否以 if(newTextElements[i]. //获得span的名字- 设置在第一和第二个引号之间 //获得内容-在第一个>标记后的所有内容 //现在更新现有的Document中的元素, //分割文档 //处理每个元素 //删除掉第一个span后面的元素 //如果找到匹配的,获得span前的内容 新的控制流 添加以下的JavaScript代码到我们的应用中,以下的步骤将在服务器和浏览器中执行。 在你的应用中设计AJAX 以上描述的JavaScript方法能在大多数的应用中使用,包括比我们的例子复杂得多的。但是,在使用之前,你需要注意以下几点: · 避免复制代码,最好在初始化请求(如,显示完整的页面)和AJAX(更新部分页面)请求中使用相同的Struts Action和JSP。 ·在公共的Action(控制器)中,决定JSP页面(所有的JSP页面或者其中的一部分)中的一个区域需要传送到浏览器。通过在web服务器的session或者ActionForm中设定标记来让JSP页面知道哪些部分需要提交。 · 在JSP中,使用Struts 或者JSTL标签来决定提交的HTML区域。 使用AJAX的本例子,可以在以下下载: struts-Ajax.zip 结语 AJAX技术允许我们在创建和使用web应用的时候完全的改变。本文介绍了一个简单的技术,在现有的Struts应用中增加Struts的处理。它允许我们利用我们已有的东西,不仅仅是代码,还包括了开发的技能。作为一个好的产品,它同样允许我们写出更清晰,更具移植性的Java Struts应用。
我们将详细的说明上面的每一步。 发送AJAX请求到服务器
url=url+getFormAsString(nameOfFormToPost);
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
req.onreadystatechange = processStateChange;
try {
req.open("GET", url, true);
} catch (e) {
alert("Server Communication Problem\n"+e);
}
req.send(null);
} else if (window.ActiveXObject) {
// IE
if (req) {
req.onreadystatechange=processStateChange;
req.open("GET", url, true);
req.send();
}
}
}
returnString ="";
formElements=document.forms[formName].elements;
//像‘/strutsaction.do&name=value‘这样的格式
//转化每一个值
returnString+="&"
+escape(formElements[i].name)+"="
+escape(formElements[i].value);
}
return returnString;
}
if (req.status == 200) { // 响应正常
spanElements =
splitTextIntoSpan(req.responseText);
replaceExistingWithNewHtml(spanElements);
alert("Problem with server response:\n "
+ req.statusText);
}
}
}
replaceExistingWithNewHtml() 是为processStateChange()使用的“私有”方法。
(newTextElements){
for(var i=newTextElements.length-1;i>=0;--i){
indexOf("-1){
//确认span元素是以下的格式
//NewContent
startNamePos=newTextElements[i].
indexOf(‘"‘)+1;
endNamePos=newTextElements[i].
indexOf(‘"‘,startNamePos);
name=newTextElements[i].
substring(startNamePos,endNamePos);
startContentPos=newTextElements[i].
indexOf(‘>‘)+1;
content=newTextElements[i].
substring(startContentPos);
// 确保文档存在该元素
if(document.getElementById(name)){
document.getElementById(name).
innerHTML = content;
}
}
}
splitTextIntoSpan() 是为processStateChange() 使用的“私有”方法。
function splitTextIntoSpan(textToSplit){
returnElements=textToSplit.
split("")
for(var i=returnElements.length-1;i>=0;--i){
spanPos = returnElements[i].
indexOf("
if(spanPos>0){
subString=returnElements[i].
substring(spanPos);
returnElements[i]=subString;
}
}
return returnElements;
}