Ajax


通信协议

协议: 规范

协议的写法

简单协议的写法:

协议名称://主机:端口/资源/子资源?key1=value1&key2=value2

复杂协议的写法

主协议名称:子协议名称://主机:端口/资源/子资源?key1=value1&key2=value2

http://baidu.com:80/index.html

获取服务器数据的方式

  • 同步获取数据: 页面有刷新,浏览器的地址栏会发生改变,用户体验不好
  • 异步获取数据: 实现页面的局部更新,浏览器的地址栏不发生改变,用户体验很好,也是现在主流的请求数据的方式;一般我们使用ajax进行异步数据的获取

jdbc

java database connection

image-20211213195053915


使用jdbc连接数据库

  • 准备好java的开发环境

  • 准备驱动包 mysql-connector-java-8.0.22.jar

  • 编写代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    package com.xzy;

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.Statement;

    public class Ops1 {
    public static void main(String[] args) throws Exception {
    //1. 加载驱动
    Class.forName("com.mysql.cj.jdbc.Driver");
    //2. 获取"连接"对象
    String url = "jdbc:mysql://localhost:3306/youdian?serverTimezone=Asia/Shanghai";
    String username = "root";
    String password = "root";
    Connection conn = DriverManager.getConnection(url, username, password);
    //3. 准备sql语句
    String sql = "insert into city(name,pid)values('庆阳市',2)";
    //4. 执行sql语句
    Statement statement = conn.createStatement();
    int rows = statement.executeUpdate(sql);
    if (rows > 0) {
    System.out.println("添加数据成功");
    }
    //5. 释放资源
    statement.close();
    conn.close();
    }
    }

java中的类库


jdbc进行CURD

添加数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.xzy;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

public class Ops1 {
public static void main(String[] args) throws Exception {
//1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获取"连接"对象
String url = "jdbc:mysql://localhost:3306/youdian?serverTimezone=Asia/Shanghai";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 准备sql语句
String sql = "insert into city(name,pid)values('庆阳市',2)";
//4. 执行sql语句
Statement statement = conn.createStatement();
int rows = statement.executeUpdate(sql);
if (rows > 0) {
System.out.println("添加数据成功");
}
//5. 释放资源
statement.close();
conn.close();
}
}

修改数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.xzy;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

/**
* 修改数据
*/
public class Ops2 {
public static void main(String[] args) throws Exception {
//1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获取"连接"对象
String url = "jdbc:mysql://localhost:3306/youdian?serverTimezone=Asia/Shanghai";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 准备sql语句
String sql = "update city set name='庆阳市1' where id=204";
//4. 执行sql语句
Statement statement = conn.createStatement();
int rows = statement.executeUpdate(sql);
if (rows > 0) {
System.out.println("数据修改成功");
}
//5. 释放资源
statement.close();
conn.close();
}
}


删除数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.xzy;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

/**
* 删除数据
*/
public class Ops3 {
public static void main(String[] args) throws Exception {
//1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获取"连接"对象
String url = "jdbc:mysql://localhost:3306/youdian?serverTimezone=Asia/Shanghai";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 准备sql语句
String sql = "delete from city where id=204";
//4. 执行sql语句
Statement statement = conn.createStatement();
int rows = statement.executeUpdate(sql);
if (rows > 0) {
System.out.println("数据删除改成功");
}
//5. 释放资源
statement.close();
conn.close();
}
}

查询数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.xzy;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

/**
* 删除数据
*/
public class Ops4 {
public static void main(String[] args) throws Exception {
//1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获取"连接"对象
String url = "jdbc:mysql://localhost:3306/youdian?serverTimezone=Asia/Shanghai";
String username = "root";
String password = "root";
Connection conn = DriverManager.getConnection(url, username, password);
//3. 准备sql语句
String sql = "select * from city";
//4. 执行sql语句
Statement statement = conn.createStatement();

//执行查询语句,返回一个ResultSet对象
ResultSet resultSet = statement.executeQuery(sql);
//游标向下移动
while (resultSet.next()) {
System.out.println(resultSet.getInt("id"));
System.out.println(resultSet.getString("name"));
}
//5. 释放资源
resultSet.close();
statement.close();
conn.close();
}
}

jdbc中的sql注入问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.xzy;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

/**
* 登录功能
*/
public class Ops5 {

public static void main(String[] args) throws Exception {
//顺口溜 "贾连欲执事"
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/youdian?serverTimezone=Asia/Shanghai";
Connection conn = DriverManager.getConnection(url, "root", "root");
//模拟用户输入
String username = "admin11111 ' or 1=1 -- ";
String password = "admin1231";
Statement statement = conn.createStatement();
String sql = "select * from user where username='" + username + "' and password='" + password + "'";
ResultSet resultSet = statement.executeQuery(sql);
if (resultSet.next()) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}

}

}

