Ajax异步技术

ajax

在提交表单发送请求时,会导致页面刷新,不利于一些例如视频观看等操作。使用Ajax异步技术可以解决这一需求。

XMLHttpRequest js 是中的对象, 它可以用来向服务器发送请求,但不会导致页面刷新跳转。

1. XMLHttpRequest 对象基本使用

  1. 创建 xhr 对象
var xhr = new XMLHttpRequest();

2. 发送请求

xhr.open("get|post", 请求地址, true|false); // 发请求前准备
xhr.send(); // 真正发送请求

3. 接收响应

xhr.responseText 

需要的响应通常不是一个完整的html, 而是一个html片段,或是一个字符串

4. open的第三个参数

true 默认值 – 异步请求, send 方法不会阻塞,页面其他代码,视频都不会等待响应,继续执行
false – 同步请求 响应没有返回之前,页面代码、视频都会暂停,直到响应返回为止,send方法在此期间一直处于阻塞状态

异步请求下需要使用事件的机制来接收响应

// 响应返回会触发 onload事件,执行事件对应的函数
xhr.onload = function () {

};

// 发送请求时会触发, 响应返回时会触发,  响应完全返回时会触发
xhr.onreadystatechange = function() {
    //xhr.readyState // 状态 
    // xhr 创建时 0
    // xhr.send 0-->1
    // xhr. 1--> 2 2-->3
    // 3--> 4 表示响应完全返回
    if(xhr.readyState == 4) {

    }
}

5. post 请求

  • get 请求只有请求行和请求头
  • post 请求行、请求头、请求体
var xhr = new XMLHttpRequest();
xhr.onload = function(){};

// 发请求
xhr.open("post", url, true);
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded"); // 告诉服务器,请求体的格式是:表单格式
xhr.send("请求体内容"); // 参数名=参数值&参数名=参数值

6. 简化xhr对象的使用

// url 请求地址 例如:/commentServlet
// param 请求参数 例如: "comment=" + document.getElementById("c").value
// callback 回调函数 例如:
function c (x) {
    document.getElementById("result").innerText = x.responseText;
}

post("/commentServlet", "comment=" + document.getElementById("c").value, c)

funciton post(url, param, callback) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() { // 当 onload 事件发生时,才会执行 c 函数
        c(xhr); // 调用 c 函数
    };
    xhr.open("post", url, true);
    xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
    xhr.send(param);
}

下面的写法不正确:

funciton post(url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.onload = c(xhr); // 立刻执行c的内容,将结果赋值给了 onload
    xhr.open("post", url, true);
    xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
    xhr.send("comment=" + document.getElementById("c").value);
}

7. 响应格式

主流格式有两种:

  1. xml (可扩展标记语言)
<response>
    <time>2019-1-19 11:43:33</time>
    <author>张三</author>
    <content>还不错</content>
    <score>11</score>
</response>

var xml = xhr.responseXML;
xml.getElementsByTagName(“time”)[0].innerText;

  1. json (javascript object 对象 notation 标记)
    {
    “time”:“2019-1-19 11:43:33”,
    “author”:“张三”,
    “content”: “还不错”,
    “score”: 11
    }
    var obj = …
    obj.time

json中除了解析方便外,还支持更多类型 字符串、数字、布尔值、数组、对象

8. Ajax的定义

多种技术的统称

  • a - asynchronous - 可以通过 xhr 对象发送异步请求
  • j - javascript
  • a - and
  • x - xml - 指响应格式

synchronized 同步的

9. XMLHttpRequest 完整api

https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest

10. json

  1. 把 java 对象转换为 json 字符串, 或反之
    转换json的第三方 api, gson(谷歌),jackson(spring),fastjson(阿里)
  2. js 对象和 json 字符串相互转换
var js对象 = JSON.parse(json字符串);
var json字符串 = JSON.stringify(js对象);

jackson
重要的类:

ObjectMapper om = new ObjectMapper();
String json = om.writeValueAsString(java对象);

还原操作

ObjectMapper om = new ObjectMapper();
类型 java对象 = om.readValue(json字符串,.class);
  • 如果要对日期进行控制,在日期属性上添加注解: @JsonFormat(pattern=“日期格式”, timezone=“GMT+08”)

  • 如果要忽略某个属性:在属性上添加一个 @JsonIgnore 注解

  • 如果要转换后改变属性名:@JsonProperty(“新属性名”)

  • java中的map,domain ==> 都会转为 json 的对象 { }

  • java中的list, set, 数组 ==> 都会转为 json 的数组 [ ]

