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

简介:
在本文中将给出一个例子来介绍使用AJAX 技术从服务端获得数据的三种方法。这个例子很简单,就是两个选择框(html 中的<select> 标签),通过选中第一个select 的某一项后,会从服务端得到一些数据,并加载到第2 select 中。
方法一、从服务端获得XML 格式的数据
从服务端获得数据的最容易想到的方法就是在服务端反加一定格式的数据,一般是XML 格式,然后在服务端使用XMLDocument 或其他技术来读取这些数据,并生成<select> 标签中选项的格式文本(<option> 标签)。下面的addOptions 函数是这个例子的核心函数,它负责根据从服务端获得的数据生成<select> 标签中的<option> 标签。在这里所使用的方法是利用了<select> 标签的innerHTML 属性( 仅限于firefox) ,如果是IE ,要使用outerHTML 属性(IE <select> 标签的innerHTML 属性有一些小bug ,读者可以试着在IE 中使用innerHTML 属性,看看会发生什么情况)。addOptions 方法的实现代码如下:

//  select表示<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 
+=   " <option value=' "   +  s  +   " '> "  ;
                options 
+=  s;
                options 
+=   " </option> "
            }
        }
            
        
var  id  =  select.id;
        
if (isIE())
            select.outerHTML 
=   " <SELECT id=' "   +  id  +   " ' onchange='onChange(this)'> "   +  options  +   " </SELECT> " ;
        
else
            select.innerHTML 
=  options;                
        
    }
}

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

//  myRequest表示XMLHttpRequest对象,selectId表示<select>标签的id属性值
function  onReadyState(myRequest, selectId) 

    
if (myRequest.readyState  ==   4 )    //  4表示成功获得相应信息
    {              
        
try
        {
            
var  xml  =  myRequest.responseXML;    //  获得XMLDocument对象      
             var  kind  =  document.getElementById(selectId);  //  获得<select>对象
            addOptions(kind, xml);   //  向<select>标签中加入<option>标签
        }
        
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 <select> 标签的数据,并将其加载到第1 <select> 标签中。让我们先看一下这个静态的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 >

    从上面代码可以看出,这两个<select> 标签分别是bigKind smallKind ,里面并没有<option> 标签,这是因为<option> 标签要在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(
" <data> " );
            
if  (s  ==   null )
            {
                
for  (String key : MyData.data.keySet())
                {
                    out.println(
" <list> "   +  key  +   " </list> " );
                }
            } 
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(
" <list> "   +  kind  +   " </list> " );
                    }
                }
            }
            out.println(
" </data> " );

        } 
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 <select> 标签 (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<String> 对象就是 smallKind 中值的列表)。下面我们来实现当第 1 <select> 标签 bigKind 变化时,更新 smallKind 标签。<select>的onchange事件函数的代码如下:

function  onChange(obj)
{
    
try
    {
        getData(encodeURI(encodeURI(
" ../GetXML?kind= "   + obj.options[obj.selectedIndex].value)),  " smallKind " );
     
    }
    
catch (e)
    {
        alert(e);
    }
}
     这个函数是<select> 标签的onchange 事件函数。obj 表示<select> 标签本身。这个函数中只有一条有实际意义的语句,也就是调用了getData 方法,这个方法人在onLoad 方法中调用getData 时差不多,只是在传送url 时使用了两个encodeURI 方法。由于XMLHttpRequest 方法以utf-8 向服务端发送数据,因此,要使用两个encodeURI 向服务端发送%xx 形式的utf-8 编码,然后在服务端进行解析。我们在GetXML 中的processRequest 方法中可以找到如下的一条语句:

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

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

方法二、直接获得<option>...</option> 内容的字符串
     上面的获得数据的方法是从服务端获得了一个XML 文档,并转换成XMLDocument 对象,然后解析。这种方法虽然很好,但是操作XMLDocument 对象还是有些麻烦,因此,我们可以在服务端直接反回<select> 标签所需要的<option> 标签字符串,然后将这些字符串传给<select> 对象的innerHTML outerHTML 就可以了。服务端的代码和上面的实现代码类似,只需要将<data> 去掉,然后将<list> 改为<option> 后,并使用如下的语句来设置ContentType
