服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 核心技术 > 查看文档

在struts应用中施展ajax魔法

  本文将介绍在jsp页面中包含一些javascript这样一个简单而有效的方法来结合ajax和struts。在此我们介绍如何重新使用已经存在的struts actions,但此技术同样可用于你选择的其他java-web 框架。本方法同样可平移到struts或者jsf的下一个版本。

  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的机制在其他地方已经有详细的说明?d?d请查看本文后的resources来获取更多。但是你至少需要知道:

  •   1. xmlhttprequest (如果你使用的是ie浏览器的话,则是microsoft.xmlhttp的activex的对象)。这些对象,你可以在web页面中使用javascript调用。他们允许你作为后台的调用方式来请求web服务器的内容(例如,在表单提交后,屏幕并不像平时一样显示“空白”)。
  •   2. xmlhttprequest 和microsoft.xmlhttp 返回的内容可以作为xml或者文本来处理。javascript(在你页面上的)可以使用请求的新内容来更新页面。
  •   3. 整个处理过程可以由普通的javascript事件来触发:onclick,onchange,onblur,等。

  在你的struts应用中使用ajax

  你阅读了本文,然后你会对使用ajax来创建动态的web页面感兴趣,并且想知道如何将它加入到你的struts应用中。这只是选择之一。那么你会如何选择呢?

  •   ? 等待,知道struts的下一个版本融合了ajax技术。如果struts开发者准备开发一个新的应用,这或许会是一个好的选择。再后面,可能会是要求jsf也这样做?d?d对其本身并不一件坏事,但是对于已经存在的系统这将会带来最根本的改变。
  •   ? 你也可以直接采用新的方法,比如direct web remoting (dwr) 和ruby on rails,这些都是专为建立ajax应用的。如果你考虑不使用struts来开发web的话,那么这些都是很又用的框架,并且值得一试。但是,这也同时意味着你必须要重写你的应用。
  •   ? 在你已经存在的struts应用中增加ajax。既然ajax只是一项技术而并非框架,那么它就很容易融入到struts中。作为现有的系统,其稳定性(如,保持现有的库文件)是相当重要的。所以这个方法被推荐,并且我们将在后面详细介绍。

  我们选择在struts应用中增加ajax的优势是:

  •   1. 它并不需要任何新的库文件或者服务器代码;只需要使用现有的struts库文件和action。
  •   2. 解决方案中所有部分?d?djavascript,xml,java和struts?d?d早已为广泛所知。
  •   3. 此应用可以一块一块地移植到ajax;我们可以确定哪些部分对用户有益,并首先将它们更新到动态ajax显示。

  实现方案

  我们如何真正的贯彻我们的选择呢?我们首先应该注意一个“标准的”(没有ajax)struts应用是如何工作的。在此应用中,一个一般的事件流程如下:

  •   1. 使用点击超链接或者表单的提交按钮,用户发送请求。
  •   2. web服务器运行处理请求的struts action来生成一个web页面。
  •   3. 浏览器显示web页面。
  •   4. 当用户点击保存的时候,信息由struts框架中一个actionform类来转换并发送到服务器。
  •   5. 然后,struts框架调用struts action来出来请求(如,保存数据到数据库中)。
  •   6. 页面再一次回传,处理流程继续。

  现有的struts应用

  一个演示事件流程的简单struts应用可以在以下地址下载: struts-non-ajax.zip。此基于struts的应用,是基于用户的输入显示或者隐藏蓝色和绿色的表格。图1显示了载入初始页面的画面。图2显示了用户输入值并点击了提交后的画面。虽然简单,但它已经足以表示一个struts的工作流程。

  图 1. 没有ajax的例子:初始屏幕

  图 2. 没有ajax的例子:输入值并点击了提交

  服务器端的代码是:一个struts action使用struts-config.xml 中定义的值转发到(相同的)jsp。这个例子代码中一些需要注意的地方是:

  •   ?struts-config.xml文件将所有的请求重定向到http://localhost:8080/struts-non-ajax/(或者和你自己的服务器相同)的index.jsp。
  •   ? index.jsp 包含了一个两个文本框的struts form(showblue和showgreen)。该页面同样包含了标签,但是如同两个文本框被初始化为空,标签之间的内容并不显示。
  •   ? 用户输入值(true或者false)并点击提交按钮,处理控制(经过struts框架,读取struts-config.xml)提交到sampleaction类中。
  •   ?sampleaction记录下值,然后转发到index.jsp。一个成熟的struts应用可能会处理更多的事情,不如保存或者查询数据库等。
  •   ? index.jsp 现在重新处理请求;如果showblue或者showgreen的值是true,这些表格就显示出来。

  该应用并没有任何“错误”。类似的struts项目好多年都是这样做的。但是,我们如何在不添加复杂的javascript或者频繁的表单提交的前提下,为此应用增加动态的元素呢?

  我们的第一个struts ajax应用

  观察下下面的图3和图4。第一眼看上去,它们和前面的例子没有说明区别。它们的不同之处在于,页面载入后(图3)然后文本框中的值改变了,窗体自动提交而不显示空白的,然后在图4中显示结果。普通的提交按钮仍然在,你也可以选择使用它。

  图 3. 页面载入后的ajax例子

  图 4. ajax调用后的ajax例子

  添加ajax是出奇的容易。服务器端的代码和前面的例子是一样的: 一个struts的actionform来后去数据,一个struts的action来执行需要的任务(例如,存储数据库)然后转发到适当的jsp页面来显示结果。

  继续

  如果你希望就此停止阅读(跳过这个例子的工作说明),但是这里的是和你需要转换你的struts应用到一个struts-ajax应用同样的风格:

  •   1. 在你的web页面中引入一个ajax.js (该文件是struts-ajax.zip 例文件中的一部分)。ajax.js 包含了所有需要发送和接收ajax调用的javascript方法。
  •   2. 确保你希望在ajax调用中更新的web页面的部分包含在标签中,并且给每个标签一个id。
  •   3. 当一些事件触发的时候就更新页面(例如,文本框的the onchange()方法),调用retrieveurl()方法,通过url传递到需要执行服务器端处理的struts action。
  •   4. 为了页面的显示/更新,最简单的方法是struts action转发回同样的页面。在本例中,showgreen/showblue 文本框中的onchange()方法来触发ajax调用。

  javascript方法retrieveurl()调用服务器的struts(通过url),获取jsp响应,然后更新显示页面中的 标签中的部分。就是这么简单!

  ajax解决方案的细节

  我们将例子变为ajax-struts应用的时候,需要三个变化:

  •   1. 增加一个javascript方法来完成到服务器的“背后的”ajax调用。
  •   2. 增加javascript代码来接收服务器的响应并更新页面。
  •   3. 在jsp页面增加标签标签,这个标签中内容将在ajax调用中更新。

  我们将详细的说明上面的每一步。

  发送ajax请求到服务器

  有两个方法(在下面列出)用于发送请求到服务器。

  ? 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转换成字符串