[
{“id”:1,“sex”:“男”,“birthday”:“2019-01-19 15:32:04”,“username”:“张三”},
{“id”:2,“sex”:“男”,“birthday”:“2019-01-19 15:32:04”,“username”:“李四”},
{“id”:3,“sex”:“男”,“birthday”:“2019-01-19 15:32:04”,“username”:“王五”},
{“id”:4,“sex”:“男”,“birthday”:“2019-01-19 15:32:04”,“username”:“赵六”}
]

servlet 中结合 jackson

resp.setCharacterEncoding("utf-8");
resp.setContentType("application/json;charset=utf-8");
List<Student> list = new ArrayList<>();
list.add(new Student(1, "123", "张三", "男", new Date()));
list.add(new Student(2, "456", "李四", "男", new Date()));
list.add(new Student(3, "456", "王五", "男", new Date()));
list.add(new Student(4, "678", "赵六", "男", new Date()));
ObjectMapper om = new ObjectMapper();

// 方法1:
//        String json = om.writeValueAsString(list);
//        resp.getWriter().print(json);
// 方法2:
om.writeValue(resp.getWriter(), list);

Ajax应用

1. 省市县联动

实现一个表单使用三个下拉列表可以选择省市县
1首先创建数据库
存储地名的数据库如下所示

在这里插入图片描述
其中parent_id为上一级地区的id
2.创建存储地区的类(省略了get、set方法)

public class Region {
    private int regionId;
    private int regionCode;
    private String regionName;
    private int parentId;
    private String regionNameEn;

3.Jdbc数据库编程
能够通过parent_id来查询所有子地区的Id

public List<Region> findByParentId(int parentId) {
        String sql = "select * from region where parent_id = ?";
        try (Connection conn = JdbcUtil.getConnection()) {
            try(PreparedStatement stmt = conn.prepareStatement(sql)) {
                stmt.setInt(1, parentId);
                ResultSet rs = stmt.executeQuery();
                List<Region> list = new ArrayList<>();
                while(rs.next()) {
                    Region region = new Region();
                    region.setRegionId(rs.getInt("region_id"));
                    region.setRegionCode(rs.getInt("region_code"));
                    region.setRegionName(rs.getString("region_name"));
                    region.setParentId(rs.getInt("parent_id"));
                    region.setRegionNameEn(rs.getString("region_name_en"));
                    list.add(region);
                }
                return list;
            }
        } catch (SQLException e) {
            e.printStackTrace();
            return Collections.emptyList();
        }
    }

4编写Servlet
通过parent_id返回所有的子地区给Jsp页面,返回的格式为json格式的字符串。

@WebServlet("/region")
public class RegionServlet extends HttpServlet {
    private RegionDao regionDao = new RegionDao();
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String parentId = req.getParameter("parentId");
        List<Region> list = regionDao.findByParentId(Integer.valueOf(parentId));
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("application/json;charset=utf-8");
        ObjectMapper om = new ObjectMapper();
        om.writeValue(resp.getWriter(), list);
    }
}

5 Jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>

</head>
<body><select id="sheng" onchange="findShi()"></select><select id="shi" onchange="findXian()"></select><select id="xian"></select>



    <script>
        function findXian () {
            // 获取省当前选中的 option 的 value
            var parentId = document.getElementById("shi").value;
            var xhr = new XMLHttpRequest();
            xhr.onload = function () {
                var json = xhr.responseText;
                var list = JSON.parse(json);
                // 添加之前要清除下拉列表的内容
                document.getElementById("xian").innerHTML = "";
                // 添加新内容
                for(var i = 0 ; i < list.length; i++) {
                    var region = list[i];
                    // js 生成标签
                    var option = document.createElement("option"); // <option></option>
                    option.value = region.regionId; // <option value="2"></option>
                    option.innerText = region.regionName; // <option value="2">北京</option>
                    // 把它添加给 市 这个父元素
                    document.getElementById("xian").appendChild(option);
                }
            };
            xhr.open("get", "/region?parentId=" + parentId, true);
            xhr.send();
        }

        function findShi () {
            // 获取省当前选中的 option 的 value
            var parentId = document.getElementById("sheng").value;
            var xhr = new XMLHttpRequest();
            xhr.onload = function () {
                var json = xhr.responseText;
                var list = JSON.parse(json);
                // 添加之前要清除下拉列表的内容
                document.getElementById("shi").innerHTML = "";
                // 添加新内容
                for(var i = 0 ; i < list.length; i++) {
                    var region = list[i];
                    // js 生成标签
                    var option = document.createElement("option"); // <option></option>
                    option.value = region.regionId; // <option value="2"></option>
                    option.innerText = region.regionName; // <option value="2">北京</option>
                    // 把它添加给 市 这个父元素
                    document.getElementById("shi").appendChild(option);
                }
                findXian()
            };
            xhr.open("get", "/region?parentId=" + parentId, true);
            xhr.send();
        }

        function findSheng() {
            var xhr = new XMLHttpRequest();
            xhr.onload = function() {
                var json = xhr.responseText;
                var list = JSON.parse(json);
                for(var i = 0 ; i < list.length; i++) {
                    var region = list[i];
                    // js 生成标签
                    var option = document.createElement("option"); // <option></option>
                    option.value = region.regionId; // <option value="2"></option>
                    option.innerText = region.regionName; // <option value="2">北京</option>
                    // 把它添加给 省 这个父元素
                    document.getElementById("sheng").appendChild(option);
                }
                // 联动
                findShi();
            };
            xhr.open("get", "/region?parentId=1", true);
            xhr.send();
        }
        findSheng();
    </script>
