使用jQuery和原生Javascript实现Ajax

  • Post author:
  • Post category:java




1.ajax的基本介绍

什么是ajax?

AJAX = Asynchronous JavaScript And XML.

AJAX 并非编程语言。

AJAX 仅仅组合了:

  • 浏览器内建的 XMLHttpRequest 对象(从 web 服务器请求数据)
  • JavaScript 和 HTML DOM(显示或使用数据)

Ajax 是一个令人误导的名称。Ajax 应用程序可能使用

XML

来传输数据,但将数据作为

纯文本



JSON

文本传输也同样常见。

Ajax 允许通过与场景后面的 Web 服务器交换数据来异步更新网页。这意味着可以更新网页的部分,而不需要重新加载整个页面。



2.使用jQuery实现ajax

语法

 $.ajax({name:value, name:value, ... })

该参数规定 AJAX 请求的一个或多个名称/值对。

下面的表格中列出了可能的名称/值:

image-20210825092601268

案例

这里是一个案例:
image-20210824194244972

文本框输入值后,当鼠标移出,文本框失去焦点时,就会调用ajax来发送请求,判断文本框内容是否符合要求。

如果用户名的值等于admin时,会出现true,反之则为false。

正确:

image-20210824194449848

错误:

image-20210825121821819

JSP前端页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <%--导入jQuery,注意点:路径问题--%>
    <script type="text/javascript" src="${pageContext.request.contextPath}/static/js/jquery-3.5.1.js"></script>
</head>
<body>
<%--文本框失去焦点时触发ajax--%>
用户名:<input type="text" id="textname" οnblur="add()"/>
<span id="text1"></span>
<script>
    function add() {
        $.get({
            url: "${pageContext.request.contextPath}/a1",
            data: {"name": $("#textname").val()},
            success: function (val) {
                if (val.toString() === 'true') {
                    $('#text1').css("color", "green");
                } else {
                    $('#text1').css("color", "red");
                }
                $("#text1").html(val);
            }
        })
    }
</script>
</body>
</html>

servlet类:

public class AjaxDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        if ("admin".equals(name)) {
            resp.getWriter().print("true");
        } else {
            resp.getWriter().print("false");
        }
    }
}


当然,别忘了在web.xml中设置相应的路由。

注意点

  1. 导入jQuery时,要注意路径问题,src的路径要加上${pageContext.request.contextPath}
  2. ajax中data数据使用jQuery进行选择html网页中的元素时,要注意选择器,例如id为

    textname

    的元素需要使用

    $("#textname")
  3. 当路径问题产生时,要重启tomact服务器,不要选择重新部署或者更新类和资源,因为有时候会不起作用(因为这个问题搞了一个下午)
  4. 在servlet类中需要使用

    req.getParameter

    来获取前端的传来的参数,返回方法的数值时使用

    resp.getWriter().print()

    方法
  5. 如果想使用post方式只需将

    $.get

    改为

    $.post

    即可

案例

这里还有一个实例:

点击按钮后,会使用ajax来请求后端数据库中传来的数据,并且渲染在这个表格中。

点击前:

image-20210824195841508

点击后:

image-20210824200031007

JSP前端页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script src="${pageContext.request.contextPath}/static/js/jquery-3.5.1.js"></script>
</head>
<body>
<button οnclick="show()">点击</button>
<table align="center" width="80%">
    <tr>
        <td>姓名</td>
        <td>年龄</td>
        <td>专业</td>
    </tr>
    <tbody id="content"></tbody>
</table>

<script>
    function show() {
        $.post({
            url: "${pageContext.request.contextPath}/a1",
            success: function (data) {
                console.log(data);
                let parse = JSON.parse(data);
                html = "";
                html += "<tr>" +
                    "<td>" + parse.name + "</td>" +
                    "<td>" + parse.age + "</td>" +
                    "<td>" + parse.major + "</td>" +
                    "</tr>";
                $("#content").html(html);
            }
        })
    }
</script>
</body>
</html>

servlet类:

public class AjaxDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HashMap hashMap = new HashMap();
        hashMap.put("name", "zovz");
        hashMap.put("age", "18");
        hashMap.put("major", "computer");

        String str = "{";
        Set set = hashMap.keySet();
        for (Object o : set) {
            str += "\"" + o + "\":" + "\"" + hashMap.get(o) + "\",";
        }
        resp.getWriter().print(str.substring(0, str.length() - 1) + "}");
    }
}