url=url+getformasstring(nameofformtopost);

//调用ajax
if (window.xmlhttprequest) {

// 非ie浏览器
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

req = new activexobject("microsoft.xmlhttp");
if (req) {
req.onreadystatechange=processstatechange;
req.open("get", url, true);
req.send();
}
}
}

getformasstring() 是一个“私有” 方法,在retrieveurl()中使用。

function getformasstring(formname){

//设置返回字符串
returnstring ="";

//取得表单的值
formelements=document.forms[formname].elements;

//循环数组,组装url
//像'/strutsaction.do&name=value'这样的格式

for(var i=formelements.length-1;i>=0; --i ){
//转化每一个值
returnstring+="&"
+escape(formelements[i].name)+"="
+escape(formelements[i].value);
}

//返回字符串
return returnstring;
}

  根据ajax的响应更新web页面

  到现在为止,我们学习过了使用javascript来完成ajax调用(前面列出),struts action,actionform以及jsp(基本没有变化,只是增加了标签)。为了完善我们对struts-ajax项目的了解,我们需要了解三个用于根据服务器返回的结果而更新页面的javascript方法。

  •   ? processstatechange(): 该方法在ajax调用前设定。它在服务器响应到达后由xmlhttprequest/microsoft.xmlhttp 对象调用。
  •   ?splittextintospan(): 根据响应,循环取出数组中的元素组装成newcontent。
  •   ?replaceexistingwithnewhtml(): 根据span元素数组,循环搜索,将里面的元素调换掉页面中和它的'somename'相同的中的内容。注意,我们使用的是req.responsetext 方法来获得返回的内容(它允许我们操作任何文本的响应)。与此相对于的是req.responsexml (它的作用更大,但是要求服务器返回是xhtml或者xml)。

function processstatechange() {

if (req.readystate == 4) { // 完成
if (req.status == 200) { // 响应正常

//将响应的文本分割成span元素
spanelements =
splittextintospan(req.responsetext);

//使用这些span元素更新页面
replaceexistingwithnewhtml(spanelements);

} else {
alert("problem with server response:\n "
+ req.statustext);
}
}
}
replaceexistingwithnewhtml() 是为processstatechange()使用的“私有”方法。

function replaceexistingwithnewhtml
(newtextelements){

//循环newtextelements
for(var i=newtextelements.length-1;i>=0;--i){

//判断是否以 if(newtextelements[i].
indexof("-1){

//获得span的名字- 设置在第一和第二个引号之间
//确认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);

//现在更新现有的document中的元素,
// 确保文档存在该元素
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){

//删除掉第一个span后面的元素
spanpos = returnelements[i].
indexof("

//如果找到匹配的,获得span前的内容
if(spanpos>0){
substring=returnelements[i].
substring(spanpos);
returnelements[i]=substring;
}
}
return returnelements;
}

  新的控制流

  添加以下的javascript代码到我们的应用中,以下的步骤将在服务器和浏览器中执行。

  •   1. 如同一个普通struts应用装载页面。
  •   2. 用户改变文本框的值,触发一个onchange() 事件,调用retrieveurl() 方法。
  •   3. 该javascript方法通过发送struts明白的表单变量(后台)请求到服务器的struts action。
  •   4. 该javascript方法同样设定了第二个javascript方法的名字,此方法将到服务器响应完毕后调用。本例子中,设定为processstatechange() 方法。
  •   5. 如我们所预期的,服务器响应完毕,调用processstatechange() 方法。
  •   6. 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应用。

版权声明:techtarget获matrix授权发布,如需转载请联系matrix
作者:作者:paul browne;pawenwen(作者的blog:http://blog.matrix.org.cn/page/pawenwen)
译文:点击

扫描关注微信公众号