Ajax部分
1定义:多种应用异步通信,能够数据的局部刷新,使用户有不间断的体验
ajax 的四项技术:
javascript, css, dom, XMLHttpRequest
2四者之间的关系:
1. javascript 创建XMLHttpRequest 对象并用它与web server 通信获得数据;
2. javascript 使用dom 的api 将数据更新到页面;
3. javascript 将css 应用到HTML 的元素上
Ajax的传输步骤------------------------------à
3 ajax 的编程步骤:
1. 创建XMLHttpRequest 对象xhr;
2. 使用xhr 的open 函数打开资源;open("GET or POST" , "传向的页面"+如果是GET要加参数(不用加/));
3. 使用xhr 的onreadystatechange 属性注册处理应答的回调函数的句柄;(为什么只传句柄?如果传display()的话相当于传入的是函数值,
而传入display()的话是将整个函数传给它,当有变化时交个这个函数来处理传入display()还会出错?)
4. (在使用POST 方法使用)使用xhr 的setRequestHeader 设置请求头。通常设置content-type
请求头,可能的值是:application/x-www-form-urlencoded 和text/xml;
5. 使用xhr 的send 方法发送请求;
6. 编写回调函数处理应答:在此函数里通过xhr 的readyState 属性判断通信是否结束(等于4 结束);然后再通过xhr 的status 属性判断web server 是否正确处理应答(等于200 正确),如果正确处理应答,应答的文本存放在xhr 的responseText 属性中,应答是xml 再将生成的xml 文档放在xhr 的responseXML 中 传XML文档只能用POST方法传
res.getCharactorEncoding();可获得res的字符编码
res.setCharactorEncoding("UTF-8");
用DOM api 解析XML 文档的步骤:
1. 创建DocumentBuilderFactory:
DocumentBu ilderFactory dbf = DocumentBuilderFactory.newInstance();
2. (可选)设置dbf 的属性:
设置合法性检测: dbf.setValidating(true);
设置处理名字空间: dbf.setNamespaceAware(true);
3.创建DocumentBuilder:
DocumentBu ilder db = dbf.newDocumentBuilder();
4a.解析XML 文档:
Document doc = db.parse(xmlResource);
4b.生成XML 文档:
Document doc = db.newDocument();
4 XMLHTTPRequest的属性和方法介绍
方法属性:
open(string method, string url, boolean asynch, string username, string password):post还是get,url地址,同步还是异步 后面三个参数是可选的
void send(content):
string getAllResponseHeaders()
void setRequestHeader(string header, string value):这个方法为HTTP请求中一个给定的首部设置值。它有两个参数,第一个串表示要设置的首部,第二个串表示要在首部中放置的值。需要说明,这个方法必须在调用open()之后才能调用。
string getResponseHeader(string header):
onreadystatechange :每个状态改变时都会触发这个事件处理器,通常会调用一个JavaScript函数、回调函数
readyState:请求的状态。有5个可取值:0 = 未初始化,1 = 正在加载,2 = 已加载,3 = 交互中,4 = 完成
responseText:服务器的响应,表示为一个串
responseXML:服务器的响应,表示为XML。这个对象可以解析为一个DOM对象
statusText:HTTP状态码的相应文本(OK或Not Found(未找到)等等)
5 kettasAjax 封装XMLHttpRequest 四个方法说明:
1.kettasAjax.doGetText(url, textHandler, async):
用GET 方法发出请求到url, 返回的文本responseText 作为回调函数textHandler 的参数。
textHandler 的签名类似function(txt).
2.kettasAjax.doGetXml(url, xmlHandler, async):
用GET 方法发出请求到url, 返回的XML Document 也就是responseXML 作为回调函数
xmlHandler 的参数。xmlHandler 的签名类似function(doc).
3.kettasAjax.doPostText(url, textHandler, body, async):
用POST 方法将请求体body 发送到url, 返回的文本responseText 作为回调函数textHandler
的参数。textHandler 的签名类似function(txt).
4.kettasAjax.doPostXml(url, xmlHandler, body, async):
用POST 方法将请求体body 发送到url, 返回的XML Document 也就是responseXML 作为
回调函数xmlHandler 的参数。xmlHandler 的签名类似function(doc).
6 AJAX全称为"Asynchronous JavaScript and XML"(异步JavaScript和XML),是指一种创建交互式网页应用的
网页开发技术。它容许网页的部分刷新,比起传统的整个页面刷新,传输的数据量大大减少,这样就显著提高了
用户浏览web页面的速度。
1) 获取ajax核心对象XMLHttpRequest的标准JavaScript函数 :
function createXhr(){
// 判断是IE浏览器还是其他浏览器,然后返回对象
if(window.ActiveXObject){
return new ActiveXObject("Microsoft.XMLHTTP");
}else if(window.XMLHttpRequest){
return new XMLHttpRequest();
}else{ throw new Error("Does not ajax programming");}
}
注 : 下面的笔记中,都用 createXhr()这个函数获取XMLHttpRequest对象
2) 实例 : 在网页中验证电子邮箱输入的格式
(1) 网页文件
<title>Validate Email Format</title>
<!-- createXhr()以及其他工具函数都在utils.js中 -->
<script type="text/javascript" src="js/utils.js"></script>
<script type="text/javascript">
//以下是标准的步骤,要牢记
var xhr = null;
function validateEmail(){
xhr = createXhr();// 获取XMLHttpRequest对象
// 要提交到服务器的请求,escape函数用于除去字符串两端空格,$函数根据id获得对象(此方法在util.js中) vm是servlet的访问地址
var url = "vm?mail=" + escape($("mail").value);
/* 指定发送的方式、接受请求的页面(或servlet)、是否采用异步回调
* 参数也可以是("GET", url, true)
* true是默认的,故可省略不写,表示采用异步回调
*/
xhr.open("GET", url);
// 指定异步回调函数
xhr.onreadystatechange = displayStatus;
// 若采用POST方式提交请求,这里就必须发送请求体,这里是GET方式,故为NULL
//请求体的设置xhr.setRequestHeader(“Content-Type”,”application/x-www-form-urlencoded”);
xhr.send(null);
}
//异步回调函数的实现
function displayStatus(){
// readyState是服务端状态, 0代表无状态,1代表建立连接,2准备发送数据,3正在发送数据 ,等于4表明对请求响应完毕,该返回客户端的数据都返回了
if(xhr.readyState == 4){
// status是客户端状态,等于200表明数据已经存在于缓存,可以直接拿来使用了
400 url出错,500内部出错
if(xhr.status == 200){
var status = $("mailFormatStatus");
// 获得服务器返回的文本数据
var mailStatus = xhr.responseText;
if(mailStatus == "true"){
status.innerHTML = "valid email format";
}else{ status.innerHTML = "invalid email format"; }
}else{// 获得客户端状态值以及对应的描述性文本
errorHandler(xhr.status, xhr.statusText);}
}else{ status.innerHTML = "please wait..."; }}
</script>
</head>
<body>
<h2>Please enter an email address to validate</h2>
<input type="text" id="mail" οnblur="validateEmail()"/><br/>
<div id="mailFormatStatus"></div>
</body>
</html>
(2) Servlet文件ValidateEmailFormatServlet.java片段
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 注意这里不是"text/html" 因为我们只需要返回纯文本字符串即可 故用"text/plain"
response.setContentType("text/plain;charset=gbk");
String mail = request.getParameter("mail");
String status = "false";
if(mail != null){
Pattern p = Pattern.compile("\\S+@\\S+");
Matcher m = p.matcher(mail);
if(m.matches()) status = "true";
}
PrintWriter out = response.getWriter();
out.print(status);
out.flush();
//这里关闭与否 应该无关痛痒
out.close();
}
(3) web.xml片段
<servlet>
<description>
</description>
<display-name>
ValidateEmailFormatServlet</display-name>
<servlet-name>ValidateEmailFormatServlet</servlet-name>
<servlet-class>
com.kettas.ajax.xhr.day1.ValidateEmailFormatServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ValidateEmailFormatServlet</servlet-name>
<url-pattern>/vm</url-pattern>
</servlet-mapping>
3) 向服务器请求获得xml文件(对象)
本例中,得到从服务器返回的xml对象,然后将数据填充到表格
<title>Online super store</title>
<script type="text/javascript" src="js/utils.js"></script>
<script type="text/javascript">
var xhr = null;
function initStore(){
xhr = createXhr();
xhr.open("GET", "xmlListProduct.jsp");
xhr.onreadystatechange = display;
xhr.send(null);
}
function display(){
if(xhr.readyState == 4){
if(xhr.status == 200){
fillStoreTable(xhr.responseXML);
}else{
errorHandler(xhr.status, xhr.statusText);
}}}
function fillStoreTable(productsRoot){
// 将xml数据,填充表格,具体过程略
...
}
</script>
</head>
<body οnlοad="initStore();">
<table id="storeTable">
<tbody id="storeBody">
</tbody>
</table>
</html>
xmlListProduct.jsp文件内容如下 :
<!-- 注意,客户端需要的是xml文件,故这里是"text/xml" -->
<%@page language="java" contentType="text/xml; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<jsp:useBean id="store" class="com.kettas.ajax.xhr.day1.SuperStore" scope="application"/>
<products>
<c:forEach var="product" items="${store.products}">
<product>
<id>${product.id }</id>
<name>${product.name }</name>
<price>${product.price}</price>
</product>
</c:forEach>
</products>
7 封装ajax的调用步骤 :
获得XMLHttpRequest对象,然后向服务器发送请求,最后对服务器返回的数据进行处理。这个过程
千篇一律,每次按照相同的步骤书写,故将它们封装起来是当务之急。这样的话,调用起来会方便
得多。
封装的具体实现如下所示(十分经典的javascript代码,掌握并牢记) :
function Request(l){
var xhr = createXhr();// 私有属性 XMLHttpRequest对象
var listener = l; // 私有属性 此对象负责对服务端响应作反应
// 保险起见 若初始化时没有赋予对象 则赋予一个新创建的对象
if(!listener) listener = new ResponseListener();
// 公有属性 请求体内容的类型 默认的表示发送的是表单数据
// 若发送的是xml类型数据 则this.contentType = "text/xml";
// 实际上 这个是无关痛痒的 都用默认的类型即可
this.contentType = "application/x-www-form-urlencoded";
// 公有方法 以GET方式发送请求
this.doGet = function(url,async){
sendRequest("GET", url, null, async);
}
// 公有方法 以POST方式发送请求
this.doPost = function(url, requestBody, async){
sendRequest("POST", url, requestBody, async);
}
// 私有方法 向服务器发送请求
function sendRequest(method, url, requestBody, async){
if(async == undefined) async = true; // 如果没有说明是否采用异步回调 则采用异步回调
// 如果async有值 并且async != ( false || 0 || null ) 则采用异步回调
else if(async) async = true;
else async = false; // 其他情况( async = false || 0 || null ) 则不采用异步回调
// 指定发送的方式、接受请求的页面(或servlet)、是否采用异步回调
xhr.open(method, url, async);
if(async) xhr.onreadystatechange = callback; // 指定异步回调函数
// 设置请求体的内容类contentType =application/x-www-form-urlencoded”
xhr.setRequestHeader("Content-Type", contentType);
xhr.send(requestBody); // 发送请求
// 若没有采用异步回调 则执行此函数
if(!async) listener.complete(
xhr.status, xhr.statusText, xhr.responseText, xhr.responseXML
);
}
// 私有函数 异步回调函数的实现
function callback(){
switch(xhr.readyState){
case 0: listener.uninitialized(); break;
case 1: listener.loading(); break;
case 2: listener.loaded(); break;
case 3: listener.interactive(); break;
case 4: listener.complete(
xhr.status, xhr.statusText, xhr.responseText, xhr.responseXML
); break;
}}
// 私有函数
function createXhr(){
if(window.ActiveXObject){
return new ActiveXObject("Microsoft.XMLHTTP");
}else if(window.XMLHttpRequest){
return new XMLHttpRequest();
}else{
throw new Error("Does not ajax programming");
}}}
// 此对象处理服务端响应
function ResponseListener(){
this.uninitialized = function(){}
this.loading = function(){}
this.loaded = function(){}
this.interactive = function(){}
// 最后一个响应状态 响应完毕
this.complete = function(status, statusText, responseText, responseXML){}
/* 继承上面的对象
* 对于其它四个状态 一般是不需要处理响应的 故这里不予理会
* 只是覆盖响应完毕后的处理方法
*/
function ResponseAdapter(){
this.handleText = function(text){}
this.handleXml = function(xml){}
this.handleError = function(status, statusText){
alert("Error: " + status + " " + statusText);
}
// 覆盖父类的方法
this.complete = function(status, statusText, responseText, responseXML){
if(status == 200){
this.handleText(responseText);
this.handleXml(responseXML);
}else{
this.handleError(status, statusText);
}
}
}
// 注意 javascript的继承机制
ResponseAdapter.prototype = new ResponseListener();
ResponseAdapter.prototype.constructor = ResponseAdapter;
// 对以上部分实现功能的组织调用类
if(!kettasAjax) var kettasAjax = {};
// 采用GET方式发送请求 对返回的文本数据进行处理
if(!kettasAjax.getText){
kettasAjax.getText = function(url, handleText, async){
var l = new ResponseAdapter();
l.handleText = handleText;
var req = new Request(l);
req.doGet(url, async);
}}
// 采用GET方式发送请求 对返回的XML数据进行处理
if(!kettasAjax.getXml){
kettasAjax.getXml = function(url, handleXml, async){
var l = new ResponseAdapter();
l.handleXml = handleXml;
var req = new Request(l);
req.doGet(url, async);
}
}
// 采用POST方式发送请求 对返回的文本数据进行处理
if(!kettasAjax.postText){
kettasAjax.postText = function(url, requestBody,handleText, async){
var l = new ResponseAdapter();
l.handleText = handleText;
var req = new Request(l);
req.doPost(url,requestBody, async);
}
}
// 采用POST方式发送请求 对返回的XML数据进行处理
if(!kettasAjax.postXml){
kettasAjax.postXml = function(url, requestBody, handleXml, async){
var l = new ResponseAdapter();
l.handleText = handleXml;
var req = new Request(l);
req.doPost(url, requestBody, async);
}
}
注 : 以后就使用这个kettasAjax对象,会方便异常
8 采用kettasAjax对象,采用不同的方式向服务器发送不同类型的数据
(1) html文件如下 :
<title>Send Request Parameters</title>
<script type="text/javascript" src="js/utils.js"></script>
<script type="text/javascript" src="js/kettasAjax.js"></script>
<script type="text/javascript">
function handleForm(httpMethod){
if(httpMethod == "GET"){
// 采用GET方式向服务器发送表单数据
kettasAjax.getText("echo.jsp?" + getQueryString(), display);
}else{
// 采用POST方式向服务器发送表单数据
kettasAjax.postText("echo.jsp", getQueryString(), display);
}}
// 显示服务器返回的数据
function display(txt){
$("response").innerHTML = txt;
}
// 获得表单数据的字符串组织形式
function getQueryString(){
var name = escape(getEavById("name"));
var age = escape(getEavById("age"));
var password = escape(getEavById("password"));
var queryStr = "name=" + name +"&age=" + age + "&password=" + password;
return queryStr;
}
// 采用POST方式向服务器发送xml数据
// 由于发送的是xml形式字符串 故服务端不能以getParameter的方式读取 要以readLine方式读取
function handleXmlForm(){
kettasAjax.postText("handleXml", getXmlFromForm(), display);
}
// 获得表单数据的xml字符串表现形式
function getXmlFromForm(){
var name = getEavById("name");
var age = getEavById("age");
var password = getEavById("password");
var xmlStr = "<params>"
+ "<name>" + name + "</name>"
+ "<age>" + age + "</age>"
+ "<password>" + password + "</password>"
+ "</params>"
return xmlStr;
}
</script>
</head>
<body>
<form action="#">
Name: <input type="text" id="name"/><br/>
Age: <input type="text" id="age"/><br/>
Password: <input type="password" id="password"/><br/>
</form>
<button οnclick="handleForm('GET')">Get</button>
<button οnclick="handleForm('POST')">Post</button>
<button οnclick="handleXmlForm()">Send Parameters as XML</button><br/>
<div id="response"></div>
</body>
</html>
(2) echo.jsp内容如下 :
Http method: ${pageContext.request.method}, and parameters
are name: ${param.name}, age: ${param.age}, password: ${param.password}
(3) Servlet文件HandleXmlServlet片段如下 :
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
StringBuilder sb = new StringBuilder();
// 由于客户端发送的是xml形式的字符串 故要获得BufferedReader对象用于读取
BufferedReader reader = request.getReader();
PrintWriter out = response.getWriter();
String line = null;
// 可能客户端是采用多行发送的 故不能只读取一行了事
while ((line = reader.readLine()) != null)
sb.append(line);
// 解析xml数据
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder db = dbf.newDocumentBuilder();
// 由于不存在.xml文件 故只能以内存字节流的方式初始化
Document doc = db.parse(
new ByteArrayInputStream(sb.toString().getBytes())
);
String name = getElementData(doc, "name");
String age = getElementData(doc, "age");
String password = getElementData(doc, "password");
out.print("Parameters are name: " + name
+ " age: " + age
+ " password: " + password
);
} catch (Exception e) {
e.printStackTrace();
out.print("error");
}
out.close();
}
9 页面部分更新,只更新表格部分
(1) html文件的实现 :
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Online super store</title>
<script type="text/javascript" src="js/utils.js"></script>
<script type="text/javascript" src="js/kettasAjax.js"></script>
<script type="text/javascript">
function initStore(){
kettasAjax.getText("listProduct.jsp", display);
}
function display(txt){
$("store").innerHTML = txt;
}
</script>
</head>
<body οnlοad="initStore();">
<div id="store"></div>
</body>
</html>
(2) listProduct.jsp内容如下 :
<%@ page language="java" contentType="text/html; charset=GBK"
pageEncoding="GBK"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<jsp:useBean id="store" class="com.kettas.ajax.xhr.day1.SuperStore" scope="application"/>
<table border="1">
<tbody>
<c:forEach var="product" items="${store.products}">
<tr>
<td>${product.id }</td>
<td>${product.name }</td>
<td>${product.price}</td>
</tr>
</c:forEach>
</tbody>
</table>
- 于Ajax中的Json
Json 是一种线上协议,轻量级的xml 一种文体格式
Json的功能,简单的说,就是实现字符串和对象之间的转换。要使用其功能,在客户端,要引入
json.js文件,在服务器端,则要引入json.jar这个包。
Json对象和数组 {}大括号代表一个对象,,【】代表数组
(1) Json在客户端的应用实例 :
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSON test</title>
<script type="text/javascript" src="js/json.js"></script>
<script type="text/javascript" src="js/utils.js"></script>
<script type="text/javascript">
// 创建一个对象,注意格式 {}
var product = {
id: 1, name: "core java", price: 100 };
// 创建一个对象字符串,注意格式
var s = '{"id": 1, "name": "George", "age":30}';
// 实现对象和字符串之间的互换 只须stringify和parse这两个方法即可
function display(){
// 将对象转换为字符串,发送给服务器处理
byId("json").innerHTML = JSON.stringify(product);
// 将字符串转换为对象,把服务端的字符串组装成对象
var student = JSON.parse(s);
alert(student.id + "\t" + student.name + "\t" + student.age); }
</script>
</head>
<body οnlοad="display()"><h2>
<div id="json"></div>
</h2>
</body>
</html>
(2) Json在客户端和服务器端同时应用 :
1 客户端html文件 :
<html><head>
<title>Query Price</title>
<script type="text/javascript" src="js/json.js"></script>
<script type="text/javascript" src="js/kettasAjax.js"></script>
<script type="text/javascript" src="js/utils.js"></script>
<script type="text/javascript">
function query(){
// obj4form是一个工具函数 根据表单id 将用户输入表单的数据封装为一个对象
var car = obj4form("carInfo");
// 直接向服务器发送对象字符串
//"queryPrice"是访问servlet地址,JSON.stringify(car)发送对象字符串,display为服务器返回内容
kettasAjax.postText("queryPrice", JSON.stringify(car), display);
}
function display(txt){
// 将从服务器返回的对象字符串转换为对象
var ret = JSON.parse(txt);
var model = ret.model;
var price = ret.price;
$("result").innerHTML = model + " " + price
}
</script>
</head>
<body>
<h2>Please enter car information</h2>
<!-- 利用输入的汽车id和生产厂商信息 得以查询汽车的价格 -->
<form action=#" id="carInfo">
Id: <input type="text" id="id"/><br/>
Make: <input type="text" id="make"/><br/>
</form>
<button οnclick="query()">Query Price</button>
<div id="result"></div>
</body>
</html>
2 Servlet文件QueryPriceServlet的片段 :
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/plain");
BufferedReader reader = request.getReader();//得到客户端的字符串
PrintWriter out = response.getWriter();
StringBuilder sb = new StringBuilder();
String str = null;
while((str = reader.readLine()) != null)
sb.append(str);
try { // 将客户端发送的对象字符串转化为JSONObject对象
JSONObject jsonObj = new JSONObject(sb.toString());
// 获得对象中的数据 注意格式
int id = jsonObj.getInt("id");
String make = jsonObj.getString("make");
// 不用make.equals("Audi") 避免了make == null的情况下抛异常 小技巧
if(id == 1 && "Audi".equals(make)){
// 给客户端回应一个对象字符串 注意格式// 首先创建一个新的JSONObject对象
jsonObj = new JSONObject();
// 向这个对象中填充数据
jsonObj.put("model", "A8");
jsonObj.put("price", 860000);
// 将对象转化为对象字符串 回发给客户端
// 这个对象字符串的格式为 : '{"model" : "A8" , "price" : 860000}'
out.print(jsonObj.toString());
}
} catch (Exception e) {
e.printStackTrace(); throw new ServletException(e);
}finally{ out.close();
}}
(3) 在服务器端将java中的实体bean、collections、array以及map对象转换为对象字符串 :
要实现这个功能,可以借助内部工具类JsonUtil.java,其中的几个方法是很有用的,如 :
public static JSONObject bean2Json(Object bean),
public static JSONObject map2Json(Map map),
public static JSONArray array2Jarr(Object value),
public static JSONArray collection2Json(Object value)
测试类片段如下 :
public class TestJsonUtil {
public static void main(String[] args) {
SuperStore ss = new SuperStore();
// ss.getProducts()方法返回一个商品对象的集合
JSONArray jarr = JsonUtil.collection2Json(ss.getProducts());
System.out.println(jarr.toString());
}
}
11 关于Ajax中的dwr框架 :
有了dwr框架,操作html页面感觉就是在直接操作java代码。实际上,还是通过服务器端执行的。
要使用此框架提供的功能,必须引入dwr.jar这个包。
思想:在web上的servlet动态生成javascript代码
(1) 最简单的实例
java类文件 :
package com.kettas.ajax.dwr.day4;
public class Hello {
public String sayHello(String user){
try{
Thread.sleep(2000);
}catch(Exception e){
}
return "Hello, " + user;
}
}
配置文件dwr.xml(与web.xml处于同一个位置) :
<dwr>
<allow>
<!-- javascript="hello"指定客户端对象名称为hello
creator="new"指定java对象的创建方式
scope="application"指定java对象的放置位置 -->
<create javascript="hello" creator="new" scope="application">
<param name="class" value="com.kettas.ajax.dwr.day4.Hello"></param>
</create>
</allow>
</dwr>
客户端html文件的内容 :
<!-- 服务器动态生成的js文件 内有hello对象 -->
<script type="text/javascript" src="dwr/interface/hello.js"></script>
<!-- dwr引擎包 -->
<script type="text/javascript" src="dwr/engine.js"></script>
<!-- 引入dwr提供的工具包 -->
<script type="text/javascript" src="dwr/util.js"></script>
<script type="text/javascript">
// element.style.visibility = "hidden";
// element.style.visibility = "";
// CSS内容 对象的隐藏属性
/*
// 这样写的话 仅此函数就可以了
function sayHello(){
// 直接给参数赋内部函数
hello.sayHello($("user").value, function(txt){
dwr.util.setValue("helloStr", txt);
});
}*/
/*
// 也可以这么写 最简便
function sayHello(){
// hello是在dwr.xml配置的,hello.sayHello相当调用服务端的方法,($("user").value 参数,display回调方法,返回值就是display(text)中的text值
hello.sayHello($("user").value, display);
}
*/
// 这么写 是最完整的
function sayHello(){
//dwr.util.useLoadingMessage("Wait a minute...");
// 给参数赋一个对象
var cb = {
callback: display, // 指定回调函数
timeout: 500, // 指定等待时间 如果超出这个时间 则出错
errorHandler: display, // 指定处理错误的回调函数
// ???
name: "George"
};
// 在客户端调用方法 始终比服务端对应方法要多一个参数
// 这个参数最终的实现是一个回调函数
// 这个回调函数的参数就是服务端方法返回的对象(在客户端是javascript对象)
hello.sayHello($("user").value, cb);
}
function display(txt){
// 调用工具包中的工具函数 为容器添加文本
dwr.util.setValue("helloStr", txt);
}
</script>
</head>
<body>
<h2 id="h2">Please enter a user who you want to say hello to:</h2>
User: <input type="text" id="user"/><button οnclick="sayHello()">Say Hello</button><br/>
<div id="helloStr"></div>
</body>
</html>
在web.xml文件中不妨加上如下内容作为测试用 :
<servlet>
<servlet-name>dwr</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dwr</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
(2) 实例 : 人员管理
Person实体类 : Integer id; String name; String address; float salary;
人员管理类PersonMgmt :
package com.kettas.ajax.dwr.day5;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class PersonMgmt {
private Map<Integer, Person> people = new HashMap<Integer, Person>();
private static int count = 10;
public PersonMgmt() {
Person fred = new Person("Fred", "1 Red Street", 2, 100000.0f);
Person jim = new Person("Jim", "42 Brown Lane", 3, 20000.0f);
Person shiela = new Person("Shiela", "12 Yellow Road", 4, 3000000.0f);
people.put(new Integer(fred.getId()), fred);
people.put(new Integer(jim.getId()), jim);
people.put(new Integer(shiela.getId()), shiela);
}
public Collection<Person> getPeople() {
return people.values();
}
public Person getPerson(Integer id) {
return people.get(id);
}
public void add(Person p) {
//如果p中没有值时执行
if (p.getId() == -1)
p.setId(count++);
people.put(p.getId(), p);
}
public void remove(Person p) {
people.remove(p.getId());
}
}
配置文件dwr.xml :
<dwr>
<allow>
<create javascript="personMgmt" creator="new" scope="session">
<param name="class" value="com.kettas.ajax.dwr.day5.PersonMgmt"></param>
</create>
<!-- 由于客户端传入的是javascript的Person对象
故这里要声明对应的服务器端java的Person对象
否则服务端将无法将对象从客户端类型转换为服务端类型
<convert》转换器,对象到字符串之间的转换 -->
<convert match="com.kettas.ajax.dwr.day5.Person" converter="bean"></convert>
</allow>
</dwr>
客户端html文件内容 :
<title>Person Management</title>
<script type="text/javascript" src="dwr/engine.js"></script>
<script type="text/javascript" src="dwr/util.js"></script>
<script type="text/javascript" src="dwr/interface/personMgmt.js"></script>
<script type="text/javascript">
// 初始化显示人员信息
function init(){
personMgmt.getPeople(fillTable);
}
// 函数数组
var peoplebodyCellFuncs = [
// 函数参数为人员对象 返回值即我们要在单元格中显示的内容
// 此数组的长度即表主体显示内容的列数
function(person) { return person.name;},
function(person) { return person.address;},
function(person) { return person.salary;},
// 在第四列添加两个操作按钮
function(person) {
var div = document.createElement("div");
div.appendChild(createBtn("personId", person.id, prepareEdit, "Edit"));
div.appendChild(createBtn("personId", person.id, removePerson, "Remove"));
return div;
}
];
// 编辑人员信息
function prepareEdit(){
var personId = this.personId; // 获得此人id 注意这里this的使用
personMgmt.getPerson(personId, fillFields) // 调用服务端方法 获得此人对象
}
// 填充人员信息编辑表
function fillFields(person){
// person对象如下 : {id : 1, name : "yinkui", address : "xf", salary : 50000}
// 相当于执行 : document.getElementById("id").value = 1
// document.getElementById("name").value = "yinkui" ...
dwr.util.setValues(person);
}
// 删除一个人
function removePerson(){
var personId = this.personId; // 获得此人id 注意这里this的使用
// 由于对应服务端java方法中 删除一个人只需要此人id
// 故 创建person对象时只需要赋予id
// 这样传到服务端 创建的java的Person对象顶多是其他属性为null
var person = {
id: personId
};
personMgmt.remove(person, init); // 调用服务端方法删除此人 然后刷新人员信息表的显示
}
// 创建按钮的函数
function createBtn(attrName, attrValue, onclick, label){
var btn = document.createElement("button");
btn[attrName] = attrValue; // 按钮对象中存放对应人员id值
btn.onclick = onclick; // 为按钮添加事件
btn.appendChild(document.createTextNode(label)); // 为按钮添加显示内容
return btn;
}
// 填充人员信息表
// 其中people对象是从服务端返回的人员对象数组
// 其格式为[{id : 1, name : "yinkui", address : "xf", salary : 50000}, {...}, ...]
function fillTable(people){
dwr.util.removeAllRows("peoplebody");// 调用工具函数 清空表主体中的所有行
// 调用工具函数 通过人员对象数组 为表主体添加行
// 其中peoplebodyCellFuncs是一个函数数组
dwr.util.addRows("peoplebody", people, peoplebodyCellFuncs);
clearPerson();// 初始化人员信息编辑表的内容
}
// 添加新人员
function writePerson(){
var person = {
id: -1,
name: null,
address: null,
salary: null
};
// 注意此工具函数的使用
// 其作用与dwr.util.setValues({...})恰恰相反
// 相当于执行 : person.id = document.getElementById("id").value
// person.name = document.getElementById("name").value
dwr.util.getValues(person);
personMgmt.add(person, init); // 调用服务端方法 然后刷新人员信息表的显示
}
// 初始化显示人员信息编辑表
function clearPerson(){
// 注意此工具函数的使用 参数为对象
// 相当于执行 : document.getElementById("id").value = -1
// document.getElementById("name").value = null ...
dwr.util.setValues(
{ id: -1, name: null,
salary: null, address: null
}
);
}
</script>
</head>
<body οnlοad="init()">
<h1>Dynamically Editing a Table</h1>
<h2>People Management</h2>
<!-- 人员信息列表 -->
<table border="1">
<!-- 表头 -->
<thead>
<tr> th>Name</th>
<th>Address</th>
<th>Salary</th>
<th colspan="2">Actions</th></tr>
</thead>
<!-- 表的主体 -->
<tbody id="peoplebody"></tbody>
</table>
<h4>Edit Person</h4>
<!-- 对人员信息进行编辑 或是添加新人员 -->
<table>
<tr><td>ID:</td>
<td><span id="id">-1</span></td></tr>
<tr><td>Name:</td>
<td><input id="name" type="text" /></td></tr>
<tr><td>Salary:</td>
<td><input id="salary" type="text" /></td></tr>
<tr><td>Address:</td>
<td><input type="text" id="address" /></td></tr>
<tr><td colspan="2" align="right">
<input type="button" value="Save" οnclick="writePerson()" />
<input type="button" value="Clear" οnclick="clearPerson()" /></td></tr>
</table></body></html>
12,关于DOJO的框架:
含义:Dojo是一个非常强大的面向对象的JavaScript的工具箱, 建议读者能够去补充一下JavaScript下如何使用OO进行编程的, 这对于你以后阅读Dojo Source有很大的用处
作用:①处理浏览器的不兼容问题,可以方便建立互动的互动用户见面。②更容易统一页面风格。③封装与服务端的通信,动态从服务器下载javascript
开发流程:①把dojo工具包考到js文件下
②引用 dojo 的启动代码
<script type="text/javascript" src="/yourpath/dojo.js" />
③声明你所要用到的包
<script type="text/javascript">
dojo.require("dojo.math");引入数学方法
dojo.require("dojo.io.*"); 引入io
dojo.require("dojo.event.*"); 引入事件
dojo.require("dojo.widget.*");引入页面
function init(){ 初始化
var btn = dojo.widget.byId("helloBtn");
dojo.event.connect(btn, "onClick", "sayHello");事件源,产生关联,时间方法
}
function sayHello(){
dojo.io.bind(
{ url: "sayHello.jsp",处理事件的url
handler: callback, 回调函数
formNode: "myForm" 表单内容
});}
function callback(type, data, evt){
document.getElementById("result").innerHTML
= data;
}
dojo.addOnLoad(init);加入事件
</script>
</head>
<body>
<h2>DOJO Test</h2>
<form action="#" id="myForm">
User: <input type="text" name="user" />
</form>
<button dojoType="Button" widgetId="helloBtn">DOJO Say Hello</button>
<div id="result"></div>
</body>
</html>
13,关于Ext框架
参考项目文档
14补充:Dom部分 创建标签 var td=document.createElement(“td”); td.apperdchild(childName)
javascript的高级部分
1,javascript的对象和继承 由于javascript是采取prototype机制的“伪继承”,prototype必须显示引用“基类”对象,所以注定了javascript只能实现“弱继承”,或者叫做“对象继承”
注意这里的次序关系需要很明确,prototype的赋值必须在对象构造之外。
function classA()
{ classA.prototype.name=”xxx”;属性
classA.prototype.methodA = function() {...}这是一个对象方法
classA.methodA = function(){...} //这是一个类方法相当于java的static方法
}
function classB()
{ classB.prototype.methodA = function(){...}
}
classB.prototype = new classA();
//注意这里声明B继承自A出现在function classB()函数体之外,并且先于
//classB对象的构造被执行。
私有成员的设置
Var name=“zhang”;
this.getName=function(){return name;}
this.setName=function(myname){name=myname; }