这里创建了hashmap来模拟数据库返回的数据,通过遍历进行字符串的拼接,将它JSON形式的字符串,最后返回到前端时,再转化为JSON对象。

返回的JSON形式的字符串:{“major”:“computer”,“name”:“zovz”,“age”:“18”}

使用jQuery来实现ajax很方便,因为都是已经封装好的,调用只需要记住哪几步就可以实现,但使用一项技术,我们还得了解一下它的原理,接下来我们来看如何使用原生JS来实现ajax。



3. 使用原生Javascript实现ajax

在使用原生JS实现ajax之前,先来介绍一下ajax的基本步骤和涉及的元素的各种方法,以下资料来源于W3school。

这是资料来源地址:https://www.w3school.com.cn/js/js_ajax_intro.asp

ajax如何工作

ajax

  1. 网页中发生一个事件(页面加载、按钮点击)
  2. 由 JavaScript 创建 XMLHttpRequest 对象
  3. XMLHttpRequest 对象向 web 服务器发送请求
  4. 服务器处理该请求
  5. 服务器将响应发送回网页
  6. 由 JavaScript 读取响应
  7. 由 JavaScript 执行正确的动作(比如更新页面)

XMLHttpRequest 对象方法

image-20210824201722657

XMLHttpRequest 对象属性

image-20210824201822718



向服务器发送请求

如需向服务器发送请求,我们使用 XMLHttpRequest 对象的 open() 和 send() 方法:

image-20210824201939668

开始案例

使用JS实现ajax一共有以下五个步骤:

第一种情况:发送GET请求:

JSP前端页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<button>点击发送请求</button>
<script>
    window.onload = function () {
        var btn = document.querySelector("button");
        btn.onclick = function () {
            //1.创建一个异步对象
            var xmlHttp = new XMLHttpRequest();
            
            //2.设置请求地址和请求方式
            xmlHttp.open("GET", "${pageContext.request.contextPath}/a2", true);
            
            //3.发送请求
            xmlHttp.send();
            
            //4.监听状态的变化
            xmlHttp.onreadystatechange = function () {
                if (xmlHttp.readyState === 4) {
                    if (xmlHttp.status >= 200 && xmlHttp.status < 300 || xmlHttp.status === 304) {
                        //5.返回处理的结果
                        console.log("接受到服务器返回的结果");
                        alert(xmlHttp.responseText);
                    } else {
                        console.log("没有接受到服务器返回的结果");
                    }
                }
            }

        }
    }
</script>
</body>
</html>

servlet类:

public class test extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().print("HELLO");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

点击后结果:

image-20210824203030809
image-20210824203040436

第二种情况:发送POST请求:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<button>开始</button>
      <script>
        window.onload = function () {
            var oBtn = document.querySelector("button");
            oBtn.onclick = function () {
                //1.创建一个异步对象
                var xmlhttp = new XMLHttpRequest();

                //2.设置请求方式和请求地址
                //在IE浏览器中需要再每次请求之后更换新的地址
                xmlhttp.open("POST", "${pageContext.request.contextPath}/a2", true);

                //注意:以下代码必须放到open和send之间
                xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

                //3.发送请求
                xmlhttp.send("username=zovz&pwd=123456");

                //4.监听状态的变化
                xmlhttp.onreadystatechange = function () {
                    if (xmlhttp.readyState === 4) {
                        //判断是否请求成功
                        if (xmlhttp.status >= 200 && xmlhttp.status < 300 || xmlhttp.status === 304) {
                            //5.处理返回的结果
                            console.log("接受到服务器返回的结果");
                            //返回文本
                            alert(xmlhttp.responseText);
                        } else {
                            console.log("没有接受到服务器返回的结果");
                        }
                    }
                }
            }
        }
    </script>
</body>
</html>

注意点



  1. IE浏览器

    中需要在每次请求之后更换新的地址,即在url后不时地更新参数,以达到不同访问地址的目的,因为IE浏览器会默认将请求过的地址与返回的结果关联起来,如果url重复,会返回第一次返回的结果。
  2. xmlhttp.open()中的async参数必须一直都设置为

    true

    ,因为ajax就是实现异步的。
  3. xmlhttp.status要大于200小于300,但还有304也表示请求成功。

