学习笔记:javaEE基础3 Ajax

来源于从网页搭建入门Java Web

这里是Ajax专场,使用ajax技术以JSON作为数据格式进行前后端交互

先胡言两句以前后端用nodejs写的时候觉得超级方便,都是一样的 JSON.parse, JSON.stringify,后面用golang写后端,处理json就有一点不舒服了…


前台还是用jquery吧,使用它的$.ajax 方法,不要和我谈什么过时,封装都大同小异的,况且人家也有Promise式的调用,都是工具嘛,后台需要用到json.jar包,记得之前学android的时候使用的是gson,算了,这个课程中老师用的是前者,保持一致呗,都是工具

从前端到后端

需要发送的数据,目标url为 /ajax/get

1
2
3
4
5
6
7
8
{
"data": {
"name": "星际老男孩",
"id" : 25,
"songs": [{"name": "祝大家新年万事大吉", "singer": "黄旭东"},
{"name": "以爱之名再见宋哈娜", "singer": "孙一峰"}]
}
}

jquery有两种json数据提交方式,第一种是为了兼容没用JSON对象的浏览器的表单提交方法,当然,这里不考虑兼容这类浏览器,所以直接用第二种方式,也就是这接传被stringify之后的JSON数据的方式,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  $.ajax({
url: "/ajax/get",
method: "POST",
contentType: 'application/json; charset=utf-8',
dataType: "json",
data: JSON.stringify({
name: "星际老男孩",
age: 25,
songs: [{name: "祝大家新年万事大吉", singer: "黄旭东"},
{name: "以爱之名再见宋哈娜", singer: "孙一峰"}]
})
}).done(function (data) {
console.log(data)
}).fail(function (data) {
console.error(data);
})
}

后台获取完整数据

注意,这里我已经使用filter将字符全转成utf-8了所以不会有乱码,要用到 JSONObjectJSONArray以及他们的一些方法,不是很难

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
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

// 通过获取输入流来读取buffer的数据
BufferedInputStream bis = new BufferedInputStream(request.getInputStream());
ByteArrayOutputStream buf = new ByteArrayOutputStream();
int result = bis.read();
while(result != -1) {
buf.write((byte) result);
result = bis.read();
}
String str = buf.toString();

/*

ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
String str = result.toString(StandardCharsets.UTF_8.name());
*/

JSONObject jsonObject = new JSONObject(str);
// 解析简单数据
String name = (String)jsonObject.get("name");
Integer age = (Integer)jsonObject.get("age");

System.out.println(name + " " + age);

// 解析对象数组
JSONArray songArr = (JSONArray)jsonObject.get("songs");
for (int i = 0; i < songArr.length(); i++) {
JSONObject song = (JSONObject)songArr.get(i);
String songname = (String)song.get("name");
String singer = (String)song.get("singer");
System.out.println(songname + " " + singer);
}
}

输出

对了,如果发现Intellij IDEA输出乱码,请在保证字符为UTF-8的前提下做如下设置

添上这么一句,在重新编译就可以了

1
-Dfile.encoding=UTF8 -Dsun.jnu.encoding=UTF8

从后端到前端

同理,也是使用之前的那两个对象

1
2
3
4
5
6
7
8
9
10
11
12
...
JSONObject obj = new JSONObject();
obj.put("name", "二五仔");
obj.put("msg", "你完了");
JSONArray array = new JSONArray();
array.put(0, "黄旭东要奶死你");
array.put(1, "孙一峰要干死你");
obj.put("defail", array);

// 设置编码,防止乱码
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(obj.toString());

这时,前台接收到的返回值如下


自己封装一个Ajax工具

首先,无视兼容性,就用 XMLHttpRequest 对象

其次,调用它的 open 方法填入一切参数,包括请求http方法,目标URL以及是否异步发送,对于第三个参数jquery默认就是异步。

第三步就是使用 send 方法发送数据了

监听 onreadystatechange 事件监听是否有相应,当产生该事件的时候就是服务端都回复的时候

查看 readyState 属性,查看是否为3(接收)状态,并查看 status 判断相应的http状态码

readyState的其他数值对于状态如下

  • 0 未初始化。尚未调用 open 方法
  • 1 启动。已调用 open 方法,但尚未调用 send 方法
  • 2 发送。已调用 send 方法,但尚未收到响应
  • 3 接收。已经收到部分响应数据
  • 4 完成。已经接收到全部响应数据

开始封装的第一步,如上面所描述的那几步

1
2
3
4
5
6
7
8
9
10
11
12
13
function ajax(obj, callback) {
var xmlhttp = new XMLHttpRequest();

// 这里的值都是用户自己设置的
xmlhttp.open(obj.method, obj.url, obj.async);
if (obj.contentType != null) {
xmlhttp.setRequestHeader("Content-Type", obj.contentType);
}
xmlhttp.send(obj.data);
xmlhttp.onreadystatechange = function () {
callback(xmlhttp)
};
}

第二步,封装成 Promise

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Ajax(obj) {
return new Promise(function(resolve, reject) {
ajax(obj, function(xmlhttp) {
// 成功
if (xmlhttp.readyState === 4 && (Math.floor(xmlhttp.status / 200) === 1 || Math.floor(xmlhttp.status / 300) === 1)) {
resolve(xmlhttp.response)

// 失败
} else if (xmlhttp.readyState === 4 && (Math.floor(xmlhttp.status / 400) === 1 || Math.floor(xmlhttp.status / 500) === 1)) {
reject(xmlhttp.response)
}
})
})
}

将之前的 $.Ajax 替换掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Ajax({
method: "POST",
url: "/ajax/get",
async: true,
contentType: "application/json",
data: JSON.stringify({
name: "星际老男孩",
age: 25,
songs: [{name: "祝大家新年万事大吉", singer: "黄旭东"},
{name: "以爱之名再见宋哈娜", singer: "孙一峰"}]
})
})
.then(function (resp) {
console.log(resp)
})
.catch(function (err) {
console.error(err)
})

效果相同