以上的sql在执行过程中存在很大的问题,sql注入问题;


解决sql注入问题

1
conn.createStatement();这种方式创建的statement都是存在sql注入问题,不建议使用

使用 ? 作为sql语句的占位符,结合PreparedStatement 来解决sql注入的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.xzy;

import java.sql.*;

/**
* 登录功能
*/
public class Ops5 {

public static void main(String[] args) throws Exception {
//顺口溜 "贾连欲执事"
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/youdian?serverTimezone=Asia/Shanghai";
Connection conn = DriverManager.getConnection(url, "root", "root");
//模拟用户输入
String username = "admin";
String password = "admin123";
String sql = "select * from user where username=? and password=?";
PreparedStatement statement = conn.prepareStatement(sql);
statement.setString(1,username);
statement.setString(2,password);
ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
System.out.println("登录成功");
} else {
System.out.println("登录失败");
}

}
}

jdbc中的事务操作

jdbc中的事务默认是自动提交的;

我们要向手动的控制事务的提交必须要设置: conn.setAutoCommit(false);


jdbc中的批处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.xzy;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
* 登录功能
*/
public class Ops7 {

public static void main(String[] args) throws Exception {
Connection conn = null;
//顺口溜 "贾连欲执事"
Class.forName("com.mysql.cj.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/youdian?serverTimezone=Asia/Shanghai";
conn = DriverManager.getConnection(url, "root", "root");
PreparedStatement preparedStatementAdd = conn.prepareStatement("insert into user(username,password) values(?,?)");

for (int i = 0; i < 100; i++) {
preparedStatementAdd.setString(1, "aaa" + i);
preparedStatementAdd.setString(2, "AAA" + i);
preparedStatementAdd.addBatch();
}
preparedStatementAdd.executeBatch();
}
}

json数据格式介绍

现在主流的开发中数据的传输格式:

  • xml
  • json

json数据格式

  • json对象的数据格式

    1
    2
    3
    4
    5
    {
    "id": 100,
    "name": "小明",
    "age": 30
    }
  • json数组的数据格式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [
    {
    "id": 100,
    "name": "小明",
    "age": 30
    },
    {
    "id": 200,
    "name": "小花",
    "age": 20
    }
    ]

    注意: json中的key一定要包含双引号,value如果不是字符串类型,不加双引号;


js中的对象和json互相转换

1
2
3
4
//把js中的对象转换为json格式的字符串
const jsonStr = JSON.stringify(obj);
//把json格式的字符串转为js中的对象
console.log(JSON.parse(jsonStr))

Http协议

http(Hyper Text Transfer Protocol)超文本传输协议

http底层是基于tcp协议,但是http是短连接;


Http协议为什么建立的是短连接?

长连接是非常耗费服务器的cpu资源的,web端的应用场景一般都是短连接

http协议的短连接病并不是说tcp协议第短连接,而是一次请求建立tcp连接,响应结束之后又会断开tcp连接

Http的版本

  • http1.0
  • http1.1(主流的版本),实现了同一会话的,固定时间之内的http连接的复用

目前主流的http的应用

  • http协议: 超文本传输协议,默认端口为80
  • https协议(基于http的一种加密协议),默认端口为 443

Http协议详解

  • 请求数据包