当然,上面这种形式只是为了描述ajax发送请求的五个步骤,将它进行封装后,假设要发送一串数据:

JSP前端页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="myAjax.js"></script>
</head>
<body>
<button>开始</button>
<script>
    window.onload = function () {
        let btn = document.querySelector("button");
        btn.onclick = function () {
            ajax("${pageContext.request.contextPath}/a2", {
                "username": "zovz",
                "pwd": "123456"
            }, 3000, function (xhr) {
                alert(xhr.responseText);
            }, function (xhr) {
                alert("请求失败");
            })
        }
    }
</script>
</body>
</html>

myAjax.js:

//将JSP页面的data数据拼接到一起,组成键值对与要发送的url进行合并
function obj2(obj) {
    //加上t,表示现在的时间,以确保每次发送的url都不同
    obj.t = new Date().getTime();
    var res = [];
    for (var key in obj) {
        res.push(key + "=" + obj[key]);//[username=zovz,pwd=123456]
    }
    return res.join("&");//username=zovz&pwd=123456
}

function ajax(url, obj, timeout, success, error) {

    var str = obj2(obj);

    //1.创建一个异步对象
    var xmlHttp = new XMLHttpRequest();

    //2.设置请求地址和请求方式
    xmlHttp.open("GET", url + "?" + str, true);

    //3.发送请求
    xmlHttp.send();

    //4.监听状态的变化
    xmlHttp.onreadystatechange = function (ev2) {
        if (xmlHttp.readyState == 4) {
            if (xmlHttp.status >= 200 && xmlHttp.status < 300 || xmlHttp.status == 304) {
                //5.返回处理的结果
                success(xmlHttp);
            } else {
                error(xmlHttp);
            }
        }
    }

    //设置超时
    if (timeout) {
        timer = setInterval(function () {
            console.log("中断请求");
            xmlHttp.abort();
            clearInterval(timer);
        }, timeout);
    }
}

servlet类:

public class test extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String pwd = req.getParameter("pwd");
        resp.getWriter().print(username + ":" + pwd);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

返回结果:

image-20210824215825197

问题

我们使用原生JS手写的ajax成功运行,并且已经解决了每次发送都会产生新的url,但是还是有以下缺点:

  1. 如果data值是中文该怎么办,众所周知,中文在url中是不可传递的,url里面只可以存在字母,数字,下划线和ASCll码。
  2. 如果我想将GET和POST请求写成小写,可以继续传递吗?
  3. 如果我这次想传递GET请求,但是下一次想传递POST请求,难道要我一直在js代码中修改吗?
  4. 我想使用ajax,但是传递参数的顺序必须和我之前定义的方法的参数顺序要一致,这会很麻烦,如果我不想遵守这些规则,我想让url在后,而success方法在前,那我该如何做?

首先,我给出问题1的解决方案:

    var res = encodeURI("username=张三");
    //返回 username=%E5%BC%A0%E4%B8%89

我们可以使用encodeURI方法将键值对中的中文进行编码,再进行传输,然后在服务端接收时,再将它转化为相对应的中文即可。

接下来,我给出问题2和问题3的解决方案:

我们可以在ajax中再多传递一个参数type,可以通过前端指定传输类型来确定使用哪种请求方式。而大小写问题,只需要使用下面的方式即可,因为小写的小写还是小写,我们只需将所传的type都设置为小写。

   if (type.toLowerCase() === "GET") {
        xmlHttp.open("GET", url + "?" + str, true);
        xmlHttp.send();
    } else if (type.toLowerCase() === "POST") {
        xmlHttp.open("POST", url, true);
        xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xmlHttp.send(str);
    }

下面是我的测试代码:

JSP前端页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="static/js/myAjax.js"></script>
</head>
<body>
<button>发送请求</button>
<script>
    window.onload = function () {
        let btn = document.querySelector("button");
        btn.onclick = function () {
            ajax("get","${pageContext.request.contextPath}/a2", {
                "username": "张三",
                "pwd": "123456"
            }, 3000, function (xhr) {
                alert(xhr.responseText);
            }, function () {
                alert("请求失败");
            })
        }
    }
</script>
</body>
</html>

myAjax.js:

