Java學習路線-47:Ajax學習XMLHttpRequest、XStream、json-lib

課時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>
發佈了1418 篇原創文章 · 獲贊 370 · 訪問量 130萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章