简单意义上来说,Ajax可以用来在服务器端和WEB客户端之间交换数据,它是利用JavaScript来装载WEB页面的。更深一层来讲,它可以利用异步JavaScript脚本来避免页面请求刷新,让Request/Response过程更加明了。实现Ajax的方法有很多,最原始的办法是用JavaScript脚本来实现这个过程,此外,我们还可以用比较成熟的功能库,比如说Dojo.
Dojo是什么
Dojo是一个强大的JavaScript类库,利用它提供的许多简单的API去实现一些比较复杂的页面功能。其中,利用Dojo来实现HTTP Request/Response不能不说是他的一个最大的亮点。除了提供Ajax功能之外,Dojo还提供了字符串操作、DOM操作、页面拖拽支持、以及数据结构(如列表,队列,堆栈等)。
JSON是什么
JSON是一个Java类库,专门用来转换Java对象为标准字符串。当这个字符串被传至客户端之后,可以通过JavaScript的eval()方法来产生一个数组,这个数组里面包含了所有关于服务端Java对象的信息。
JSON的标准语法可以用来加密许多嵌入对象的结构,这种语法产生的结果比相应的XML要小不少,而且用来很方便的传入eval()函数处理,因此JSON是一个高效、快速的浏览器/服务器数据传输媒介。既然服务端代码可以以多种语言形式存在,JSON也提供了对C#,Python,PHP等语言的支持。
利用Dojo处理HTTP请求
在下面的例子中,我们用Dojo来实现一个简单的功能:当用户按下一个button之后,页面弹出一个来自服务端的欢迎信息。让我们看看以下的部分代码:
- <html>
- <body onLoad="onLoad();">
- <head>
- <title>Example 1</title>
- <script language="javascript" src="js/dojo.js"></script>
- <script language="javascript">
- dojo.require("dojo.io.*");
- dojo.require("dojo.event.*");
- function onLoad() {
- var buttonObj = document.getElementById("myButton");
- dojo.event.connect(buttonObj, "onclick",
- this, "onclick_myButton");
- }
- function onclick_myButton() {
- var bindArgs = {
- url: "welcome.jsp",
- error: function(type, data, evt){
- alert("An error occurred.");
- },
- load: function(type, data, evt){
- alert(data);
- },
- mimetype: "text/plain",
- formNode: document.getElementById("myForm")
- };
- dojo.io.bind(bindArgs);
- }
- </script>
- </head>
- <body>
- <form id="myForm">
- <input type="text" name="name"/>
- <input type="button" id="myButton" value="Submit"/>
- </form>
- </body>
- </html>
<html>
<body onLoad="onLoad();">
<head>
<title>Example 1</title>
<script language="javascript" src="js/dojo.js"></script>
<script language="javascript">
dojo.require("dojo.io.*");
dojo.require("dojo.event.*");
function onLoad() {
var buttonObj = document.getElementById("myButton");
dojo.event.connect(buttonObj, "onclick",
this, "onclick_myButton");
}
function onclick_myButton() {
var bindArgs = {
url: "welcome.jsp",
error: function(type, data, evt){
alert("An error occurred.");
},
load: function(type, data, evt){
alert(data);
},
mimetype: "text/plain",
formNode: document.getElementById("myForm")
};
dojo.io.bind(bindArgs);
}
</script>
</head>
<body>
<form id="myForm">
<input type="text" name="name"/>
<input type="button" id="myButton" value="Submit"/>
</form>
</body>
</html>
首先,页面会导入Dojo库dojo.js,其中包含了所有必须的Dojo类。Dojo库类似于我们Java代码中的Package的概念,象这个例子中所描述的,此处导入了两个包:dojo.io包中含有一些相关的类,可以通过类似于XMLHTTPTransport的协议发出HTTP Request请求;dojo.event包则是用来为网页DOM对象提供一个统一的事件处理方式。
其次,需要注意的是,我们为button指定了一个onclick事件。传统的做法一般都是:
- <input type="submit" onclick="someFunc();"/>
<input type="submit" οnclick="someFunc();"/>
这样可以达到事件绑定的效果,但是遗憾的是,这种方式始终一次只能最多绑定一个事件。而例子中的dojo.event.connect()方法可以让我们关联到不同类中的多个function。例如此处,我们就将onclick_myButton作为myButton的处理句柄。
当onclick_myButton事件执行的时候,系统将会访问welcome.jsp页面,然后返回一个响应。dojo.io.bind()函数在这里起到了强大的作用,参数bindArgs是一个键值对数组。在这个例子中,我们指定了以下五对键值组合:
1、url:请求的目标URL;
2、mimetype:响应的类型类型,默认是"text/plain";
3、load:执行成功之后响应的方法;
4、error:执行发生错误的时候响应的方法;
5、formNode:一个Form的ID,其中的所有fields都将作为参数传递给url处理。
一旦dojo.io.bind(bindArgs)被处理,load或error中的事件将在指定情况下被触发,仔细观察,会发现这两个方法都有三个共有的参数:
1、type:函数的返回类型值,一般load()事件对应"load",而error()事件对应"error";
2、data:得到的响应内容,如果mimetype被指定为text/plain,data内容将是一个字符串响应;如果mimetype是text/json,data的内容理论上就是eval('('+responseReceived+')')的值,这里responseReceived即是响应返回过来的一个JSON字串。
3、evt:HTML DOM Event Object,用来标示一个事件的状态,如事件发生的对象,键盘鼠标的状态等。
除了例子中的这种绑定方式之外,还可以用dojo.event.connect()的来关联一个含有(type,data.evt)参数的function,如:
- dojo.event.connect(req, "load", this, "handleResponse");
- //handleResponse即是一个预定义的JavaScript function
var req = dojo.io.bind(bindArgs); dojo.event.connect(req, "load", this, "handleResponse"); //handleResponse即是一个预定义的JavaScript function
注:
考虑到安全的因素,Fixfox不支持给bindArgs中url参数给定一个外部URL地址,而IE在这方面是没有限制的。
使用JSON传输Java对象
在前面的部分我们间接提到了JSON,它可以将Java对象通过eval()函数转换成一个Javascript理解的对象。
一般我们喜欢在服务端写一些个POJO,而要把它传至Web客户端,可以通过JSON库提供的一些接口方法,如我们在一个名为Book的POJO类中额外添加一个方法Book.toJSONString()方法:
- JSONObject jsonObj = new JSONObject();
- jsonObj.put("bookId", new Integer(this.bookId));
- jsonObj.put("title", this.title);
- jsonObj.put("isbn", this.isbn);
- jsonObj.put("author", this.author);
- return jsonObj.toString();
- }
public String toJSONString() throws JSONException {
JSONObject jsonObj = new JSONObject();
jsonObj.put("bookId", new Integer(this.bookId));
jsonObj.put("title", this.title);
jsonObj.put("isbn", this.isbn);
jsonObj.put("author", this.author);
return jsonObj.toString();
}
例子中的JSONObject类即将Book类的所有属性都提取出来,然后包装成为一个类似于java.util.Map的对象,最后通过toString()方法提供传输给Web端去eval()。同样,我们可以用另外一个JSONArray对象来包装相关信息为一个List,然后传输到Web客户端。
在Web客户端的实现,我们可以参考下面的例子:
- getBookInfo(bookId);
- }
- function trMouseOut(evt) {
- var bookDiv = document.getElementById("bookInfo");
- bookDiv.style.display = "none";
- }
- function getBookInfo(bookId) {
- var params = new Array();
- params['bookId'] = bookId;
- var bindArgs = {
- url: "book.jsp",
- error: function(type, data, evt){
- alert("error");
- },
- mimetype: "text/json",
- content: params
- };
- var req = dojo.io.bind(bindArgs);
- dojo.event.connect(req, "load", this, "populateDiv");
- }
- function populateDiv(type, data, evt) {
- var bookDiv = document.getElementById("bookInfo");
- if (!data) {
- bookDiv.style.display = "none";
- } else {
- bookDiv.innerHTML = "ISBN: " + data.isbn +
- "<br/>Author: " + data.author;
- bookDiv.style.display = "";
- }
- }
function trMouseOver(bookId) { getBookInfo(bookId); } function trMouseOut(evt) { var bookDiv = document.getElementById("bookInfo"); bookDiv.style.display = "none"; } function getBookInfo(bookId) { var params = new Array(); params['bookId'] = bookId; var bindArgs = { url: "book.jsp", error: function(type, data, evt){ alert("error"); }, mimetype: "text/json", content: params }; var req = dojo.io.bind(bindArgs); dojo.event.connect(req, "load", this, "populateDiv"); } function populateDiv(type, data, evt) { var bookDiv = document.getElementById("bookInfo"); if (!data) { bookDiv.style.display = "none"; } else { bookDiv.innerHTML = "ISBN: " + data.isbn + "<br/>Author: " + data.author; bookDiv.style.display = ""; } }
不同于前一个例,此例中的bingArgs多了一个content属性,用来存储一个键值对,然后作为参数传递给book.jsp页面去响应。在某种意义上来说,它有点类似于Form的fields提交。
下一次,再继续写Dojo的高级运用:Widget的制作。