`
lengue
  • 浏览: 8708 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

用XMLHttpRequest和struts实现AJAX(译)[转]

    博客分类:
  • AJAX
阅读更多

大约五年前我曾参与一个web应用的开发,该应用的一个主要需求是要提供类似window胖客户端的外观和操作方式。先不讨论为什么当初这个项目不直接使用window胖客户端,而把这个难题带到了web开发中,事实是在五年前还没有多少这样的东西(基于web的胖客户端)存在。

作为对这一课题研究的结果,我偶然发现了一些用于实现上述需求的非典型技术和方法。使用这些技术实现的web应用,直到现在很多人还不能相信它们是基于web的,然后事实上你确实是通过浏览器来访问它们。

让我没想到的是,几年后的今天我所实现的那种东西又出现另一种实现方式,它就是AJAX。AJAX是Adaptive Path的人们发明的一个名词,全称是Asynchronous Javascript + XML。

这说明了一件事情,提炼你曾经拥有的好主意是致富的一个好方法。如果当初我意识到我所作的是一件很特别的东西......我跑题了

Google正在使用这项技术,许多其它的组织也是。但它究竟是个什么东西呢?概括地说,AJAX不是一项技术,只是一种考虑问题的方法,这个方法整合了多种技术且基于这样一种考虑:为每一个客户请求构造一张全新的web页面是低效的且应该避免的。

举个例子,假设你再一张web页面上放了两个SELECT元素,你想让第二个SELECT元素的内容随着第一个的内容变化而变化,这是实际开发中很常见的一个问题而且有多种解决方案。

AJAX对此问题的解决方法是:只重画页面的一小部分,在这里是第二个SELECT。

AJAX基于一种称为XMLHttpRequest的组件。讨厌Microsoft的人要开始叫嚷了,因为这是Microsoft的东西。不错,Microsoft有些东西做得挺好,而且先于其他人做了。Microsoft最初实现XMLHttpRequest是在Windows下的IE 5中,其实现方式是ActiveX对象(好吧,他们做得不完全对!)。Monilla项目在Mozilla 1.0中实现了一个本地版本,还有Netscape 7。其他的还有Apple的Safari 1.2,Opera 7.60,Firefox等,有提供了类似的功能。

好,让我们切开这块蛋糕看看它的实现。

XMLHttpRequest是一个客户端组件,需要在Javascript脚本中实例化后才能使用。幸运的事,这样做非常简单。在IE中,实现代码如下:

var req = new ActiveXObject("Microsoft.XMLHTTP");

对其他的浏览器,使用:

var req = new XMLHttpRequest();

你当然想在代码中实现一些判断逻辑,有很多方法可以做到这点,但是我倾向于简单的方案,比如只是检查一下某个对象是否存在:

var req;

if (window.XMLHttpRequest) { // Non-IE browsers

req = new XMLHttpRequest();

} else if (window.ActiveXObject) { // IE

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

}

不管你怎么实现,上面的代码执行之后,你会发现变量req现在指向了一个XMLHttpRequest对象,这个对象有一组属性和方法,列举如下:

Property Description

onreadystatechange Event handler for an event that fires at every state change

readyState Status:

0 = uninitialized

1 = loading

2 = loaded

3 = interactive

4 = complete

responseText Data returned from server in string form

responseXML DOM-compatible document object of data returned

status HTTP status code (i.e., 200, 404, 500, etc.)

statusText String message associated with the status code



Method Description

abort() Stops the current request

getAllResponseHeaders() Returns all headers (name and value) as a string

getResponseHeader( Returns the value of the specified header

"<headerName>")

open("", "URL"[, Opens a connection and retrieves response from the specified URL.

asyncFlag[, ""[, Can also specify optional values method (GET/POST), username and

"<password>"]]]) password for secured sites

send(content) Transmits request (can include postable string or DOM object data)

setRequestHeader Assigns values to the specifed header

("<name>", "")



继续介绍之前,我强烈建议你运行本文末尾给出的那个web应用。如果你还没有下载示例应用,请参见本文末尾给出的链接,下载并安装到你的servlet引擎中。示例应用是以展开目录的结构形式发布的,所以只要解压后拷贝解压出的目录就可以工作。比如,如果你使用Tomcat,只要把xhrstruts目录拷贝到\webapps下就可以了。完成之后,启动服务器即可。

该应用可以通过http://localhost:8080/xhrstruts (将8080换成你的服务器所监听的端口)来访问。 它展示了几种不同的应用场景:一个可排序的table,一个可以改变另一个下拉框内容的下拉框(如上文所述),一个RSS feed 解析器。正像本文标题中说明的那样,该示例基于struts。尽管AJAX可以完全独立于struts和任何其他的后端技术,但我使用Java,而且使用struts,所以......

web应用中的所有例子都在代码头部的标签中包含有一段代码,尽管每个都有所不同,总体是出自相同的基础代码,如下:

var req;

var which;



function retrieveURL(url) {

if (window.XMLHttpRequest) { // Non-IE browsers

req = new XMLHttpRequest();

req.onreadystatechange = processStateChange;

try {

req.open("GET", url, true);

} catch (e) {

alert(e);

}

req.send(null);

} else if (window.ActiveXObject) { // IE

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

if (req) {

req.onreadystatechange = processStateChange;

req.open("GET", url, true);

req.send();

}

}

}



function processStateChange() {

if (req.readyState == 4) { // Complete

if (req.status == 200) { // OK response

document.getElementById("urlContent").innerHTML = req.responseText;

} else {

alert("Problem: " + req.statusText);

}

}

}


这段代码逻辑很简单。你可以调用retieveURL()方法,传入你想访问的URL,该方法根据浏览器类型实例化相应的XMLHttpRequest对象,开启一个对指定URL的请求。请留意这里的try...catch语句块,加入这段代码是因为有些浏览器(比如Firefox)不允许使用XMLHttpRequest从一个域到另一个域发送请求,换句话说,如果你从www.omnytex.com/test.htm页面请求www.cnn.com,该类浏览器是不允许的,但是,访问www.omnytext.com/whatever.htm是可以的。IE允许这种跨域访问但是需要用户验证。

有一行代码很重要:req.onreadystatechange = processStateChange,这行代码设定了一个事件处理器。当request的状态发生变化时,processStateChange()方法将被调用。然后,你可以检查XMLHttpRequest对象的状态进行后续处理。上面的列表中列出了所有可能的值。这里我们关心的是请求完成之后,下面要做的事就是检查收到的HTTP响应代码,除200(HTTP OK)外的任何代码都预示着需要显示错误信息。

在这个例子中,如果响应接收完成且没有异常,我们就把接收到的代码插入urlContent span,然后最终效果就显示在页面上。

语法上讲,这就是所有XMLHttpRequest的使用方法!

另一个更有趣的例子是web应用中的第二个,动态排序table。下面是完整的页面代码:

<code>

<html>

<head>

<title>Example 2</title>



<script>



var req;

var which;



function retrieveURL(url) {

if (window.XMLHttpRequest) { // Non-IE browsers

req = new XMLHttpRequest();

req.onreadystatechange = processStateChange;

try {

req.open("GET", url, true);

} catch (e) {

alert(e);

}

req.send(null);

} else if (window.ActiveXObject) { // IE

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

if (req) {

req.onreadystatechange = processStateChange;

req.open("GET", url, true);

req.send();

}

}

}



function processStateChange() {

if (req.readyState == 4) { // Complete

if (req.status == 200) { // OK response

document.getElementById("theTable").innerHTML = req.responseText;

} else {

alert("Problem: " + req.statusText);

}

}

}



</script>



</head>

<body onLoad="retrieveURL('example2RenderTable.do');">



<h1>Example 2</h1>

Dynamic table.<hr>

<p align="right"><a href="home.do">Return home</a></p><br>

This example shows how a table can be built and displayed on-the-fly by showing

sorting of a table based on clicks on the table headers.

<br><br>



<span id="theTable"></span>

<br>



</body>

</html>

</code>


请注意中几乎相同的代码。这里我们实际请求的是一个Struts的Action,该action返回绘制table的HTML脚本。还有其他方法可以达到相同的效果而无需在Action中产生HTML,但这是最快捷而且工作良好的。当页面最初载入的时候我们发送请求到Action得到一个最初的table,点击任何列标题可以将该table排序并重新绘制。

我们再来看另外一个例子,RSS feed 解析器:

<code>

<html>

<head>

<title>Example 6</title>

</head>



<script>



var req;

var which;



function retrieveURL(url) {

if (url != "") {

if (window.XMLHttpRequest) { // Non-IE browsers

req = new XMLHttpRequest();

req.onreadystatechange = processStateChange;

try {

req.open("GET", url, true);

} catch (e) {

alert(e);

}

req.send(null);

} else if (window.ActiveXObject) { // IE

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

if (req) {

req.onreadystatechange = processStateChange;

req.open("GET", url, true);

req.send();

}

}

}

}



function processStateChange() {

if (req.readyState == 4) { // Complete

if (req.status == 200) { // OK response

// We're going to get a list of all tags in the returned XML with the

// names title, link and description. Everything else is ignored.

// For each that we find, we'll constuct a simple bit of HTML for

// it and build up the HTML to display. When we hit a title,

// link or description element that isn't there, we're done.

xml = req.responseXML;

i = 0;

html = "";

while (i >= 0) {

t = xml.getElementsByTagName("title")[i];

l = xml.getElementsByTagName("link")[i];

d = xml.getElementsByTagName("description")[i];

if (t != null && l != null && d != null) {

t = t.firstChild.data;

l = l.firstChild.data;

d = d.firstChild.data;

html += "<a href=\"" + l + "\">" + t + "</a><br>" + d + "<br><br>";

i++;

} else {

i = -1;

}

}

document.getElementById("rssData").innerHTML = html;

} else {

alert("Problem: " + req.statusText);

}

}

}



</script>



<body>



<h1>Example 6</h1>

RSS example.<hr>

<p align="right"><a href="home.do">Return home</a></p><br>

This example is a more real-world example. It retrieves an RSS feed from one

of three user-selected sources, parses the feed and displays the headlines

in clickable form. This demonstrates retrieving XML from a server and

dealing with it on the client.

<br><br>

<b>Note that the RSS feed XML is actually stored as files within this

webapp. That is because some browsers will not allow you to retrieve

content with XMLHttpRequest outside the domain of the document trying to

do the call. Some browsers will allow it with a warning though.</b>

<br><br>

<form name="rssForm">

<select name="rssFeed" onChange="retrieveURL(this.value);">

<option value=""></option>

<option value="cnn_rss.xml">CNN Top Stories</option>

<option value="slashdot_rss.xml">Slashdot</option>

<option value="dans_rss.xml">Dan's Data</option>

</select>

</form>

<hr><br>

<span id="rssData"></span>

<br>



</body>

</html>

</code>


首先要注意的是RSS feed XML文件实际上是包含在web应用中的本地文件。一个真正实用使用XMLHttpRequest的RSS阅读器是不可能实现的因为要涉及到跨域处理。然而,一个可行的方法是写一个Action从真正的URL处得到feed然后将之返回给请求页面,参见示例7。除了需要一个Action作为代理来得到RSS feed外,页面上代码还是相同的。

上面的例子跟其它的类似,除了在事件处理器中的XML解析代码。这只是一个简化的例子,我们只是简单地忽略了除标题之外的其他标签。在一个真实的例子中(比如一个请求复杂XML的应用),解析代码会变得复杂,但这个我留给读者作为练习。

让我们以一个在请求中提交数据的例子做结,中的脚本如下:

var req;

var which;



function submitData() {

// Construct a CSV string from the entries. Make sure all fields are

// filled in first.

f = document.theForm.firstName.value;

m = document.theForm.middleName.value;

l = document.theForm.lastName.value;

a = document.theForm.age.value;

if (f == "" || m == "" || l == "" || a == "") {

alert("Please fill in all fields first");

return false;

}

csv = f + "," + m + "," + l + "," + a;

// Ok, so now we retrieve the response as in all the other examples,

// except that now we append the CSV onto the URL as a query string,

// being sure to escape it first.

retrieveURL("example5Submit.do?csv=" + escape(csv));

}



function retrieveURL(url) {

if (window.XMLHttpRequest) { // Non-IE browsers

req = new XMLHttpRequest();

req.onreadystatechange = processStateChange;

try {

req.open("GET", url, true);

} catch (e) {

alert(e);

}

req.send(null);

} else if (window.ActiveXObject) { // IE

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

if (req) {

req.onreadystatechange = processStateChange;

req.open("GET", url, true);

req.send();

}

}

}



function processStateChange() {

if (req.readyState == 4) { // Complete

if (req.status == 200) { // OK response

document.getElementById("theResponse").innerHTML = req.responseText;

} else {

alert("Problem: " + req.statusText);

}

}

}


在这个例子中,我们只是简单地用用户的输入创建了一个以逗号分割的字符串。你当然可以创建一个XML文档然后提交,事实上那是更常见的情况。但是这正是我不想那样做的一部分原因:我想告诉读者你并不一定非要使用XMLHttpRequest对象来传输XML。就本例而言,除了将一个CSV字符串添加到URL之外并没有做任何事情。在网上有不计其数的例子演示了如何创建XML文档并使用XMLHttpRequest.send()方法提交,我强烈推荐你阅读相关文档,当然,如果你使用这种方法的话。

我希望这篇简短的文章和附加的例子可以给你一个好的研究XMLHttpRequest对象的起点。在结束之前我还想说AJAX概念本身并不强制你使用XMLHttpRequest对象,你可以使用其他方法得到相同的效果,比如代替XMLHttpRequest的隐藏frame,这正是我在本文开头提到的在五年前的那个项目中采用的方法。然而,XMLHttpRequest的确使得AJAX概念更容易实现,而且更标准。请参见Google研究这种技术的强大之处。

但是,我提醒所有认为全部的web应用都应该用这种方法开发的人,我不认为这是web开发的不二法门。在某些情况下它是一个好的方案,但在其他情况下不是。如果获得尽可能多的浏览者是你的目标,你最好放弃这种方案。如果一个用户取消了浏览器的脚本解释功能(而你的网站除了这又没有其他出彩的地方),这就不是一个好的情况。还有其他AJAX不适用之处,但是你完全可以把它当成你工具箱中的一个普通工具:它适合某些工作,不适合其他工作。毕竟,你不能指望用一个胶水枪钉钉子吧?

到此为止,我希望本文已经带给了你进一步思考的食粮,尽情享用吧!
示例应用: http://www.omnytex.com/articles/xhrstruts/xhrstruts.zip

本文的英文版本:http://www.omnytex.com/articles/xhrstruts/

本文的PDF版本: http://www.omnytex.com/articles/xhrstruts/xhrstruts.pdf


转自:http://www.neeao.com/blog/article-852.html
分享到:
评论

相关推荐

    Ajax using XMLHttpRequest and Struts

    ajax和struts的结合应用

    struts-ajax.rar_ajax struts _struts ajax_struts ajax war

    struts与ajax结合的例子 Ajax打破了使用页面重载的惯例技术组合,使用XMLHttpRequest对象进行异步数据读取,完成了浏览器和服务器之间的异步通信

    北京中科信软AJAX培训

    jax概述 Ajax的定义 Web应用程序的解决方案 Ajax的工作方式 基于各种Web解决方案的Ajax技术选择路线 ...利用DWR实现常见的Ajax功能 DWR异常处理 DWR开发常见问题解决 和现有Web框架Struts的集成 和Hibernate框架的集成

    Ajax中responseText返回的是一个页面而不是一个值

    自己在struts2中的写好了业务逻辑用response返回的内容却是... 您可能感兴趣的文章:ajax的responseText乱码的问题的解决方法jquery ajax学习笔记2 使用XMLHttpRequest对象的responseXMLAjax request response 乱码解决

    ajax利用json在struts2.0中的使用

    支持struts2自带的dojo提交功能和自己写的XMLHttpRequest

    Ajax与Java高级程序设计(英文版)

    本书重点介绍与Java相关的Ajax工具和技术,主要内容包括XMLHttpRequest对象,JavaScript编辑器、格式器和混淆器,快速开发Ajax应用所使用的Dojo、Prototype、script.aculo.us、Taconite和Yahoo!库等框架和工具包,...

    java web技术开发大全(最全最新)

    《Java Web开发技术大全:JSP+Servlet+Struts+Hibernate+Spring+Ajax》重点讲解了Struts 2、Speing和HIbernate框架的基础知识和高级技术,如Sruts 2中的*、类型转换、国际化和标签等,HIbe rna{e的会话、0/R映射和...

    java web开发技术大全

    《Java Web开发技术大全:JSP+Servlet+Struts+Hibernate+Spring+Ajax》重点讲解了Struts 2、Speing和HIbernate框架的基础知识和高级技术,如Sruts 2中的*、类型转换、国际化和标签等,HIbe rna{e的会话、0/R映射和...

    Extjs ajax同步请求时post方式参数发送方式

    ajax同步请求一般下面这样: 代码如下: var conn = Ext.lib.Ajax.getConnectionObject().conn; conn.open(“POST”, ‘http://localhost:8080/struts2study/TreeDDGet?node=-1’,false); // 这里的conn对象其实就是 ...

    java-ee电子商城系统课程设计.doc

    Struts 是目前创建Web 应用最常用的表现层MVC 框架实现,基于Model2 的Struts 框架利用控制器和定制标签库将应用中的模型和视图分离,达到了层间松散耦合的效果 ,同时提高系统的灵活性、重用性和维护性。...

    千方百计笔试题大全

    165、AJAX应用和传统Web应用有什么不同? 38 166、如何用JQuery进行表单验证? 39 167、Prototype如何实现页面局部定时刷新? 40 168、Prototype如何为一个Ajax添加一个参数? 40 169、Ajax请求总共有多少种Callback...

    java面试宝典

    165、AJAX应用和传统Web应用有什么不同? 38 166、如何用JQuery进行表单验证? 39 167、Prototype如何实现页面局部定时刷新? 40 168、Prototype如何为一个Ajax添加一个参数? 40 169、Ajax请求总共有多少种Callback...

    整理后java开发全套达内学习笔记(含练习)

    implements (关键字) 实现 ['implimәnt] import (关键字) 引入(进口,输入) Info n.信息 (information [,infә'meiʃәn] ) Inheritance [java] 继承 [in'heritәns] (遗传,遗产) initialize 预置 初始化 [i'ni...

    基于J2EE框架的个人博客系统项目毕业设计论文(源码和论文)

    2、 Ajax我们主要应用就是xmlhttprequest,回调函数实现局部刷新达道数据更新! 4.2需求分析 Blog网站主要是实现注册用户登录、管理相关信息、博文及相关评论、查看留言、友情链接、及图片的上传和图像的播放而为...

    J2EE应用开发详解

    124 8.5.2 拦截器的实现原理 124 8.5.3 Struts2的内置拦截器 124 8.5.4 拦截器的配置和使用 125 8.5.5 自定义拦截器 126 8.6 一个简单的Struts2应用 130 8.7 小结 140 第9章 JSF 141 9.1 JSF技术简介 141 9.1.1 JSF...

    java学习阶段所有的API帮助文档

    有java api中英文版,Ajax_XMLHttpRequest帮助文档,Apache+Ant+1.7,Comm2.0_参考手册,DHTML_网页制作完全手册_中文,DHTML文档对象模型中文手册,DOS_练就高手,Hibernate3.1.2_帮助文档_中文,Hibernate3.2_帮助...

    基于J2EE框架的个人博客系统项目毕业设计论...

    2、 Ajax我们主要应用就是xmlhttprequest,回调函数实现局部刷新达道数据更新! 4.2需求分析 Blog网站主要是实现注册用户登录、管理相关信息、博文及相关评论、查看留言、友情链接、及图片的上传和图像的播放而为...

Global site tag (gtag.js) - Google Analytics