Ajax的全称:Asynchronous JavaScript and XML (异步Javascript和XML)
传统模式中,数据提交通过表单方式实现,数据的获取是靠全页面刷新来重新获取整页的内容。而Ajax模式只是通过XMLHttpRequest对象向服务器端提交数据,即按需发送。因为Ajax需要与Web服务器端进行交互,所以用个服务器,我这里用的是Tomcat。
1. 传统Js的Ajax操作
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"><title></title><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><script language="javascript" type="text/javascript">//通过这个函数来异步获取信息function Ajax(){ var xmlHttpReq =null; //声明一个空对象用来装入XMLHttpRequestif (window.ActiveXObject){//IE5 IE6是以ActiveXObject的方式引入XMLHttpRequest的 xmlHttpReq =new ActiveXObject("Microsoft.XMLHTTP"); } elseif (window.XMLHttpRequest){//除IE5 IE6 以外的浏览器XMLHttpRequest是window的子对象 xmlHttpReq =new XMLHttpRequest();//实例化一个XMLHttpRequest } if(xmlHttpReq !=null){ //如果对象实例化成功 xmlHttpReq.open("GET","test.jsp",true); //调用open()方法并采用异步方式 xmlHttpReq.onreadystatechange=RequestCallBack; //设置回调函数 xmlHttpReq.send(null); //因为使用get方式提交,所以可以使用null参调用 } function RequestCallBack(){//一旦readyState值改变,将会调用这个函数if(xmlHttpReq.readyState ==4){//readyState的值为4表示请求完成加载(即请求发出去了) if(xmlHttpReq.status ==200){//HTTP状态为200表示相服务器应成功 //将xmlHttpReq.responseText的值赋给ID为 resText 的元素 document.getElementById("resText").innerHTML = xmlHttpReq.responseText; } } } } </script></head><body><input type="button" id="" value="Ajax提交" onclick="Ajax();"/><div id="resText"></div></body></html>
2. jQuery中的Ajax
$.ajax(); $.load(); $.get(); $.post(); $.getStript(); $.getJSON() 这几个常用的方法。
$.load()方法: 将远程的HTML载入并插入DOM中。
首先构建一个test.html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title></title><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/></head><body><div class="comment"><h6>张三:</h6><p class="para">沙发.</p></div><div class="comment"><h6>李四:</h6><p class="para">板凳.</p></div><div class="comment"><h6>王五:</h6><p class="para">地板.</p></div></body></html>
然后用load()方法将它插入到另一个页面中:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title></title><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><style> * { margin:0; padding:0;} body { font-size:12px;} .comment { margin-top:10px; padding:10px; border:1px solid #ccc;background:#DDD;} .comment h6 { font-weight:700; font-size:14px;} .para { margin-top:5px; text-indent:2em;background:#DDD;}</style><!-- 引入jQuery --><script src="../scripts/jquery.js" type="text/javascript"></script><script language="javascript" type="text/javascript"> $(function(){ $("#send").click(function(){ $("#resText").load("test.html"); }) }) </script></head><body><input type="button" id="send" value="Ajax获取"/><div class="comment"> 已有评论: </div><div id="resText"></div></body></html>
自己第一遍写的时候忘记了基本的事:对于jQuery来说,为页面元素添加事件要在DOM初始完成之后再操作,即$(document).ready(......);
load()方法里的第三个参数是个回调函数,这个函数有3个参数,分别代表请求返回的内容,请求状态和XMLHttpRequest对象
$("#resText").load("test.html .para",function (responseText, textStatus, XMLHttpRequest){ alert( $(this).html() ); //在这里this指向的是当前的DOM对象,即 $("#iptText")[0] alert(responseText); //请求返回的内容 alert(textStatus); //请求状态:success,error alert(XMLHttpRequest); //XMLHttpRequest对象 });
$.get()方法和$.post()方法
分别使用get方式和post方式来进行异步请求。
注意上面的回调函数是只有当请求成功时才会被调用,这点和$.load()的回调函数不一样。面是一个评论页面的HTML的代码,来说明$.get()方法的使用。
<form id="form1"><p>评论:</p><p>姓名: <input type="text" name="username" id="username"/></p><p>内容: <textarea name="content" id="content"></textarea></p><p><input type="button" id="send" value="提交"/></p></form><div class=‘comment‘>已有评论:</div><div id="resText"></div>
实现点击提交按钮后将评论显示在已有评论下方:
$(function(){ $("#send").click(function(){ $.get("get1.jsp", { //使用$get()方法异步请求,第一个参数是请求页面的URL地址,第二个是发送至服务器的data,第三个是回调函数 username : encodeURI( $("#username").val() ) , content : encodeURI( $("#content").val() ) }, function (data, textStatus){ //第一个参数是返回的内容,第二个是请求状态 $("#resText").html( decodeURI(data) ); // 把返回的数据添加到页面上 } ); }) })
Js的encodeURI()和decodeURI() 方法,encodeURI() 函数可把字符串作为 URI 进行编码。对以下在 URI 中具有特殊含义的 ASCII 标点符号,encodeURI() 函数是不会进行转义的: , / ? : @ & = + $ #
decodeURI() 函数可对 encodeURI() 函数编码过的 URI 进行解码。
数据格式:HTML片段、XML文档(jQuery的DOM处理也可用于XML文档)、JSON
jQuery解析XML文档:
$(function(){ $("#send").click(function(){ $.get("get2.jsp", { username : encodeURI( $("#username").val() ) , content : encodeURI( $("#content").val() ) }, function (data, textStatus){ var username = $(data).find("comment").attr("username"); var content = $(data).find("comment content").text(); username = decodeURI(username); content = decodeURI(content); var txtHtml = "<div class=‘comment‘><h6>"+username+":</h6><p class=‘para‘>"+content+"</p></div>"; $("#resText").html(txtHtml); // 把返回的数据添加到页面上 }); }) })
jQuery解析JSon:
$(function(){ $("#send").click(function(){ $.get("get3.jsp", { username : encodeURI( $("#username").val() ) , content : encodeURI( $("#content").val() ) }, function (data, textStatus){ var username = data.username; var content = data.content; username = decodeURI(username); content = decodeURI(content); var txtHtml = "<div class=‘comment‘><h6>"+username+":</h6><p class=‘para‘>"+content+"</p></div>"; $("#resText").html(txtHtml); // 把返回的数据添加到页面上 },"json"); }) })
$.getScript()和$.getJson()方法
$.getScript()用来加载js文件,它也有回调函数,在js文件加载成功后运行。
$.getJson()方法用于加载json文件,用法和$.getScript()相同。
可以通过JSONP形式的回调函数来加载其它网站的JSON数据,关于JSON和JSONP。例如从图片网站Flickr搜索4张汽车图片:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"><title></title><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><style> * { margin:0; padding:0;} body { font-size:12px;} .para { width:100px; height:100px; margin:5px; border:0;}</style><!-- 引入jQuery --><script src="../scripts/jquery.js" type="text/javascript"></script><script> $(function(){ $(‘#send‘).click(function() { $.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?tags=car&tagmode=any&format=json&jsoncallback=?", function(data){ $.each(data.items, function( i,item ){ $("<img class=‘para‘/> ").attr("src", item.media.m ).appendTo("#resText"); if ( i ==3 ) { returnfalse; } }); } ); }) }) </script></head><body><p><input type="button" id="send" value="加载"/></p><div id="resText"></div></body></html>
关于遍历用的$.each()函数:以一个数组或者对象作为第一个参数,以一个回调函数作为第二个参数。回调函数有两个参数,第一个是对象的成员或者数组的索引,第二个是对应变量或内容。
$.ajax()方法:jQuery最底层ajax的实现。
<!-- $.ajax()方法代替$.getScript()方法 --> <script> $(function(){ $(‘#send‘).click(function() { $.ajax({ type: "GET", url: "test.js", dataType: "script" }); }); }) </script>
<!-- $.ajax()方法代替$.getJson()方法 --> <script> $(function(){ $(‘#send‘).click(function() { $.ajax({ type: "GET", url: "test.json", dataType: "json", success : function(data){ $(‘#resText‘).empty(); var html = ‘‘; $.each( data , function(commentIndex, comment) { html += ‘<div class="comment"><h6>‘ + comment[‘username‘] + ‘:</h6><p class="para">‘ + comment[‘content‘] + ‘</p></div>‘; }) $(‘#resText‘).html(html); } }); }); }) </script>
2. 序列化元素
其余需要注意的方法是:serializaArray()方法,作用于DOM对象而不是全局函数,将DOM元素序列化后,返回JSON数据的格式。eg:
$(function(){ var fields = $(":checkbox,:radio").serializeArray(); console.log(fields);// Firebug输出 $.each( fields, function(i, field){ $("#results").append(field.value + " , "); }); })
$.param()方法,用来对一个数组或对象按照key/value进行序列化。
3. jQuery中的ajax全局事件
使某个Ajax请求不受全局方法影响。
4. 实战案例——基于jQuery的Ajax聊天室程序
Mysql建表,这里navicat建表的话字段名和表名不要加什么双引号之类的,否则报错。
CREATETABLE messages ( id INT (7) NOTNULL auto_increment, USERVARCHAR (255) NOTNULL, msg textNOTNULL, time INT (9) NOTNULL, PRIMARYKEY (id) );
HTML:
<body><div id="wrapper"><p id="messagewindow"><span id="loading">加载中...</span></p><form id="chatform" action="#"> 姓名: <input type="text" id="author" size="50"/><br /> 内容: <input type="text" id="msg" size="50"/><br /><input type="submit" value="发送"/><br /></form></div></body>
书上给的例子只有PHP的....,你妹的我只懂JSP啊!!!结果只好自己用JSP来实现了。
对于服务端:
对于客户端:
使用Myeclipse新建web工程,src目录下建servlet存放servlet类和数据操作的类。顺便说一句:引入jar包时,直接将jar包黏贴到web工程的lib目录下即可,不需要再build path了。
数据库操作,这里可以参照的是jdbc连接数据库的写法,以后直接拷贝:
1package servlets; 2 3import java.sql.Connection; 4import java.sql.DriverManager; 5 6publicclass DatabaseConnection { 7privatestaticfinal String DBDRIVER = "org.gjt.mm.mysql.Driver"; 8privatestaticfinal String URL = "jdbc:mysql://localhost:3306/test"; 9privatestaticfinal String USER = "root"; 10privatestaticfinal String PASSWORD = "root"; 11private Connection conn = null; 1213public DatabaseConnection(){ 14try{ 15 Class.forName(DBDRIVER); 16this.conn=DriverManager.getConnection(URL,USER,PASSWORD); 17 }catch (Exception e) { 18 e.printStackTrace(); 19 } 20 } 2122public Connection getConnection(){ 23return conn; 24 } 2526publicvoid close() throws Exception{ 27if(conn!=null){ 28try{ 29 conn.close(); 30 }catch (Exception e) { 31throw e; 32 } 33 } 34 } 35 }
编写后端的servlet,用于处理前端页面发来的请求并将对应的请求结果发回给前端页面:
1package servlets; 2 3import java.io.IOException; 4import java.io.PrintWriter; 5import java.sql.Connection; 6import java.sql.PreparedStatement; 7import java.sql.ResultSet; 8import java.sql.SQLException; 9import java.text.SimpleDateFormat; 10import java.util.Date; 1112import javax.servlet.ServletException; 13import javax.servlet.http.HttpServlet; 14import javax.servlet.http.HttpServletRequest; 15import javax.servlet.http.HttpServletResponse; 1617publicclass AjaxServlet extends HttpServlet { 18 DatabaseConnection db = new DatabaseConnection(); 19 Connection connection = db.getConnection(); 20 PreparedStatement pstmt = null; 2122 @Override 23protectedvoid doGet(HttpServletRequest req, HttpServletResponse resp) 24throws ServletException, IOException { 25 req.setCharacterEncoding("UTF-8"); 26 resp.setContentType("text/xml;charset=utf-8"); 27 resp.setHeader("Cache-Control", "no-cache"); 28 PrintWriter out = resp.getWriter(); //这里要注意 29int status_code = 2; 30 String name = req.getParameter("name"); 31 String message = req.getParameter("message"); 32 String current=req.getParameter("time"); 33 Date d = new Date(); 34 SimpleDateFormat sdf = new SimpleDateFormat("MMddHHmmss"); 35 String dateNowStr = sdf.format(d); 36int time=Integer.parseInt(dateNowStr); 37if (req.getParameter("action") != null38 && req.getParameter("action").equals("postmsg")) { 39 String sql = "insert into messages (user, msg, time) values(?,?,?)"; 40try { 41 pstmt = connection.prepareStatement(sql); 42 pstmt.setString(1, name); 43 pstmt.setString(2, message); 44 pstmt.setLong(3, time); 45 pstmt.execute(); 46 } catch (SQLException e) { 47 e.printStackTrace(); 48 } 49 } 50 String sql = "select user,msg from messages where time>? order by id asc"; 51try { 52 pstmt = connection.prepareStatement(sql); 53 pstmt.setInt(1, Integer.parseInt(current)); 54 ResultSet resultSet = pstmt.executeQuery(); 55if (resultSet.next()) { 56 status_code = 1; 57 } else { 58 status_code = 2; 59 } 60 System.out.println(status_code); 61 out.println("<?xml version=‘1.0‘ encoding=‘utf-8‘?>"); 62 out.println("<response>"); 63 out.println("\t<status>" + status_code + "</status>"); 64 out.println("\t<time>" + time + "</time>"); 65if (status_code == 1) { 66do { 67 out.println("\t<message>"); 68 out.println("\t\t<author>" + resultSet.getString("user") 69 + "</author>"); 70 out.println("\t\t<text>" + resultSet.getString("msg") 71 + "</text>"); 72 out.println("\t</message>"); 73 } while (resultSet.next()); 74 } 75 out.println("</response>"); 76 } catch (Exception e) { 77 e.printStackTrace(); 78 } 79 } 8081 @Override 82protectedvoid doPost(HttpServletRequest req, HttpServletResponse resp) 83throws ServletException, IOException { 84// TODO Auto-generated method stub85this.doGet(req, resp); 86 } 8788 }
自己写代码就会写得乱七八糟的.....,嘛、现在是完成主义就对了(并没有完成保持数据库中只有10条数据这个功能,懒)。上面代码的注意点有:
1. 如何向前台页面返回XML文档?首先是
resp.setContentType("text/xml;charset=utf-8");
resp.setHeader("Cache-Control", "no-cache");
设置了返回内容的类型,编码,头部。然后是 PrintWriter out = resp.getWriter(), 接着套xml的格式拼装打印输出到前端页面即可。
2. 第二个要注意的比较基本,数据库基本API的使用:Connection PreparedStatement ResultSet之类的,jdbc的基本操作。
3. 注意使用$.post(url,data,callback,type)时,JSP后端是怎么拿到data里的值的:req.getParameter("name")
接下来在web.xml配置我们写的servlet:
<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"><display-name></display-name><servlet><servlet-name>ajax</servlet-name><servlet-class>servlets.AjaxServlet</servlet-class></servlet><servlet-mapping><servlet-name>ajax</servlet-name><url-pattern>/back</url-pattern></servlet-mapping></web-app>
编写脚本,下面是完整的前端页面:
1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2<html xmlns="http://www.w3.org/1999/xhtml"> 3<head> 4<title></title> 5<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> 6<style> 7body { 8 margin: 0; 9 padding: 0;10 font-size: 12px;11}1213#messagewindow {14 height: 250px;15 border: 1px solid;16 padding: 5px;17 overflow: auto;18}1920#wrapper {21 margin: auto;22 width: 438px;23}24</style>25<!-- 引入jQuery -->26<script src="scripts/jquery.js" type="text/javascript"></script>27<script type="text/javascript">28 $(function(){ 29//定义时间戳30 timestamp =0; 31//调用更新信息函数32 updateMsg(); 33//表单提交34 $("#chatform").submit(function(){ 35 $.post("back",{ 36 message: $("#msg").val(), 37 name: $("#author").val(), 38 action: "postmsg", 39 time: timestamp 40 }, function(xml) { 41//清空信息文本框内容42 $("#msg").val(""); 43//调用解析xml的函数44 addMessages(xml); 45 }); 46returnfalse; //阻止表单提交47 }); 48 }); 49//更新信息函数,每隔一定时间去服务端读取数据50function updateMsg(){ 51 $.post("back",{ time: timestamp }, function(xml) { 52//移除掉 等待提示53 $("#loading").remove(); 54//调用解析xml的函数55 addMessages(xml); 56 }); 57//每隔4秒,读取一次.58 setTimeout(‘updateMsg()‘, 4000); 59 } 60//解析xml文档函数,把数据显示到页面上61function addMessages(xml) { 62//如果状态为2,则终止63if($("status",xml).text() =="2") return; 64//更新时间戳65 timestamp = $("time",xml).text(); 66//$.each循环数据67 $("message",xml).each(function() { 68var author = $("author",this).text(); //发布者69var content = $("text",this).text(); //内容70var htmlcode ="<strong>"+author+"</strong>: "+content+"<br />"; 71 $("#messagewindow").prepend( htmlcode ); //添加到文档中72 }); 73 } 74</script>75</head>76<body>77<div id="wrapper">78<p id="messagewindow">79<span id="loading">加载中...</span>80</p>81<form id="chatform" action="#">82 姓名: <input type="text" id="author" size="50"/><br /> 内容: <input 83type="text" id="msg" size="50"/><br /><input type="submit"84 value="发送"/><br />85</form>86</div>87</body>88</html>
上面的代码中要注意的是jQuery对xml文档的DOM操作:$("status",xml)方法用来通知jQuery去XML文档中寻找 "status"标签,找到后再利用text()方法取其标签里的文本即可。运行效果如下: