读书笔记: JavaWeb从入门到精通 第13章: Ajax 技术

通过阅读本章, 你可以:

  • 了解 Ajax 开发模式与传统开发模式的比较

  • 掌握如何使用 XMLHttpRequest 对象

  • 通过 Ajax 向服务器发送请求

  • 通过 Ajax 处理服务器的响应

  • 通过 Ajax 实现检测用户名是否唯一

  • 进行 Ajax 重构

  • 通过 Ajax 实现实时显示公告信息

  • 通过 Ajax 实现无刷新的级联下拉列表

  • 通过 Ajax 实现上传文件时显示进度条

13.1 当下谁在用 Ajax

13.1.1 百度搜索提示

13.1.2 淘宝新会员免费注册

13.1.3 明日科技编程词典服务网

 

13.2 Ajax 开发模式与传统开发模式的比较

对于每个用户的请求, 在传统的 Web应用 模式中, 将生成一次HTTP请求, 而在 Ajax 应用 开发模式中, 将变成对 Ajax 引擎的一次 JavaScript 调用. 在  Ajax 应用开发模式中 通过 JavaScript 实现在不刷新整个页面的情况下, 对部分数据进行更新, 从而降低了网络流量, 给用户带来更好的体验.

 

13.3 Ajax 使用的技术

Ajax (Asynchronous JavaScript and XML) 是 XMLHttpRequest 对象 和 JavaScript, XML, CSS, DOM 等多种技术的组合. 其中, 只有 XMLHttpRequest 对象是新技术, 其他的均为已有技术. 

XMLHttpRequest 对象

它是一个具有应用程序接口的 Javascript 对象, 能够使用 超文本传输协议(HTTP) 连接服务器, 是微软公司为了满足开发者的需要, 与1999年在 IE5.0 浏览器中率先推出的.

XML

XML 是 eXtensible Markup Language (可扩展的标记语言) 的缩写, 它提供了用于描述结构化数据的格式, 适用于不同应用程序间的数据交换, 而且这种交换不以预先定义的一组数据结构为前提, 增强了可扩展性. XMLHttpRequest 对象与服务器交换的数据通常采用XML格式.

[例13.1] (略)

注意: 在XML文档中, 必须有一个根元素,  所有其他的元素必须嵌入到根元素中.

JavaScript

Ajax 就是利用 JavaScript 将 DOM, XHTML (或 HTML), XML 以及 CSS 等技术综合起来, 并控制它们的行为的. 因为要开发一个复杂高效的 Ajax 应用程序, 就必须对 JavaScript 有深入的了解.

CSS

CSS 是 Cascading Style Sheet ( 层叠样式表) 的缩写, 用于(增强) 控制网页样式并允许将样式信息与网页内容分离的一种标记性语言. 

DOM

DOM 是文档对象模型的简称, 是表示文本(如HTML文档)和访问, 操作构成文档的各种元素(如 HTML标记和文本串) 的应用程序接口. W3C 定义了 标准的 文档对象模型, 它以树形结构表示 HTML 和 XML 文档, 并且定义了 遍历树 和 添加, 修改, 查找树的节点的方法和属性. 在 Ajax 应用中, 通过 JavaScript 操作 DOM, 可以达到在不刷新页面的情况下实时修改用户界面的目的.

 

13.4 使用 XMLHttpRequest 对象

13.4.1 初始化 XMLHttpRequest 对象

IE 浏览器

IE 浏览器把 XMLHttpRequest 实例化为一个 ActiveX 对象. 具体方法如下:

 

1
2
3
var  http_request =  new  ActiveXObject( "Msxml2.XMLHTTP" );
// or
var  http_request =  new  ActiveXObject( "Microsoft.XMLHTTP" );

在上面的语法中, Msxml2.XMLHTTP 和 Microsoft.XMLHTTP 是针对 IE 浏览器 的不同版本而进行设置的, 目前比较常用的是这两种.

非IE浏览器

非IE浏览器(如 Chrome, FireFox, Opera, Mozzila, Safari) 把 XMLHttpRequest 对象实例化为一个本地 JavaScript 对象. 具体方法如下:

1
var  http_request =  new  XMLHttpRequest();