response.setContentType("text/html;charset=UTF-8");
客户端可通过XMLHttpRequest 对象的responseText 属性获得这些含有<option> 的文本,并将其赋给innerHTML outerHTML 属性。这种方法虽然很方便,但并不灵活。如果客户端不使用<select> 标签,而是使用<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 
+=   " <option value=' "   +  options[i]  +   " '> "  ;
                myOptions 
+=  options[i];
                myOptions 
+=   " </option> "
            }
        }
    }
       
    
var  id  =  select.id;
    
if ( ! isIE())    
        select.innerHTML 
=   myOptions;           
}

     在上面的addOptions 方法中还有一个不同是在IE 中使用了<select> 对象的options 数组来添加选择项,而不是使用outerHTML 。这么做的好处是可以在onLoad 方法中就获得<select> 的选项值。而如果使用outerHTML html 未装载完时,<select> 标签中选择项仍然为0 。这样在onLoad 方法中就无法访问<select> 中的被加入项了,当然,在onchange 事件中可以。 
     firefox 中使用innerHTML 时,在html 未装载完时,只要<select> 标签被装载完(也就是调用了addOptions 方法后),就可以访问<select> 标签中的<option> 了。个人感觉这一点要从IE 做得好。顺便说一句,笔者使用的是IE6 ,不知道ie7 会是什么效果。如果哪位试过,可以跟贴。图1是本例的效果图







 本文转自 androidguy 51CTO博客,原文链接:http://blog.51cto.com/androidguy/215038,如需转载请自行联系原作者

相关文章
|
16天前
|
JavaScript 前端开发 容器
AJAX载入外部JS文件到页面并让其执行的方法(附源码)
AJAX载入外部JS文件到页面并让其执行的方法(附源码)
17 0
|
1月前
|
Web App开发 JSON 前端开发
Ajax实现动态及时刷新表格数据
Ajax实现动态及时刷新表格数据
34 1
|
4月前
|
JSON 前端开发 Java
利用Spring Boot处理JSON数据实战(包括jQuery,html,ajax)附源码 超详细
利用Spring Boot处理JSON数据实战(包括jQuery,html,ajax)附源码 超详细
60 0
|
2月前
|
XML 机器学习/深度学习 JSON
在火狐浏览器调ajax获取json数据时,控制台提示“XML 解析错误:格式不佳”。
在火狐浏览器调ajax获取json数据时,控制台提示“XML 解析错误:格式不佳”。
29 0
在火狐浏览器调ajax获取json数据时,控制台提示“XML 解析错误:格式不佳”。
|
1月前
|
JSON 前端开发 数据格式
Ajax传递json数据
Ajax传递json数据
11 0
|
1月前
|
前端开发
AJAX发送请求方法封装和请求函数底层刨析以及axios二次封装
AJAX发送请求方法封装和请求函数底层刨析以及axios二次封装
|
1月前
|
移动开发 前端开发 安全
Ajax跨域的所有方法(最详细带使用教程!!!)
Ajax跨域的所有方法(最详细带使用教程!!!)
|
2月前
|
数据采集 Web App开发 前端开发
Python爬虫之Ajax分析方法与结果提取#6
Ajax分析方法、Ajax结果提取【2月更文挑战第20天】
37 0
Python爬虫之Ajax分析方法与结果提取#6
|
2月前
|
数据采集 前端开发 JavaScript
Python爬虫之Ajax数据爬取基本原理#6
Ajax数据爬取原理【2月更文挑战第19天】
32 1
Python爬虫之Ajax数据爬取基本原理#6
|
2月前
|
XML 前端开发 JavaScript
AJAX get() 和 post() 方法
AJAX(Asynchronous JavaScript and XML)是一种用于创建快速和动态网页的技术,它允许使用 JavaScript 和 XMLHttpRequest 对象在不重新加载整个页面的情况下向服务器发送请求和接收响应。jQuery 提供了几个用于 AJAX 操作的方法,包括 .ajax()、.get() 和 .post()
14 1