JavaWeb 数据交换与异步请求:JSON 与 Ajax 技术详解
Web 开发中的数据交换格式 JSON 及异步请求技术 Ajax。内容涵盖 JSON 的定义、语法、对象与字符串转换,以及在 Java 中使用 Gson 库进行序列化与反序列化的实践。同时详细讲解了原生 JavaScript 与 jQuery 实现 Ajax 请求的方法,以及利用 ThreadLocal 解决多线程数据共享与安全问题的原理与源码分析。旨在帮助开发者掌握前后端数据交互的核心机制。

Web 开发中的数据交换格式 JSON 及异步请求技术 Ajax。内容涵盖 JSON 的定义、语法、对象与字符串转换,以及在 Java 中使用 Gson 库进行序列化与反序列化的实践。同时详细讲解了原生 JavaScript 与 jQuery 实现 Ajax 请求的方法,以及利用 ThreadLocal 解决多线程数据共享与安全问题的原理与源码分析。旨在帮助开发者掌握前后端数据交互的核心机制。

var 变量名 = {
"k1": value, // Number 类型
"k2": "value", // 字符串类型
"k3": [], // 数组类型
"k4": {}, // json 对象类型
"k5": [{}, {}] // json 数组
};
: 表示,'名称':值,注意名称是字符串,因此要用双引号引起来。, 分隔。'名称 1':值,'名称 2':值。{} 表示。{"名称 1":值,"名称 2":值}。[] 表示。[{"名称 1":值,"名称 2":值}, {"名称 1":"名称 2":值}]。string, number, object, array, true, false, null。<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>json 快速入门案例</title>
<script type="text/javascript">
var myJson = {
"key1": "教育",
"key2": 123,
"key3": [1, "hello", 2.3],
"key4": {"age": 12, "name": "jack"},
"key5": [
{"k1": 10, "k2": "milan"},
{"k3": 30, "k4": "smith"}
]
};
console.log("key1= " + myJson.key1);
console.log("key3[1]= " + myJson.key3[1]);
console.log("name= " + myJson.key4.name);
console.log("myJson.key5[0]= " + myJson.key5[0]);
console.log("myJson.key5[0].k2= " + myJson.key5[0].k2);
</script>
</head>
<body>
<h1>json 快速入门案例</h1>
</body>
</html>
JSON.stringify(json) 功能:将一个 json 对象转换成为 json 字符串。JSON.parse(jsonString) 功能:将一个 json 字符串转换成为 json 对象。代码演示:
// 一个 json 对象
var jsonObj = {
"name": "韩顺平教育",
age: 10
};
// JSON 是一个 build-in 对象,内建对象,有方法可以使用
console.log(JSON);
// 把 json 对象转换成为字符串对象
var jsonStr = JSON.stringify(jsonObj);
console.log(jsonStr);
// 把 json 对象的字符串,转换成为 json 对象
var jsonObj2 = JSON.parse(jsonStr);
console.log(jsonObj2);
JSON.stringify(jsonObject) 会返回对应 string,并不会影响原来 json 对象。JSON.parse(string) 函数会返回对应的 json 对象,并不会影响原来 string。' ' 表示字符串。例如 var json_person = {'name': 'jack', 'age': 100};。"",否则会报错。例如:var str_dog = "{'name':'小黄狗', 'age': 4}"; 转 json 就会报错。JSON.stringify(jsonObject) 返回的字符串,都是 "" 表示的字符串,所以在语法格式正确的情况下,是可以重新转成 json 对象的。gson.jar。// 创建一个 gson 对象,作为一个工具对象使用
Gson gson = new Gson();
// 演示 javaBean -> json 字符串
Book book = new Book(100, "零基础学 Java");
String strBook = gson.toJson(book);
System.out.println("strBook=" + strBook);
// json 字符串 -> javaBean
Book book2 = gson.fromJson(strBook, Book.class);
System.out.println("book2=" + book2);
解读
strBook就是 json 字符串。Book.class指定将 json 字符串转成 Book 对象。- 底层是反射机制。
// 演示把 list 对象 -> json 字符串
List<Book> bookList = new ArrayList<>();
bookList.add(new Book(200, "天龙八部"));
bookList.add(new Book(300, "三国演义"));
// 因为把对象、集合转成字符串,相对比较简单
// 底层只需要遍历,按照 json 格式拼接返回即可
String strBookList = gson.toJson(bookList);
System.out.println("strBookList= " + strBookList);
TypeToken 是一个自定义泛型类,然后通过 TypeToken 来指定我们需要转换成的类型。Type type = new TypeToken<List<Book>>(){}.getType();
List<Book> bookList2 = gson.fromJson(strBookList, type);
System.out.println("bookList2= " + bookList2);
解读
- 返回类型的完整路径
java.util.List<com.hspedu.json.Book>。- Gson 的设计者,需要得到类型的完整路径,然后进行底层反射。
- 所以 Gson 设计者就提供
TypeToken,来搞定。
== 使用 TypeToken,为什么要加 {} ==
首先我们看一下 TypeToken 的源码。
com.google.gson.reflect public class TypeToken<T> {
final Class<? super T> rawType;
final Type type;
final int hashCode;
protected TypeToken() {
this.type = getSuperclassTypeParameter(this.getClass());
this.rawType = Types.getRawType(this.type);
this.hashCode = this.type.hashCode();
}
}
说明
- 如果我们
new TypeToken<List<Book>>(),错误提示'TypeToken()' has protected access in 'com.google.gson.reflect.TypeToken'。- 因为
TypeToken的无参构造器是 protected,而new TypeToken<List<Book>>()就是调用其无参构造器。- 根据 Java 基础,如果一个方法是
protected,而且不在同一个包,是不能直接访问的,因此报错。- 为什么
new TypeToken<List<Book>>(){}使用就可以?这里就涉及到匿名内部类的知识。- 当
new TypeToken<List<Book>>(){}其实这个类型就不是TypeToken而是一个匿名内部类 (子类),继承。- 而且这个匿名内部类是有自己的无参构造器 (隐式),根据 Java 基础规则,当执行子类的无参构造器时,默认
super()。
// 把 map 对象->json 字符串
Map<String, Book> bookMap = new HashMap<>();
bookMap.put("k1", new Book(400, "射雕英雄传"));
bookMap.put("k2", new Book(500, "西游记"));
String strBookMap = gson.toJson(bookMap);
System.out.println("strBookMap=" + strBookMap);
// 把 json 字符串 -> map 对象
// new TypeToken<Map<String, Book>>() {}.getType()=> java.util.Map<java....String,com.hspedu.json.Book>
Map<String, Book> bookMap2 = gson.fromJson(strBookMap, new TypeToken<Map<String, Book>>(){}.getType());
Ajax 经典应用场景
首先给大家推荐一下 Ajax 的在线文档:https://www.w3school.com.cn/js/js_ajax_intro.asp
点击验证用户名,使用 ajax 方式,服务端验证该用户名是否已经占用了,如果该用户已经占用,以 json 格式返回该用户信息。
<script type="text/javascript">
window.onload = function(){
var checkButton = document.getElementById("checkButton");
checkButton.onclick = function(){
// 1. 创建 XMLHttpRequest 对象 (!!!) [ajax 引擎对象]
var xhr = new XMLHttpRequest();
// 获取用户填写的用户名
var uname = document.getElementById("uname").value;
// 2. 准备发送指定数据 open, send
// (1) "GET" 请求方式可以 GET/POST
// (2) "/ajax/checkUserServlet?username=" + uname 就是 url
// (3) true , 表示异步发送
xhr.open("GET","/ajax/checkUserServlet?uname=" + uname,true);
// 在 send 函数调用前,给 XMLHttpRequest 绑定一个事件 onreadystatechange
// 该事件表示,可以去指定一个函数,当数据变化,会触发 onreadystatechange
// 每当 xhr 对象 readyState 改变时,就会触发 onreadystatechange 事件
xhr.onreadystatechange = function(){
// 如果请求已完成,且响应已就绪,并且状态码是 200
if(xhr.readyState == 4 && xhr.status == 200){
// 把返回的 jon 数据,显示在 div
document.getElementById("div1"). = xhr.;
responseText = xhr.;
xhr.();
}
}
}
}
</script>
$.ajax 常用参数
url: 请求的地址type: 请求的方式 get 或 postdata: 发送到服务器的数据。将自动转换为请求字符串格式success: 成功的回调函数error: 失败后的回调函数dataType: 返回的数据类型 常用 json 或 text$.get 和 $.post 常用参数
url: 请求的 URL 地址data: 请求发送到服务器的数据success: 成功时回调函数type: 返回内容格式,xml, html, script, json, text$.get 和 $.post 底层还是使用 $.ajax() 方法来实现异步请求。$.getJSON 常用参数
url: 请求发送的哪个 URLdata: 请求发送到服务器的数据success: 请求成功时运行的函数$.getJSON 底层使用 $.ajax() 方法来实现异步请求。类图