    • 请求行
    • 请求头
    • 请求实体
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #请求行
    POST https://fanyi.baidu.com/v2transapi?from=zh&to=en HTTP/1.1
    #请求头
    Host: fanyi.baidu.com
    Connection: keep-alive
    Content-Length: 146
    sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="96", "Google Chrome";v="96"
    Accept: */*
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    X-Requested-With: XMLHttpRequest
    sec-ch-ua-mobile: ?0
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36
    sec-ch-ua-platform: "Windows"
    Origin: https://fanyi.baidu.com
    Sec-Fetch-Site: same-origin
    Sec-Fetch-Mode: cors
    Sec-Fetch-Dest: empty
    Referer: https://fanyi.baidu.com/
    Accept-Encoding: gzip, deflate, br
    Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
    Cookie: BIDUPSID=0FC1D9004EBF6C0ADC29F9CF859186AB; PSTM=1639567242; BAIDUID=0FC1D9004EBF6C0A855E532D592AC6C5:FG=1; BAIDUID_BFESS=0FC1D9004EBF6C0A855E532D592AC6C5:FG=1; delPer=0; PSINO=2; H_PS_PSSID=34448_35106_34584_35491_35329_35316_26350_35312; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; BA_HECTOR=a42ha58l842ha1a4nh1grjlu60q; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1639569367; __yjs_duid=1_5cb244490827d2b8282bb8a7a21870c61639569368190; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1639569384; ab_sr=1.0.1_Mjk1YzBjMzI3NmIxYzI0YzJmMzM3YmMwY2VlNDI2OTY4NmE5Njc1ZmQyZGFmYzY1MWFmOWJiZTE3Nzg0Nzg4YmQ1YTQ5NGVmZjc4YTY2MGZhZWM2MTYzZTg2MGQwMWFkOGExMDFlMmRhOWI3M2VjYWE1YTcwZDZjNDU4YWI2Y2JkZDY5MjZhNTMzMGU2Nzc5MDA0YmUyYzZhY2Y4NzAzZQ==; __yjs_st=2_NTBiYjQyZjBhODlmYTc4NzJiOTFkNDBjYjdmNzQwNmUyOTFjOTkzM2UxMDkxYmY3NjUzOGEzOTU1NDRkMDI0MGNiNjc0ZmQ1MWEyYjk5NWM0NGE0ZDE5ZjIxMDY0Y2NjYmU2MTkxYmJlNTZlMmFkZThhZDk5ZmZmM2ZkMzJjM2U1MjllZDM2MTcwMGU1ZDhjNGZlODZhZTQ2MTU5MDgxMWJlMmZiZWFmYzA3YjBmZjg0ZDA5NjM1N2FhMzNlMmYyOTBkZWRlZjY1NTExZTQ5NGE5YmM3NjM5ZjYwNDM3MTEwNTJhMDU1NGQzZjhiNjk1ZDI1NmEzOWQ5ZWVkOTY1Zl83XzczYmIwYTdh

    #请求实体
    from=zh&to=en&query=%E4%BD%A0%E5%A5%BD&transtype=enter&simple_means_flag=3&sign=232427.485594&token=1082f914a7120fea0cb89c08e8b0ca0f&domain=common

注意:

  1. 请求数据包中的第一行就是请求行; 请求方式 请求地址 协议版本
  2. 第一行往后,空行之前都是请求头; key: value
  3. 空行往后开始都是请求实体;
  • 响应数据包
    • 响应行
    • 响应头
    • 响应实体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#响应行
HTTP/1.1 200 OK
#响应头
Cache-Control: no-cache, private
Content-Encoding: gzip
Content-Type: application/json
Date: Wed, 15 Dec 2021 11:57:24 GMT
Server: Apache
Tracecode: 34440933802685789194121519
Vary: Accept-Encoding
Transfer-Encoding: chunked

#响应实体
eeb

注意:

  1. 响应数据包中的第一行为响应行; 协议版本 响应码 响应信息
  2. 第一行往后,空行之前都是响应头; key: value
  3. 空行往后都是响应实体; 页面上需要呈现的数据在响应实体中;

http的的请求方式

1
2
3
4
5
6
GET
POST
HEAD
PUT
DELETE
OPTIONS

GET请求与其他请求的不同:

  • 凡是在浏览器的地址栏输入地址,看到的页面使用的请求方式都是GET,因为浏览器的地址栏不支持其他请求方式;

  • GET请求不能有请求实体的,所有的请求参数必须在url中携带;

    1
    http://localhost:8080?key1=value1&key2=value2

    不同的浏览器对url的长度有不同的限制,google浏览器的限制 1024byte

  • GET请求的参数在URL地址栏中携带,是不安全的,POST请求的参数既可以在地址栏携带,也可以在请求实体中携带;

  • POST请求在请求实体中携带数据,是相对 安全 ;

  • GET请求是可以做资源定位;


Http中的响应码与相应信息

1
2
3
4
5
6
7
8
9
10
200 OK
400 Bad Request
401 Unauthorized
404 Not Found
405 Method Not Allowed
415 Unsupported Media Type
500 Internal Server Error
502 Bad Gateway
504 Gateway Time-out
505 HTTP Version not supported

MimeType媒体类型

1
2
3
4
5
6
7
text/plain  原生的文本类型
text/html html类型
text/css css类型
text/javascript js类型
application/json json类型
image/jpeg 图片类型
.....其他的用到再查

后端接口

  • 大家先学会使用
  • 学会调试接口 java -jar xxx.jar

获取城市列表接口

请求地址: http://localhost:8080/city/listAll

请求方式: GET

参数: 无


获取城市对应的学校列表接口

请求地址: http://localhost:8080/school/listByCid

请求方式: POST

请求参数: cid=xxx


接口调试

  • 借助浏览器的地址栏进行接口的调试

    • 优点: 简单
    • 缺点: 浏览器的地址栏只支持GET请求,不支持其他请求方式
  • 借助接口调试工具(推荐使用的做法)

    • PostMan
    • PostWoman
    • Insomnia

同步请求与异步请求

同步请求:

在浏览器给服务器发送请求到接收响应的过程中,浏览器不能做其他的事,只能等等着服务器的响应,直到成功;

同步请求,浏览器的地址栏中的url会发生变化

eg:

1
<a href="http://localhost:8080/city/listAll">获取城市列表</a>

以上的点击a标签之后,页面发生跳转,发送的是同步请求,浏览器的地址栏发生了变化;

异步请求:

在浏览器给服务器发送请求的过程中,浏览器还可以进行其他的业务操作

异步请求,浏览器的地址栏不会发生变化


原生的js中发送异步请求(ajax)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>异步请求</title>
</head>
<body>
<button id="btnGetCityList">从服务器获取城市列表</button>
</body>
<script>
window.onload = function () {
//获取元素
let btnCityList = document.querySelector("#btnGetCityList");
//给元素添加点击事件
btnCityList.onclick = function () {
//发送异步请求
//1. 创建xhr对象
const xhr = new XMLHttpRequest();
//2. 给xhr绑定请求的地址
xhr.open("GET", "http://localhost:8080/city/listAll");
//3. xhr发送请求
xhr.send();
//4. 接收响应 监听连接状态的改变
xhr.onreadystatechange = function () {
//一般我们对 4(浏览器正确的接收的响应信息,并且正确的处理了) 状态码进行判断
if (xhr.readyState === 4) {
//获取响应实体
const respText = xhr.responseText;
//把json字符串解析成js中的对象
const respArray = JSON.parse(respText);
//遍历
// for (let i = 0; i < respArray.length; i++) {
// console.log(respArray[i])
// }

// for (let respArrayKey in respArray) {
// console.log(respArray[respArrayKey])
// }
respArray.forEach(city=>console.log(city))
}
}
}
}
</script>
</html>

jQuery中的封装的ajax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jQuery中封装的ajax</title>
<script src="jquery-1.9.1.min.js"></script>
</head>
<body>
<button id="btnCityList">点我获取城市列表</button>

<button id="btnSchoolList">点我获取学校列表</button>
<script>
$(function () {
$("#btnCityList").click(function () {
$.ajax({
url: "http://localhost:8080/city/listAll",
type: "GET",//type不写默认为"GET"
dataType: "json",
success: function (resp) {
console.log("成功:", resp)
},
error: function (msg) {
console.log("失败:", msg)
}
});
});
$("#btnSchoolList").click(function () {
$.ajax({
url: "http://localhost:8080/school/listByCid",
type: "POST",
data: {
cid: 2
},//非 "GET"请求,请求实体中携带的数据
dataType: "json",
success(resp) {
console.log("成功:", resp)
}
});
});
});
</script>
</body>
</html>

基于jQuery的二级联动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>基于jQuery的二级联动</title>
<style>
#root {
width: 400px;
height: 300px;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: center;
}

button {
width: 120px;
letter-spacing: 3px;
}

select, button {
width: 130px;
height: 30px;
}

select[name=citySelect] {
}
</style>
<script src="jquery-1.9.1.min.js"></script>
</head>
<body>
<div id="root">
<select name="citySelect" id="citySelect">
</select>
<select name="schoolSelect" id="schoolSelect">
</select>
<button>点击查询</button>
<script>
$(function () {
const citySelect = $("#citySelect")
const schoolSelect = $("#schoolSelect")
//1. 获取城市列表
$.ajax({
url: "http://localhost:8080/city/listAll",
success(resp) {
resp.forEach(city => {
const optionStr = `<option value="${city.id}">${city.name}</option>`;
citySelect.append(optionStr);
})
//做一次初始化的学校数据的渲染
renderSchoolListByCid(citySelect.val())
}
});

citySelect.change(function () {
renderSchoolListByCid(this.value)
});

//按钮的点击事件
$("button").click(function () {
console.log("城市:" + citySelect.val(), "学校:" + schoolSelect.val())
});

/**
*获取并渲染学校列表
* @param cid 城市id
*/
function renderSchoolListByCid(cid) {
$.ajax({
url: "http://localhost:8080/school/listByCid",
type: "POST",
data: {cid},
dataType: "json",
success(resp) {
schoolSelect.empty();//清空select中的option
resp.forEach(school => {
const optionStr = `<option value="${school.id}">${school.name}</option>`;
schoolSelect.append(optionStr);
})
}

});

}
});
</script>
</div>
</body>
</html>

axios

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

发送请求Get请求:

1
2
3
4
5
6
7
axios.get("http://localhost:8080/city/listAll")
.then(function (resp) {
console.log("成功:", resp)
})
.catch(function (msg) {
console.log("失败:", msg)
})

文章作者: Yang Shiyu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Yang Shiyu !
  目录