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

时间:2008-05-26 07:38:34  来源:cnblogs  作者:银河使者  【背景色 杏仁黄 秋叶褐 胭脂红 芥末绿 天蓝 雪青 灰 银河白

  不管读者会不会java和servlet,从这个程序中的</span>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方法中可以找到如下的一条语句:

s = 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是本例的效果图

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


共2页: 上一页 [1] 2 下一页

文章评论

共有 0位网翼网友发表了评论 查看完整内容

24小时热门信息