ThreadLocal<Object> threadLocal = new ThreadLocal<>();
threadLocal.set(dog);
如果希望在同一个线程共享多个对象/数据,就在创建一个 ThreadLocal 对象。 //threadLocal2.set(pig);
只要明白这个机制,后面的 set get 全部通透。
public void set(T value) {
// 获取当前线程
Thread t = Thread.currentThread();
// 获取当前线程的 ThreadLocal.ThreadLocalMap 属性 threadLocals , 类型是 ThreadLocal 的静态内部类
// threadLocals 有一个属性 Entry[], 类型 ThreadLocal.ThreadLocalMap.Entry
// k-> ThreadLocal 对象 v-> 值
ThreadLocalMap map = getMap(t);
if(map != null) map.set(this, value); // 存放这里的 this 就是 ThreadLocal, 可以 debug 源码,一目了然
else createMap(t, value); // 创建
}
说明:
- ThreadLocalMap 对象是和当前 Thread 对象的绑定的属性。
- ThreadLocalMap 对象含有 Entry[] table; 这个 Entry(K,V)。
- 这个 key 就是 ThreadLocal 对象,V 就是你要在放入的对象,比如 dog。
- 当执行了 threadLocal.set(dog) 后,内存布局图为 [看图]。


这里涉及到的弱引用,涉及到知识点很多,暂不深入。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online