请选择 进入手机版 | 继续访问电脑版

技术_方法_掌握技术,成就未来-6miu百度云

 找回密码
 立即注册
查看: 9|回复: 0

AJAX从服务端获取数据的三种方法

[复制链接]

329万

主题

329万

帖子

988万

积分

论坛元老

Rank: 8Rank: 8

积分
9889035
发表于 2021-1-4 13:17:41 | 显示全部楼层 |阅读模式
原文地址:http://www.blogjava.net/nokiaguy/archive/2008/05/25/202795.html

在本文中将给出一个例子来介绍使用AJAX技术从服务端获得数据的三种方法。这个例子很简单,就是两个选择框(html中的标签),通过选中第一个select的某一项后,会从服务端得到一些数据,并加载到第2个select中。

方法一、从服务端获得XML格式的数据

从服务端获得数据的最容易想到的方法就是在服务端反加一定格式的数据,一般是XML格式,然后在服务端使用XMLDocument或其他技术来读取这些数据,并生成标签中选项的格式文本(标签)。下面的addOptions函数是这个例子的核心函数,它负责根据从服务端获得的数据生成标签中的标签。在这里所使用的方法是利用了标签的innerHTML属性(仅限于firefox),如果是IE,要使用outerHTML属性(IE中标签的innerHTML属性有一些小bug,读者可以试着在IE中使用innerHTML属性,看看会发生什么情况)。addOptions方法的实现代码如下:// select表示对象,xml表示XMLDocument对象function addOptions(select, xml){        if(select)    {        var options = "";        for(var i = 0; i  xml.childNodes[0].childNodes.length ; i++)        {              if(xml.childNodes[0].childNodes[i].nodeName == "list")            {                var s = "";                if(isIE())                                   s = xml.childNodes[0].childNodes[i].text;                         else                    s = xml.childNodes[0].childNodes[i].textContent                options += "" + s + "'>" ;                options += s;                options += ""            }        }                    var id = select.id;        if(isIE())            select.outerHTML = "" + id + "' οnchange='onChange(this)'>" + options + "";        else            select.innerHTML = options;                            }}

    onReadState函数将在XMLHttpRequest对象的异步访问服务端时调用。当readyState为4时表示成功从服务端返回XML数据。这个函数的实现代码如下:



//
  myRequest表示XMLHttpRequest对象,selectId表示标签的id属性值

function
  onReadyState(myRequest, selectId) {     
if
(myRequest.readyState
==
  
4
)   
//
  4表示成功获得相应信息

     {                     
try
         {            
var
  xml
=
  myRequest.responseXML;   
//
  获得XMLDocument对象      

            
var
  kind
=
  document.getElementById(selectId);
//
  获得对象

             addOptions(kind, xml);  
//
  向标签中加入标签

         }        
catch
(e)        {            alert(
"
onReadyState:
"
  
+
  e);        }    }}


    getData函数负责向服务端发送请求,并设置异步事件。实现代码如下:


function
  getData(url, selectId){   
var
  myRequest
=
  getXMLHTTPRequest();  
//
  获得一个XMLHttpRequest对象

         
if
(myRequest)    {        myRequest.onreadystatechange
=
   
function
()
//
  接收获得数据状态的事件函数

         {                                    onReadyState(myRequest, selectId);          }                 
try
          {            myRequest.open(
"
post
"
, url,
true
);                    }        
catch
(e)        {            alert(e);        }         
try
         {            myRequest.send(
""
);          }        
catch
(e)        {            alert(e);        }      }}


   现在本例子的核心代码已经实现完成,下一步就是在html而加载时从服务端获得第1个标签的数据,并将其加载到第1个标签中。让我们先看一下这个静态的html代码。



DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
>


html
>
     

head
>
         

title
>
title
>
         

meta
http-equiv
="Content-Type"
  content
="text/html; charset=UTF-8"
>
         

script
type
="text/javascript"
  src
="myscript.js"
>
         

script
>
     

head
>
     

body
>
         

select
id
="bigKind"
  onchange
="onChange(this)"
  
>
                     

select
>
         

select
id
="smallKind"
  
>
                    

select
>
     

body
>


html
>


      从上面代码可以看出,这两个标签分别是bigKind和smallKind,里面并没有标签,这是因为标签要在javascript里动态加载。下面我们先来加载bigKind中的数据。


window.onload
=
  onLoad
function
  onLoad(){                             
try
     {        getData(
"
../GetXML
"
,
"
bigKind
"
);                   }   
catch
(e)    {        alert(
"
onLoad:
"
  
+
  e);    }}

     其中GetXML是一个Servlet程序(读者可以将其换成其他的服务端程序,如asp.net、php的)。下面是这个GetXML程序的实现代码:


package
  servlet;
import
  java.io.
*
;
import
  javax.servlet.
*
;
import
  javax.servlet.http.
*
;
import
  database.MyData;
public
  
class
  GetXML