</body>
</html>

2. 自动完成(补全)

通过输入框输入的字符来显示数据库中所有有关内容
数据库还是使用上边的地区类型数据。
1 Jdbc编程
通过已有字符来查询以该字符开头的所有地区

 public List<Region> findByName(String name) {
        String sql = "select * from region where region_name like ?";
        try(Connection conn = JdbcUtil.getConnection()) {
            try(PreparedStatement stmt = conn.prepareStatement(sql)){
                //                  name = 西
                stmt.setString(1, name + "%");
                ResultSet rs = stmt.executeQuery();
                List<Region> list = new ArrayList<>();
                while(rs.next()) {
                    Region region = new Region();
                    region.setRegionId(rs.getInt("region_id"));
                    region.setRegionCode(rs.getInt("region_code"));
                    region.setRegionName(rs.getString("region_name"));
                    region.setParentId(rs.getInt("parent_id"));
                    region.setRegionNameEn(rs.getString("region_name_en"));
                    list.add(region);
                }
                return list;
            }
        } catch (SQLException e) {
            e.printStackTrace();
            return Collections.emptyList();
        }
    }

2 编写Servlet

@WebServlet(urlPatterns = "/regionByName")
public class RegionNameServlet extends HttpServlet {

    private RegionDao regionDao = new RegionDao();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        List<Region> list = regionDao.findByName(name);

        resp.setCharacterEncoding("utf-8");
        resp.setContentType("application/json;charset=utf-8");

        ObjectMapper om = new ObjectMapper();
        om.writeValue(resp.getWriter(), list);

    }
}

3 Jsp页面
**js中没有块作用域,如果需要必须用let声明 而不是var **

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <style>
        li {
            list-style: none;

        }
        li:hover {
            background: blue;
            color:white;
        }
        ul {
            display: none;
            border: 1px solid rgb(238,238,238);
            margin: 0;
            padding: 0;
            width: 160px;
            box-shadow: 0px 1px 6px rgba(0,0,0,0.2);
            border-radius: 4px ;
            font-size: 13px;
        }
    </style>
</head>
<body>
    <input type="text" id="name" onkeyup="findByName()" onblur="hideResult()" onclick="toggleResult()">
    <ul id="result"></ul>

    <script>
        function toggleResult() {
            if(document.getElementById("result").style.display == "none") {
                document.getElementById("result").style.display = "block";
            } else {
                document.getElementById("result").style.display = "none";
            }
        }
        function hideResult() {
            setTimeout(function(){
                document.getElementById("result").style.display = "none";
            }, 300);
        }
        function findByName() {
            var xhr = new XMLHttpRequest();
            xhr.onload = function() {
                var json = xhr.responseText;
                var list = JSON.parse(json);
                document.getElementById("result").innerHTML="";
                for(let i = 0; i < list.length; i++) {
                    let li = document.createElement("li");
                    li.innerText = list[i].regionName;
                    li.onclick = function(){
                        document.getElementById("name").value = li.innerText;
                        document.getElementById("result").style.display = "none";
                    };
                    document.getElementById("result").appendChild(li);
                }
                document.getElementById("result").style.display = "block";
            };
            var v = document.getElementById("name").value;
            xhr.open("get", "http://localhost:8080/regionByName?name=" + v);
            xhr.send();
        }
    </script>
</body>
</html>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值