數據庫(Database)是按照數據結構來組織、存儲和管理數據的倉庫,它產生于距今五十年前,隨著信息技術和市場的發展,特別是二十世紀九十年代以后,數據管理不再僅僅是存儲和管理數據,而轉變成用戶所需要的各種數據管理的方式。數據庫有很多種類型,從最簡單的存儲有各種數據的表格到能夠進行海量數據存儲的大型數據庫系統都在各個方面得到了廣泛的應用。在信息化社會,充分有效地管理和利用各類信息資源,是進行科學研究和決策管理的前提條件。數據庫技術是管理信息系統、辦公自動化系統、決策支持系統等各類信息系統的核心部分,是進行科學研究和決策管理的重要技術手段。
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方法中可以找到如下的一條語句:
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做得好。圖1是本例的效果圖
圖1
評論
查看更多