extends
  HttpServlet{   
protected
  
void
  processRequest(HttpServletRequest request, HttpServletResponse response)            
throws
  ServletException, IOException    {        response.setContentType(
"
application/xml;charset=UTF-8
"
);        PrintWriter out
=
  response.getWriter();        
try
         {            String s
=
  request.getParameter(
"
kind
"
);            out.println(
"

"
);            
if
  (s
==
  
null
)            {               
for
  (String key : MyData.data.keySet())                {                    out.println(
"

"
  
+
  key
+
  
"

"
);                }            }
else
             {                s
=
  java.net.URLDecoder.decode(s,
"
UTF-8
"
);                System.out.println(s);                java.util.List

String
>
  smallKind
=
  MyData.data.get(s);               
if
  (smallKind
!=
  
null
)                {                    
for
  (String kind : smallKind)                    {                        out.println(
"

"
  
+
  kind
+
  
"

"
);                    }                }            }            out.println(
"

"
);        }
finally
         {            out.close();        }    }   
protected
  
void
  doGet(HttpServletRequest request, HttpServletResponse response)            
throws
  ServletException, IOException    {        processRequest(request, response);    }   
protected
  
void
  doPost(HttpServletRequest request, HttpServletResponse response)            
throws
  ServletException, IOException    {        processRequest(request, response);    }   
public
  String getServletInfo()    {        
return
  
"
Short description
"
;    }}

  

   不管读者会不会java和servlet,从这个程序中的processRequest方法中都可以看出,首先会获得请求参数kind,如果这个参数不存在,则返回bigKind所需要的数据,以xml格式返回,类似于如下的格式:



data
>
   

list
>
data1

list
>
   

list
>
data2

list
>


data
>


    如果kind参数存在,则在MyData.data中查询第2个标签(smallKind)所需要的数据。data是一个Map类型。为了方便起见,本例子并未使用数据库,而是在MyData类中定义了一个静态的Map类型变量。MyData的实现代码如下:


package
  database;
import
  java.util.
*
;
public
  
class
  MyData {   
public
  
static
  Map

String, List

String
>>
  data;        
static
  {                data
=
  
new
  HashMap

String, List

String
>>
();                List

String
>
  eProducts
=
  
new
  LinkedList

String
>
();        eProducts.add(
"
手机
"
);        eProducts.add(
"
数码/IT
"
);        eProducts.add(
"
家电
"
);        eProducts.add(
"
电脑
"
);                        data.put(
"
消费电子
"
, eProducts);                List

String
>
  goods
=
  
new
  LinkedList

String
>
();                goods.add(
"
化妆
"
);        goods.add(
"
健康
"
);        goods.add(
"
玩具
"
);        goods.add(
"
办公/文体
"
);        goods.add(
"
童装童鞋
"
);        goods.add(
"
其他
"
);                data.put(
"
日用百货
"
, goods);                List

String
>
  books
=
  
new
  LinkedList

String
>
();                books.add(
"
小说
"
);        books.add(
"
动漫
"
);         books.add(
"
经济
"
);        books.add(
"
法律
"
);        books.add(
"
计算机
"
);        books.add(
"
英语
"
);        books.add(
"
通讯
"
);        books.add(
"
其他
"
);                data.put(
"
图书
"
, books)        ;                            }}

    其中data变量中的key值就是bigKind中的值,而每一个key对应的值(一个List对象就是smallKind中值的列表)。下面我们来实现当第1个标签bigKind变化时,更新smallKind标签。的onchange事件函数的代码如下:


function
  onChange(obj){   
try
     {        getData(encodeURI(encodeURI(
"
../GetXML?kind=
"
  
+
obj.options[obj.selectedIndex].value)),
"
smallKind
"
);         }   
catch
(e)    {        alert(e);    }}



    这个函数是标签的onchange事件函数。obj表示标签本身。这个函数中只有一条有实际意义的语句,也就是调用了getData方法,这个方法人在onLoad方法中调用getData时差不多,只是在传送url时使用了两个encodeURI方法。由于XMLHttpRequest方法以utf-8向服务端发送数据,因此,要使用两个encodeURI向服务端发送%xx形式的utf-8编码,然后在服务端进行解析。我们在GetXML中的processRequest方法中可以找到如下的一条语句:


s
=
  java.net.URLDecoder.decode(s,
"
UTF-8
"
);


    就是进行解码操作。

    注:如果在IE中,客户端可以不使用encodeURI对带中文的URL进行编码,服务端也不用解码。在服务端仍然可以正常显示中文。但在firefox中就必须要进行编码和解码。因此,要想跨浏览器,就需要使用本文所述的方法。

方法二、直接获得...内容的字符串

    上面的获得数据的方法是从服务端获得了一个XML文档,并转换成XMLDocument对象,然后解析。这种方法虽然很好,但是操作XMLDocument对象还是有些麻烦,因此,我们可以在服务端直接反回标签所需要的标签字符串,然后将这些字符串传给对象的innerHTML或outerHTML就可以了。服务端的代码和上面的实现代码类似,只需要将去掉,然后将改为后,并使用如下的语句来设置ContentType:

