课时1 1.ajax简介(异步与同步)
asynchronous javascript and xml
异步js和xml
1、异步交互和同步交互
同步 发送,等待 整个页面刷新
异步 发送,不等待 局部刷新
示例:异步刷新
<button id="btn">点击</button> <h2 id="text"></h2> <script> // 文档加载完成后马上执行 window.onload = function(){ let btn = document.getElementById("btn"); // 给btn注册点击事件监听 btn.onclick = function(){ let text = document.getElementById("text"); text.innerHTML= "hello!"; } } </script>
课时2 2.异步和同步交互图
数据格式
text、xml、json
同步:
请求 -> 响应 <- 请求 -> 响应 <-
异步:
请求 -> 请求 -> 响应 <- 响应 <-
课时3 3.ajax的应用场景和优缺点
优点:
异步交互,增强用户体验
性能:只需要响应部分内容,服务器压力减少
缺点:
ajax不能应用在所有场景
ajax增多了对服务器的请求,给服务器增加压力
课时4 4.ajax四步操作
1、获取XMLHttpRequest
// 大多数浏览器 var xmlHttp = new XMLHttpRequest(); // IE6.0 var xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); // IE<=5.5 var xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
编写一个创建XMLHttpRequest对象的函数
function createXMLHttpRequest(){ try{ // 大多数浏览器 return new XMLHttpRequest(); }catch(e){ try{ // IE6.0 new ActiveXObject("Msxml2.XMLHTTP"); }catch(e){ try{ // IE<=5.5 new ActiveXObject("Microsoft.XMLHTTP"); }catch(e){ console.log("浏览器版本太老了!"); throw e; } } } }
2、连接服务器
xmlHttp.open("GET", "/url", true); // 参数:请求方式,请求url,是否为异步
3、发送请求
xmlHttp.send(null); // 参数:请求体内容,如果是GET,必须给出null,不然FireFox可能不发送
4、注册事件监听器
(1)5个状态:
0 刚创建 1 请求开始,调用open 2 请求发送完成 调用send 3 服务器开始响应 4 服务器响应结束
(2)获取响应内容
// 获取状态 var state = xmlHttp.readyState; // 得到服务器响应状态码 200, 404, 500 var status = xmlHttp.status; // 得到服务器响应内容 var content = xmlHttp.responseText; // 文本格式 var content = xmlHttp.responseXml; // xml格式,document对象
(3)注册监听事件
xmlHttp.onreadystatechange = function(){ // 双重判断 xmlHttp状态为服务器响应结束,服务器状态响应结束 if(xmlHttp.readyState == 4 && xmlHttp.status == 200){ var text = xmlHttp.responseText; } }
课时5 5.ajax第一例:helloworld
为了便于测试,服务端使用Python语言
服务端 hello.py
# pip install flask, flask-cors from flask import Flask from flask_cors import CORS app = Flask(__name__) CORS(app, supports_credentials=True) @app.route("/") def index(): return "<h2>Hello!</h2>" if __name__ == '__main__': app.run()
客户端 demo.html
<button id="btn">点击</button> <h2 id="text"></h2> <script> // 获取XMLHttpRequest对象 function createXMLHttpRequest(){ try{ // 大多数浏览器 return new XMLHttpRequest(); }catch(e){ try{ // IE6.0 new ActiveXObject("Msxml2.XMLHTTP"); }catch(e){ try{ // IE<=5.5 new ActiveXObject("Microsoft.XMLHTTP"); }catch(e){ console.log("浏览器版本太老了!"); throw e; } } } } // 文档加载完成后马上执行 window.onload = function(){ let btn = document.getElementById("btn"); // 给btn点击事件注册监听 btn.onclick = function(){ let xmlHttp = createXMLHttpRequest(); xmlHttp.open("GET", "http://127.0.0.1:5000/", true); xmlHttp.send(); xmlHttp.onreadystatechange = function(){ // 双重判断 xmlHttp状态为服务器响应结束,服务器状态响应结束 if(xmlHttp.readyState == 4 && xmlHttp.status == 200){ var text = xmlHttp.responseText; let h2 = document.getElementById("text"); h2.innerHTML= text; } } } } </script>
6.ajax第二例:发送POST请求
多添加一个请求头
// 设置请求头 xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // 发送请求体 xmlHttp.send("username=Tom&age=23");
服务端接收函数 hello.py
@app.route("/post", methods=['POST']) def post(): username = request.form.get("username") age = request.form.get("age") return f"<h2>username: {username}, age: {age}</h2>"
客户端修改 demo.html
xmlHttp.open("POST", "http://127.0.0.1:5000/post", true); xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xmlHttp.send("username=Tom&age=23");
课时7 7.ajax第三例:用户名是否已被注册
客户端要求:
1、注册表单
2、监听用户名文本框失去焦点onblur事件
3、获取文本框内容,通过ajax异步发送给服务器
4、如果为1 显示:用户名已被注册
如果为0 什么都不显示
<meta charset="utf-8"> <style> #errorText { color: red; } </style> <form action=""> <input type="text" name="username" id="username"> <span id="errorText"></span> </form> <script> // 获取XMLHttpRequest对象 function createXMLHttpRequest() { try { // 大多数浏览器 return new XMLHttpRequest(); } catch (e) { try { // IE6.0 new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { // IE<=5.5 new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { console.log("浏览器版本太老了!"); throw e; } } } } // 文档加载完成后马上执行 window.onload = function () { let username = document.getElementById("username"); // 失去焦点注册事件监听 username.onblur = function () { let xmlHttp = createXMLHttpRequest(); xmlHttp.open("POST", "http://127.0.0.1:5000/validate", true); xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xmlHttp.send("username=" + username.value); xmlHttp.onreadystatechange = function () { // 双重判断 xmlHttp状态为服务器响应结束,服务器状态响应结束 if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { var text = xmlHttp.responseText; let errorText = document.getElementById("errorText"); if (text == '1') { errorText.innerHTML = "用户名已被注册"; } else { errorText.innerHTML = ""; } } } } } </script>
服务端要求:
1、获取客户端传递的用户名参数
2、判断是否为demo,是返回1,否返回0
@app.route("/validate", methods=['POST']) def validate(): username = request.form.get("username") if username == "demo": return "1" else: return "0"
课时8 8.ajax第四例:响应内容为xml
服务端响应头
Content-Type: text/xml; charset=utf-8
客户端设置
var doc = xmlHttp.responseXML; // 得到Document对象
服务端代码
@app.route("/xml") def xml(): data = """ <person> <name>Tom</name> <age>23</age> </person> """ res = make_response(data) res.headers['Content-Type'] = 'text/xml; charset=utf-8' return res
客户端代码
<button id="btn">点击</button> <h2 id="text"></h2> <script> // 获取XMLHttpRequest对象 function createXMLHttpRequest() { try { // 大多数浏览器 return new XMLHttpRequest(); } catch (e) { try { // IE6.0 new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { // IE<=5.5 new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { console.log("浏览器版本太老了!"); throw e; } } } } // 判断是否为IE浏览器 function isIE() { if (window.addEventListener) { return false; } else { return true; } } // 文档加载完成后马上执行 window.onload = function () { let btn = document.getElementById("btn"); // 注册事件监听 btn.onclick = function () { let xmlHttp = createXMLHttpRequest(); xmlHttp.open("GET", "http://127.0.0.1:5000/xml", true); xmlHttp.send(null); xmlHttp.onreadystatechange = function () { // 双重判断 xmlHttp状态为服务器响应结束,服务器状态响应结束 if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { // 获取响应结果 var doc = xmlHttp.responseXML; // IE 和非IE有所区别 let name = doc.getElementsByTagName("name")[0].textContent; let age = doc.getElementsByTagName("age")[0].textContent; let text = document.getElementById("text"); text.innerHTML = `name: ${name}, age: ${age}`; } } } } </script>
课时9-10 ajax第五例:省市联动
<select name="province" id=""> <option value="">请选择省份</option> </select> <select name="city" id=""> <option value="">请选择城市</option> </select>
服务端提供两个接口
province
city?province=北京
完整代码
一、前端代码
1、util.js
// 获取XMLHttpRequest对象 function createXMLHttpRequest() { try { // 大多数浏览器 return new XMLHttpRequest(); } catch (e) { try { // IE6.0 new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { // IE<=5.5 new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { console.log("浏览器版本太老了!"); throw e; } } } } // 判断是否为IE浏览器 function isIE() { if (window.addEventListener) { return false; } else { return true; } }
2、demo.html
<select name="province" id="province"> <option value="">请选择省份</option> </select> <select name="city" id="city"> <option value="">请选择城市</option> </select> <script src="./util.js"></script> <script> function createOption(name) { // 创建option元素 let option = document.createElement("option"); option.value = name; // 创建文本节点 let textNode = document.createTextNode(name); option.appendChild(textNode); return option; } // 文档加载完成后马上执行 window.onload = function () { // 第一步:先获取省级列表 let xmlHttp = createXMLHttpRequest(); xmlHttp.open("GET", "http://127.0.0.1:5000/provinces", true); xmlHttp.send(null); let province = document.getElementById("province"); xmlHttp.onreadystatechange = function () { // 双重判断 xmlHttp状态为服务器响应结束,服务器状态响应结束 if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { // 获取响应结果 var text = xmlHttp.responseText; let list = text.split("|"); // 拆分数据得到数组 for (let item of list) { let option = createOption(item); province.appendChild(option); } } } // 第二步:监听省级列表变动,获取城市列表 province.onchange = function () { if (province.value == "") { return } let xmlHttp = createXMLHttpRequest(); xmlHttp.open("POST", "http://127.0.0.1:5000/cities", true); xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xmlHttp.send(`province=${province.value}`); xmlHttp.onreadystatechange = function () { // 双重判断 xmlHttp状态为服务器响应结束,服务器状态响应结束 if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { // 移除所有结果 let city = document.getElementById("city"); let optionList = city.getElementsByTagName("option"); while (optionList.length > 1) { city.removeChild(optionList[1]); } // 获取响应结果 var doc = xmlHttp.responseXML; let cities = doc.getElementsByTagName("city"); for (let item of cities) { let cityName = ""; // 兼容IE浏览器和其他浏览器 if (isIE()) { cityName = item.text; // IE } else { cityName = item.textContent; // FireFox等 } let option = createOption(cityName); city.appendChild(option); } } } } } </script>
二、后端代码
1、数据文件china.xml
<china> <province name="北京"> <city>东城区</city> <city>西城区</city> </province> <province name="天津"> <city>和平区</city> <city>河东区</city> </province> </china>
2、数据解析文件demo.py
# pip install lxml from lxml import etree class China(): path = "china.xml" @classmethod def getProvinces(cls): """获取省份 """ tree = etree.parse(cls.path) return tree.xpath('//province/@name') @classmethod def getCities(cls, province): """获取城市 """ tree = etree.parse(cls.path) result = tree.xpath(f"//province[@name='{province}']") if result: return etree.tostring(result[0], encoding="UTF-8") else: return "" if __name__ == "__main__": print(China.getProvinces()) print(China.getCities("北京"))
3、接口文件
from flask import Flask, request, make_response from flask_cors import CORS from demo import China app = Flask(__name__) CORS(app, supports_credentials=True) @app.route("/provinces") def provinces(): return "|".join(China.getProvinces()) @app.route("/cities", methods=['POST']) def cities(): province = request.form.get("province") res = make_response(China.getCities(province)) res.headers['Content-Type'] = 'text/xml; charset=utf-8' return res if __name__ == '__main__': app.run(debug=True)
课时11 11.XStream(可把Javabean转换成XMl的小工具)
依赖
<dependency> <groupId>xstream</groupId> <artifactId>xstream</artifactId> <version>1.2.2</version> </dependency>
代码实例
import com.thoughtworks.xstream.XStream; import java.util.ArrayList; import java.util.List; class City { private String name; public City(String name) { this.name = name; } } class Province { private String name; private List<City> cities = new ArrayList<>(); public void addCity(City city){ cities.add(city); } public Province(String name) { this.name = name; } } public class TestXStream { public static void main(String[] args) { // 数据准备 List<Province> list = new ArrayList<Province>(); Province province = new Province("北京"); province.addCity(new City("东城区")); province.addCity(new City("昌平区")); list.add(province); XStream xStream = new XStream(); // 指定别名 xStream.alias("china", List.class); xStream.alias("province", Province.class); xStream.alias("city", City.class); // 属性设置 xStream.useAttributeFor(Province.class, "name"); // 去除无用的标签 xStream.addImplicitCollection(Province.class, "cities"); String str = xStream.toXML(list); System.out.println(str); } }
课时12 12.JSON的概述
js提供的一种数据交换格式
Json语法
属性名必须使用双引号括起来
对象:{} 属性: null、数值、字符串、数组[]、boolean(true/false)
var s = "1 + 2"; eval(s); // 3
1、示例
(1)服务端代码
from flask import Flask, jsonify from flask_cors import CORS app = Flask(__name__) CORS(app, supports_credentials=True) @app.route("/json") def json(): return jsonify({"name": "Tom"}) if __name__ == '__main__': app.run(debug=True)
(2)客户端代码
<button id="btn">点击</button> <h2 id="text"></h2> <script src="./util.js"></script> <script> // 文档加载完成后马上执行 window.onload = function () { let btn = document.getElementById("btn"); btn.onclick = function () { let xmlHttp = createXMLHttpRequest(); xmlHttp.open("GET", "http://127.0.0.1:5000/json", true); xmlHttp.send(null); xmlHttp.onreadystatechange = function () { // 双重判断 xmlHttp状态为服务器响应结束,服务器状态响应结束 if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { // 获取响应结果 let text = xmlHttp.responseText; let obj = JSON.parse(text); document.getElementById("text").innerHTML = `name: ${obj.name}`; } } } } </script>
json与xml比较
可读性
解码难度
流行度
课时13 13.json-lib的应用
继承关系
public final class JSONArray extends AbstractJSON implements JSON, List, Comparable public final class JSONObject extends AbstractJSON implements JSON, Map, Comparable
依赖
<dependency> <groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <version>2.4</version> <classifier>jdk15</classifier> </dependency>
示例
设置标签
import net.sf.json.JSONObject; class Demo { public static void main(String[] args) { JSONObject map = new JSONObject(); map.put("name", "Tom"); map.put("age", 23); String str = map.toString(); System.out.println(str); // {"name":"Tom","age":23} } }
java对象转为json
Person.java
public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
Demo.java
import net.sf.json.JSONArray; import net.sf.json.JSONObject; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; class Demo { public static void main(String[] args) { // 对象转JSONObject Person person = new Person("Tom", 23); JSONObject obj = JSONObject.fromObject(person); System.out.println(obj.toString()); // {"name":"Tom","age":23} // List转 JSONArray List<Person> list = new ArrayList<Person>(); list.add(new Person("Tom", 23)); list.add(new Person("Jack", 23)); JSONArray array = JSONArray.fromObject(list); System.out.println(array.toString()); // [{"age":23,"name":"Tom"},{"age":23,"name":"Jack"}] // map转JSONObject Map<String ,String> map = new HashMap<String ,String>(); map.put("name", "Tom"); map.put("sex", "male"); System.out.println(JSONObject.fromObject(map).toString()); // {"sex":"male","name":"Tom"} } }
课时14 14.打包ajax生成小工具
参数
option{ method url asyn type callback params data }
xml
text
json
后端接口
from flask import Flask, request, jsonify from flask_cors import CORS app = Flask(__name__) CORS(app, supports_credentials=True) @app.route("/json", methods=["GET", "POST"]) def json(): username = request.args.get("username") if request.method == "POST": username = request.form.get("username") if request.is_json: username = request.json.get("username") return jsonify({"name": username}) if __name__ == '__main__': app.run(debug=True)
封装的工具 ajax-util.js
// 获取XMLHttpRequest对象 function createXMLHttpRequest() { try { // 大多数浏览器 return new XMLHttpRequest(); } catch (e) { try { // IE6.0 new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { // IE<=5.5 new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { console.log("浏览器版本太老了!"); throw e; } } } } // 判断是否为IE浏览器 function isIE() { if (window.addEventListener) { return false; } else { return true; } } /** * 将对象转为url查询参数 * @param {*} data * { "name": "Tom", "age": 23 } * -> name=Tom&age=23 */ function encodeData(data) { if (!data) { return null; } let list = []; for (let [key, value] of Object.entries(data)) { list.push(`${key}=${value}`); } return list.join("&"); } const CONTENT_TYPE = "Content-Type"; const contentTypeMap = { html: "text/html; charset=utf-8", xml: "text/xml; charset=utf-8", json: "application/json; charset=utf-8", form: "application/x-www-form-urlencoded" } /** * * @param {*} option: * method * url * asyn * type * callback * params * data */ function ajax(option) { // 必传参数 let url = option.url; let callback = option.callback; // 可选参数 let method = option.method || "GET"; let asyn = option.asyn || true; let params = option.params || {}; let type = option.type || "html"; let data = option.data || {}; let xmlHttp = createXMLHttpRequest(); // 处理响应数据 xmlHttp.onreadystatechange = function () { // 双重判断 xmlHttp状态为服务器响应结束,服务器状态响应结束 if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { // 获取响应结果 let responseData = null; if (xmlHttp.responseXML) { responseData = xmlHttp.responseXML; } else { responseData = xmlHttp.responseText; try { responseData = JSON.parse(responseData); } catch (e) { } } callback(responseData); } } // 处理请求数据 if (params) { url = url + "?" + encodeData(params); } xmlHttp.open(method, url, asyn); xmlHttp.setRequestHeader(CONTENT_TYPE, contentTypeMap[type]); let sendData = null; if (type == "json") { sendData = JSON.stringify(data); } else { sendData = encodeData(data); } xmlHttp.send(sendData); } // console.log(encodeData(undefined));
测试代码
<button id="get-btn">GET</button> <h2 id="get-text"></h2> <button id="post-btn">POST</button> <form action=""> <input type="text" name="username" id="username"> </form> <h2 id="post-text"></h2> <script src="./ajax-util.js"></script> <script> // 文档加载完成后马上执行 window.onload = function () { // get方法 let getBtn = document.getElementById("get-btn"); getBtn.onclick = function () { ajax({ url: "http://127.0.0.1:5000/json", method: "GET", params: { "username": "Tom" }, callback: function (data) { console.log(data); document.getElementById("get-text").innerHTML = data.name; } }) }; // post方法 let postBtn = document.getElementById("post-btn"); postBtn.onclick = function () { ajax({ url: "http://127.0.0.1:5000/json", method: "POST", type: "json", params: { "username": "Tom" }, data: { "username": document.getElementById("username").value }, callback: function (data) { console.log(data); document.getElementById("post-text").innerHTML = data.name; } }) } } </script>