为了提高程序的兼容性, 可以创建一个跨浏览器的 XMLHttpRequest 对象. 

1
2
3
4
5
6
7
8
9
10
11
if (window.XMLHttpRequest){     // non-IE browser
     http_request =  new  XMLHttpRequest();
else  if (window.ActiveXObject){     // IE browser
     try {
         http_request =  new  ActiveXObject( "Msxml2.XMLHTTP" );
     catch (e){
         try {
             http_request =  new  ActiveXObject( "Microsoft.XMLHTTP" );
         } catch (e){}
     }
}

在上面的代码中, 调用 window.ActiveXObject 将返回一个对象, 或是 null. 在 if 语句中, 会把返回值看作是 true 或 false.

13.4.2 XMLHttpRequest 对象的常用方法

open方法

open 方法用于设置进行异步请求目标的 URL, 请求方法以及其他参数. 其具体语法如下:

open("method", "URL", [,asyncFlag,[,"username"[,"password"]]])

参数说明:

method: 指定请求的类型, 一般为 GET 或 POST.

URL: 指定请求地址, 可以是绝对地址或相对地址, 并且可以传递查询字符串.

asyncFlag: 为可选参数, 异步请求为 true, 同步请求为 false, 默认情况下为 true.

username: 为可选参数, 用于指定请求用户名, 没有时可省略.

password: 为可选参数, 用户指定请求密码, 没有时可省略.

[例13.2] 设置异步请求目标为 register.jsp, 请求方法为 GET, 请求方式为异步的代码如下:

 

1
http_request.open( "GET" "register.jsp" true );

send(content) 方法

send() 方法用于向服务器发送请求. 如果请求声明为异步, 该方法立即返回, 否则将等到接受到响应为止.

content: 用于指定发送的数据, 可以是 DOM 对象的实例, 输入流 或 字符串. 如果没有参数需要传递, 可以设置为null.

[例13.3] 向服务器发送一个不包含任何参数的请求, 可以使用下面的代码:

1
http_request.send( null );

setRequestHeader()方法, 用于为请求的 HTTP头 设置值. 

setRequestHeader("header", "value");

header: 用于指定 HTTP头

value: 用于为指定的 HTTP头 设置值.

注意: setReqeustHeader() 方法必须在调用 open() 方法之后才能调用.

[例13.4] 在发送POST请求时, 需要设置 Content-Type 请求头的值为 "application/x-www-form-urlencoded", 这是就可以通过 setRequestHeader() 方法进行设置. 具体代码如下:

1
http_request.setRequestHeader( "Content-Type" "application/x-www-form-urlencoded" );

abort() 方法用于停止或放弃当前异步请求. 其语法格式如下:

abort()

getResponseHeader()方法, 用于以字符串形式返回指定的 HTTP头 信息.  其语法格式如下:

getResponseHeader("headerLabel")

参数说明:

headerLabel: 用于指定 HTTP头, 包括 Server, Content-Type 和 Date 等.

[例13.5] 要获取 HTTP头 Content-Type 的值, 可以使用以下代码:

1
http_request.getResponseHeader( "Content-Type" );

上面的代码将获取到类似以下内容:

text/html;charset=GB18030

 

getAllResponseHeaders() 方法, 用于以字符串形式返回完整的 HTTP头 信息, 其中包括 Server, Date, Content-Type 和 Content-Length.

[例13.6] 使用下面的代码调用 getAllResponseHeaders() 方法, 将弹出如图13.6 所示的对话框(省略)显示完整的 HTTP 头信息.

 

13.4.3 XMLHttpRequest 对象的常用属性

onreadystatechange 属性

onreadystatechange 属性用于指定状态改变时所触发的事件处理器. 在 Ajax 中, 每个状态改变时都会触发这个事件处理器, 通常会调用一个JavaScript 函数.

[例13.7] 指定状态改变时触发 JavaScript 函数 getResult 的代码如下:

1
http_request.onreadystatechange = getResult;

注意: 在指定所触发的事件处理器时, 所调用的 JavaScript 函数不能添加小括号以及指定参数名. 不过这里可以使用匿名函数. 例如, 要调用带参数的函数 getResult(), 可以使用下面的代码:

 

1
2
3
http_request.onreadystatechange =  function (){
     getResult( "添加的参数" );   // 调用带参数的函数
};                             // 通过匿名函数来指定要带参数的函数

readyState 属性

 

用于获取请求的状态

表 13.1 readyState 属性的属性值及其意义

 

意义 意义
0
           
未初始化 3 交互中
1 正在加载 4 完成
2 已加载    

responseText 属性: 

用于获取服务器的响应, 表示为支付串.

responseXML 属性:

responseXML 属性用于获取服务器的响应, 表示为 XML. 这个对象可以解析为一个 DOM 对象.

status 属性:

用于返回服务器的 HTTP 状态码, 常用的状态码 如表13.2 所示.

表13.2 status 属性的状态码

 


           
意义 意义
200 表示成功 404 

文件未找                

202 表示请求被接受, 但尚未成功 500 内部服务器错误
400 错误的请求    

statusText 属性

statusText 属性用于返回 HTTP 状态码对应的文本, 如 OK 或 Not Found 等.

 

13.5 与服务器通信--发送请求与处理响应

13.5.1 发送请求

无论发送GET请求还是POST请求, 都需要经过以下 4 个步骤:

(1) 初始化 XMLHttpRequest 对象. 为了提高程序的兼容性, 需要创建一个跨浏览器的 XMLHttpRequst 对象, 并且判断 XMLHttpRequest 对象的实例是否创建成功, 如果不成功, 则给予提示.

[例13.8] 发送请求.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
http_request =  false ;
if (window.XMLHttpRequest){  // non-IE browser
     http_request =  new  XMLHttpRequest();
} else  if (window.ActiveXObject){  // IE browser
     try {
         http_request =  new  ActiveXObject( "Msxml2.XMLHTTP" );
     } catch (e){
         try {
             http_request =  new  ActiveXObject( "Microsoft.XMLHTTP" );
         } catch (e){}
     }
}
if (!http_request){
     alert( "无法创建 XMLHttpRequest 对象实例!" );
     return  false ;
}

(2) 为XMLHttpRequest 对象指定一个返回结果处理函数(即 回调函数), 用于对返回结果进行处理. 具体代码如下:

[例13.9] 设置回调函数.

1
http_request.onreadystatechange = getResult;  //调用返回结果处理函数

注意: 使用 XMLHttpRequest 对象的 onreadystatechange 属性指定回调函数时, 不能指定要传递的参数.如果要指定传递的参数, 可以使用以下方法:

 

1
http_request.onreadystatechange =  function (){ getResult(param) };

(3) 创建一个到服务器的连接. 在创建时, 需要指定发送请求的方式(即GET或POST), 以及设置是否采用异步方式发送请求.

[例13.10] 采用异步方式发送 GET 请求 的具体代码如下:

http_request.open('GET', url, true);

[例13.11] 采用异步方式发送 PSOT 请求的具体代码如下:

http_request.open('POST', url, true);

说明: 在 open() 方法中的 url 参数, 可以是一个 JSP页面的 URL 地址, 也可以是 Servlet 的映射地址.

技巧: 在指定 URL 参数时, 最好将一个时间戳追加到该 URL 参数的后面, 这样可以防止因浏览器缓存结果而不能实时得到最新的结果. 例如, 可以指定 URL参数 为以下代码:

1
String url= "deal.jsp?nocache=" + new  Date().getTime();

(4) 向服务器发送请求. XMLHttpRequest 对象的 send() 方法 可以实现向 服务器发送请求, 该方法需要传递一个参数, 如果发送的是 GET 请求, 可以将该参数设置为null; 如果发送的是 POST 请求, 可以通过该参数指定要发送的 请求参数.

向服务器发送 GET 请求的代码如下:

1
http_request.send( null );  // 向服务器发送 GET 请求

[例13.12] 向服务器发送POST请求的代码如下:

 

1
2
3
4
//需要注意的是, 在发送POST请求前,还需要设置正确的请求头
http_request.setRequestHeader( "Content-Type" "application/x-www-form-urlencoded" );
var  param= "user" +form1.user.value+ "&pwd=" +form1.pwd.value+&email="+form1.email.value;  // 组合参数
http_request.send(param);  // 向服务器发送请求

13.5.2 处理服务器响应

  1. 处理字符串响应

    [例13.13] 将字符串响应显示到提示对话框中的回调函数的具体代码如下:


           

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function  getResult(){
         if (http_request.readyState == 4){     //判断请求状态
             if (http_request.status == 200){   //判断响应状态
                 alert(http_request.responseText);
             else {
                 alert( "您所请求的页面有错误!" );
             }
         }
    }

           

           

    如果需要将响应结果显示到页面的指定位置, 那么可以预先在页面的适当位置添加一个<div>或<span>标记, 并设置其id属性, 然后在回调函数中使用如下代码显示响应结果:


           

    1
    document.getElementById( "div_result" ).innerHTML=http_request.responseText;

           

       

  2. 处理XML响应

[例13.14] 保存图书信息的 XML 文档. 具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version= "1.0"  encoding= "UTF-8" ?>
<mr>
     <books>
         <book>
             <title>Java Web 程序开发范例宝典</title>
             <publisher>人们邮电出版社</publisher>
         </book>
         <book>
             <title>Java 范例完全自学手册</title>
             <publisher>人们邮电出版社</publisher>
         </book>
     </books>
<mr>

在回调函数中遍历图书信息的XML文档, 并将其显示到页面中的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function  getResult{
     if (http_request.readyState == 4) {   //判断请求状态
         if (http_request.status == 200){  //判断响应状态
             var  xmldoc = http_request.responseXML;
             var  str= "" ;
             for (i=0;i<xmldoc.getElementsByTagName( "book" ).length;i++){
                 var  book=xmldoc.getElementsByTagName( "book" ).item(i);
                 str=str+ " <<" +book.getElementsByTagName( "title" )[0].firstChild.data+ ">> 由 " +book.getElementsByTagName( "publisher" )[0].firstChild.data+ " 出版<br>" ;
             }
             document.getElementById( "book" ).innerHTML=str;
         } else {
             alert( "您所请求的页面有错误!" );
         }
     }
}
<div id= "book" ></div>

13.5.3 一个完整的实例 -- 检测用户名是否唯一

[例13.15]检测用户名是否唯一. (实例位置: disc\TM\sl\13\1)

(1)创建index.jsp文件, 在该文件中添加用于收集用户注册信息的表单及表单元素, 以及代表"检测用户名"按钮的图片, 并在该图片的onclick事件中调用 checkName() 函数, 检测用户名是否已被注册.

1
2
3
4
5
6
7
8
9
< form  method = "post"  action = ""  name = "form1" >
 
用户名:< input  name = "username"  type = "text"  id = "username"  size = "32" ></ td >
         < img  src = "images/checkBt.jpg"  width = "104"  height = "23"  style = "cursor:hand;"  onClick = "checkUser(form1.username);" ></ td >
密码:< input  name = "pwd1"  type = "password"  id = "pwd1"  size = "35" >
确认密码:< input  name = "pwd2"  type = "password"  id = "pwd2"  size = "35" >
E-mail:< input  name = "email"  type = "text"  id = "email"  size = "45" >
< input  type = "image"  name = "imageField"  src = "images/registerBt.jpg" >
</ form >

(2) 在页面的适当位置添加用于显示提示信息的<div>标记, 并通过CSS设置该<div>标记的样式.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<style type= "text/css" >
<!--
#toolTip {
     position:absolute;  //设置为绝对路径
     left:331px;         //设置左边距
     top:39px;             //设置顶边距
     width:98px;         //设置宽度
     height:48px;         //设置高度
     padding-top:45px;     //设置文字与顶边的距离
     padding-left:25px;     //设置文字与左边的距离
     padding-right:25px;     //设置文字与右边的距离
     z-index:1;
     display:none;     //设置默认不显示
     color:red;         //设置文字的颜色
     background-image: url(images/tooltip.jpg); //设置背景图片
}
-->
</style>
<div id= "toolTip" ></div>

(3) 编写JavaScript函数 createRequest().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function  createRequest(url) {
     http_request =  false ;
     if  (window.XMLHttpRequest) {                                    // 非IE浏览器
         http_request =  new  XMLHttpRequest();                           //创建XMLHttpRequest对象
     else  if  (window.ActiveXObject) {                              // IE浏览器
         try  {
             http_request =  new  ActiveXObject( "Msxml2.XMLHTTP" );     //创建XMLHttpRequest对象
         catch  (e) {
             try  {
                 http_request =  new  ActiveXObject( "Microsoft.XMLHTTP" );   //创建XMLHttpRequest对象
            catch  (e) {}
         }
     }
     if  (!http_request) {
         alert( "不能创建XMLHttpRequest对象实例!" );
         return  false ;
     }
     http_request.onreadystatechange = getResult;                        //调用返回结果处理函数
     http_request.open( 'GET' , url,  true );                                //创建与服务器的连接
     http_request.send( null );                                        //向服务器发送请求
}

(4) 编写回调函数 getResult().

1
2
3
4
5
6
7
8
9
10
function  getResult() {
     if  (http_request.readyState == 4) {              // 判断请求状态
         if  (http_request.status == 200) {            // 请求成功,开始处理返回结果
             document.getElementById( "toolTip" ).innerHTML=http_request.responseText;  //设置提示内容
             document.getElementById( "toolTip" ).style.display= "block" ;    //显示提示框
         else  {                             // 请求页面有错误
             alert( "您所请求的页面有错误!" );
         }
     }
}

(5) 编写JavaScript函数 checkUser(), 用于检测用户名是否为空, 当用户名不为空时, 调用 createRequest() 函数发送异步请求检测用户名是否已被注册.

1
2
3
4
5
6
7
function  checkUser(userName){
     if (userName.value== "" ){
         alert( "请输入用户名!" );userName.focus(); return ;
     } else {
         createRequest( 'checkUser.jsp?user=' +userName.value);
     }
}

(6) 编写检测用户名是否已被注册的处理页checkUser.jsp.

1
2
3
4
5
6
7
8
9
10
11
12
<%@ page language= "java"  import = "java.util.*"  pageEncoding= "GB18030"  %>
<%
     String[] userList={ "明日科技" , "mr" , "mrsoft" , "wgh" };          //创建一个一维数组
     String user= new  String(request.getParameter( "user" ).getBytes( "ISO-8859-1" ), "GB18030" );   //获取用户名
     Arrays.sort(userList);                                   //对数组排序
     int  result=Arrays.binarySearch(userList,user);               //搜索数组
     if (result>- 1 ){
         out.println( "很抱歉,该用户名已经被注册!" );           //输出检测结果
     } else {
         out.println( "恭喜您,该用户名没有被注册!" );           //输出检测结果
     }
%>

说明: 由于本实例比较简单, 这里没有从数据库中获取用户列表, 而是将用户列表保存在一个一维数组中. 在实际项目开发时, 通常情况下是从数据库中获取用户信息.

图13.7 检测用户名

 

13.6 解决中文乱码问题

Ajax 不支持多种字符集, 其默认的字符集是 UTF-8, 所以在使用 Ajax 技术的程序中, 应及时进行编码转换, 否则程序中出现的中文字符将变成乱码.

 

13.6.1 发送请求时出现中文乱码

(1) 当接收使用GET方法提交的数据时, 要将编码转换为 GBK 或 UTF-8.

1
2
String selProvince=request.getParameter( "parProvince" );
selProvince= new  String(selProvince.getBytes( "ISO-8859-1" ), "UTF-8" );

(2)用于使用POST方法提交数据时, 默认的字符编码是 UTF-8, 所以当接收使用 POST 方法提交的数据时, 要将编码转换为UTF-8.

1
2
String username=request.getParameter( "user" );
username= new  String(username.getBytes( "ISO-8859-1" ), "UTF-8" );

13.6.2 获取服务器的响应结果时出现中文乱码

由于 Ajax 在接收 responseText 或 responseXML 的值时是按照 UTF-8 的编码格式进行解码的, 所以如果服务器端传递的数据不是UTF-8格式, 在接收 responseText 或 responseXML 的值时, 就可能产生乱码. 解决的办法是 确保从服务器端传递的数据采用 UTF-8 的编码格式.

 

13.7 Ajax 重构

13.7.1 Ajax 重构的步骤

(1) AjaxRequest.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
var  net =  new  Object();  // 定义一个全局变量net
// 编写构造函数
net.AjaxRequest =  function (url, onload, onerror, method, params) {
     this .req =  null ;
     this .onload = onload;
     this .onerror = (onerror) ? onerror :  this .defaultError;
     this .loadDate(url, method, params);
}
// 编写用于初始化XMLHttpRequest对象并指定处理函数,最后发送HTTP请求的方法
net.AjaxRequest.prototype.loadDate =  function (url, method, params) {
     if  (!method) {
         method =  "GET" ;
     }
     if  (window.XMLHttpRequest) {
         this .req =  new  XMLHttpRequest();
     else  if  (window.ActiveXObject) {
         this .req =  new  ActiveXObject( "Microsoft.XMLHTTP" );
     }
     if  ( this .req) {
         try  {
             var  loader =  this ;
             this .req.onreadystatechange =  function () {
                 net.AjaxRequest.onReadyState.call(loader);
             }
             this .req.open(method, url,  true ); // 建立对服务器的调用
             if  (method ==  "POST" ) { // 如果提交方式为POST
                 this .req.setRequestHeader( "Content-Type" ,
                         "application/x-www-form-urlencoded" );  // 设置请求头
             }
             this .req.send(params);  // 发送请求
         catch  (err) {
             this .onerror.call( this );
         }
     }
}
 
// 重构回调函数
net.AjaxRequest.onReadyState =  function () {
     var  req =  this .req;
     var  ready = req.readyState;
     if  (ready == 4) { // 请求完成
         if  (req.status == 200) { // 请求成功
             this .onload.call( this );
         else  {
             this .onerror.call( this );
         }
     }
}
// 重构默认的错误处理函数
net.AjaxRequest.prototype.defaultError =  function () {
     alert( "错误数据\n\n回调状态:"  this .req.readyState +  "\n状态: "  this .req.status);
}

 

(2) 在需要使用 Ajax 的页面中使用如下语句

1
<script language= "javascript"  src= "AjaxRequest.js" ></script>

 

(3) 在使用 Ajax的页面中编写错误处理方法, 实例化 Ajax 对象的方法和回调函数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script language= "javascript" >
/**错误处理的方法**/
function  onerror(){
     alert( "您的操作有误!" );
}
/**实例化Ajax对象的方法**/
function  getInfo(){
     var  loader= new  net.AjaxRequest( "getInfo.jsp?nocache=" + new  Date().getTime(), deal_getInfo, onerror,  "GET" );
}
/**回调函数**/
function  deal_getInfo(){
     document.getElementById( "showInfo" ).innerHTML= this .req.responseText;
}
</script>

 

131.7.2 使用 Ajax 重构实现实时显示公告信息

[例13.17] 实时显示公告信息. (实例位置: disc\TM\sl\13\2)

(1) AjaxRequest.js

(2) 在 index.jsp 中引用 AjaxRequest.js 文件

1
<script language= "javascript"  src= "JS/AjaxRequest.js" ></script>

 

 

(3) 在 index.jsp 页面中编写错误处理函数, 实例化Ajax对象的方法和回调函数.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script language= "javascript" >
/**错误处理的方法**/
function  onerror(){
     alert( "您的操作有误!" );
}
/**实例化Ajax对象的方法**/
function  getInfo(){
     var  loader= new  net.AjaxRequest( "getInfo.jsp?nocache=" + new  Date().getTime(), deal_getInfo, onerror,  "GET" );
}
/**回调函数**/
function  deal_getInfo(){
     document.getElementById( "showInfo" ).innerHTML= this .req.responseText;
}
</script>

(4) 由于要实现滚动显示公告信息, 所以还添加了<marquee>标记.

1
2
3
4
5
<div style= "border: 1px solid; height: 50px; width: 200px; padding: 5px;" >
     <marquee direction= "up"  scrollamount= "3" >
         <div id= "showInfo" ></div>
     </marquee>
</div>

 

(5) getInfo.jsp

1
2

你可能感兴趣的:(读书笔记: JavaWeb从入门到精通 第13章: Ajax 技术)