response.setContentType("text/html;charset=UTF-8");

客户端可通过XMLHttpRequest对象的responseText属性获得这些含有的文本,并将其赋给innerHTML或outerHTML属性。这种方法虽然很方便,但并不灵活。如果客户端不使用标签,而是使用[table]或其他的标签显示数据,那么返回的这些数据就没什么用处了。而即方便,又灵活的应该是下面要介绍的方法。

方法三、从服务端返回javascript代码,在客户端使用eval函数执行

    我们可以在服务端返回类似于如下的字符串:

    var options = new Array();

    options.push(‘data1’);

    options.push(‘data2’);

    然后使用eval函数执行上面的字符串,这样我们在javascript中就可以使用options数组了。我个人认为,使用数组要比使用XMLDocument更容易,代码量也更少。如果要返回更为复杂的数据,也可以使用javascript中的类或其他数据结构。根据上面的思想,新的processRequest方法的代码如下:


     
protected
  
void
  processRequest(HttpServletRequest request, HttpServletResponse response)            
throws
  ServletException, IOException    {        response.setContentType(
"
text/html;charset=UTF-8
"
);        PrintWriter out
=
  response.getWriter();        out.println(
"
var options = new Array();
"
);        
try
          {            String s
=
  request.getParameter(
"
kind
"
);            
if
  (s
==
  
null
)            {                                
for
  (String key : MyData.data.keySet())                {                    out.println(
"
options.push('
"
  
+
  key
+
  
"
');
"
);                }            }
else
             {                s
=
  java.net.URLDecoder.decode(s,
"
UTF-8
"
);                System.out.println(s);                java.util.List

String
>
  smallKind
=
  MyData.data.get(s);               
if
  (smallKind
!=
  
null
)                {                    
for
  (String kind : smallKind)                    {                        out.println(
"
options.push('
"
  
+
  kind
+
  
"
');
"
);                    }                }            }        }
finally
         {            out.close();        }    }


    客户端经过改进的addOptions函数如下:


//
  javascript表示从服务端返回的javascript代码字符串

function
  addOptions(select, javascript){        
if
(select)    {           
if
(select.id
==
  
"
smallKind
"
)        {            
if
(isIE())                select.options.length
=
  
0
;         }        
var
  myOptions
=
  
""
;        eval(javascript);  
//
执行从服务端返回的javascript代码

         
for
(
var
  i
=
  
0
; i

  options.length ; i
++
)  
//
  从options数组中取数据

         {                        
var
  s
=
  
""
;            
if
(isIE())             {                                select.options[select.options.length]
=
  
new
  Option(options[i], options[i]);            }            
else
             {                           myOptions
+=
  
"

"
  
+
  options[i]
+
  
"
'>
"
  ;                myOptions
+=
  options[i];                myOptions
+=
  
"

"
             }        }    }           
var
  id
=
  select.id;   
if
(
!
isIE())            select.innerHTML
=
   myOptions;           }


    在上面的addOptions方法中还有一个不同是在IE中使用了对象的options数组来添加选择项,而不是使用outerHTML。这么做的好处是可以在onLoad方法中就获得的选项值。而如果使用outerHTML在html未装载完时,标签中选择项仍然为0。这样在onLoad方法中就无法访问中的被加入项了,当然,在onchange事件中可以。

    在firefox中使用innerHTML时,在html未装载完时,只要标签被装载完(也就是调用了addOptions方法后),就可以访问标签中的了。个人感觉这一点要从IE做得好。顺便说一句,笔者使用的是IE6,不知道ie7会是什么效果。如果哪位试过,可以跟贴。图1是本例的效果图。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|技术_方法_掌握技术,成就未来-6miu百度云

GMT+8, 2021-1-28 16:36 , Processed in 0.059077 second(s), 19 queries .

合作伙伴:

盘搜搜 / 百度云搜索 / 盘多多 / 如风搜 / 小说阅读网 / 笔趣阁 / 文库 / 学术 / 小说排行榜 / 专利网 / 专利查询 / 网盘搜索 / 网盘 / 问医生 / 健康网 / APP开发 / 金蝶 / 软件定制 / 软件开发 / 教育app / ERP系统 / SAP / 分销系统 / 成都软件开发 / 小程序开发 / ERP / WMS / MES / LIMS / SCADA / PLM / PDM / 希沃 / SEEWO / OTO / O2O / 培训系统 / 在线问诊 / 在线问诊系统 / 医疗咨询系统 / 网店代运营 / 返利网 / 京东代运营 / 斯特封 / trelleborg / NOK / 斯凯孚 / SKF / 圣戈班 / Saint-Gobain / 派克汉尼汾 / parker / 洪格尔 / hunger / Merkel / 密封圈 /
快速回复 返回顶部 返回列表