function obj2(obj) {
    obj.t = new Date().getTime();
    var res = [];
    for (var key in obj) {
        res.push(key + "=" + obj[key]);//[username=zovz,pwd=123456]
    }
    return res.join("&");//username=zovz&pwd=123456
}

function ajax(type, url, obj, timeout, success, error) {
    //使用encodeURI编码
    var str =encodeURI(obj2(obj));
    //1.创建一个异步对象
    var xmlHttp = new XMLHttpRequest();

    if (type.toLowerCase() === "get") {
        //2.设置请求地址和请求方式
        xmlHttp.open("GET", url + "?" + str, true);
        //3.发送请求
        xmlHttp.send();

    } else if (type.toLowerCase() === "post") {
        //2.设置请求地址和请求方式
        xmlHttp.open("POST", url, true);
        //注意:以下代码必须放到open和send之间
        xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        //3.发送请求
        xmlHttp.send(str);
    }

    //4.监听状态的变化
    xmlHttp.onreadystatechange = function () {
        if (xmlHttp.readyState === 4) {
            if (xmlHttp.status >= 200 && xmlHttp.status < 300 || xmlHttp.status === 304) {
                //5.返回处理的结果
                success(xmlHttp);
            } else {
                error(xmlHttp);
            }
        }
    }

    //设置超时

    if (timeout) {
        timer = setInterval(function () {
            console.log("中断请求");
            xmlHttp.abort();
            clearInterval(timer);
        }, timeout);
    }
}

servlet类:

public class test extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf8");
        resp.setContentType("TEXT/HTML;charset=utf-8");
        String username = req.getParameter("username");
        String pwd = req.getParameter("pwd");
        resp.getWriter().print(username + ":" + pwd);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

返回结果:

image-20210825102132106

接下来给出问题4的解决方案:

因为我不想再遵守方法定义的参数顺序,那我可以传入一个对象,而type,data等作为对象的属性,在传递的过程中使用

对象.属性

的方法就可以解决。

下面是我的测试代码:

JSP前端页面:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script type="text/javascript" src="static/js/myAjax.js"></script>
</head>
<body>
<button>发送请求</button>
<script>
    window.onload = function () {
        let btn = document.querySelector("button");
        btn.onclick = function () {
            ajax({
                type: "get",
                url: "${pageContext.request.contextPath}/a2",
                data: {"username": "张三", "pwd": "123456"},
                timeout: 3000,
                success: function (xhr) {
                    console.log(xhr.responseText);
                    alert(xhr.responseText);
                },
                error: function () {
                    alert("请求失败");
                }
            });
        }
    }
</script>
</body>
</html>

myAjax.js:

function obj2(obj) {
    obj.t = new Date().getTime();
    var res = [];
    for (var key in obj) {
        res.push(key + "=" + obj[key]);//[username=zovz,pwd=123456]
    }
    return res.join("&");//username=zovz&pwd=123456
}

function ajax(object) {
//function ajax(type, url, data, timeout, success, error)

    var str = encodeURI(obj2(object.data));
    //1.创建一个异步对象
    var xmlHttp = new XMLHttpRequest();

    if (object.type.toLowerCase() === "get") {
        //2.设置请求地址和请求方式
        xmlHttp.open("GET", object.url + "?" + str, true);
        //3.发送请求
        xmlHttp.send();

    } else if (object.type.toLowerCase() === "post") {
        //2.设置请求地址和请求方式
        xmlHttp.open("POST", object.url, true);
        //注意:以下代码必须放到open和send之间
        xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        //3.发送请求
        xmlHttp.send(str);
    }

    //4.监听状态的变化
    xmlHttp.onreadystatechange = function () {
        if (xmlHttp.readyState === 4) {
            if (xmlHttp.status >= 200 && xmlHttp.status < 300 || xmlHttp.status === 304) {
                //5.返回处理的结果
                object.success(xmlHttp);
            } else {
                object.error(xmlHttp);
            }
        }
    }

    //设置超时
    if (object.timeout) {
        timer = setInterval(function () {
            console.log("中断请求");
            xmlHttp.abort();
            clearInterval(timer);
        }, object.timeout);
    }
}

这样就实现了我们手写的Ajax方法参数顺序任意,这也就是使用jQuery封装的ajax方法。



版权声明:本文为qq_46549203原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。