1 JSON
JSON(JavaScript Object Notation,JS对象表示法),一种轻量级的数据交换格式。2004年诞生,2006年加入的ajax技术体系,用来取代xml封装批量的数据,本质上就是一个特殊格式的字符串,可以直接打印。被称之为Java的第十种数据类型。
1.1 两种传输格式
- {key1:value1,key2:value2,keyN:valueN},其中,key和value分别可以的取值是:
key: 只能是字符串
value: 八种基本数据类型、String、null、自定义数据类型、数组、JSON - [value1,value2,value3,valueN],其中,key和value分别可以的取值是:
value: 八种基本数据类型、String、null、自定义数据类型、数组、JSON
1.2 三种创建(封装)方法
JSON存在三种封装方式,可以封装成以上两种格式的JSON数据。
package com.test.test;
import com.test.po.Student;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import java.util.*;
public class Test {
public static void main(String[] args) {
//1)可以封装任意格式的数据,封装之后呈现格式1的JSON
//但这样的格式在存入JSON时存放了一些key值,这些值很多情况下都是垃圾数据
int i = 3;
String str = "测试JSON方法1";
boolean flag = true;
String[] strArray = {"Java", "C++", "Python"};
JSONObject jo = new JSONObject();
jo.put("key1", i);
jo.put("key2", str);
jo.put("key3", flag);
jo.put("key4", strArray);
jo.put("key5", new Student(1, "张三", "1@t.tt", "111222"));
System.out.println(jo);
//输出{"key1":3,"key2":"测试JSON方法1","key5":{"phone":"111222","name":"张三","id":1,"isdeleted":0,"email":"1@t.tt"},
//"key3":true,"key4":["Java","C++","Python"]}
//2)可以封装自定义数据类型和Map,封装之后呈现格式1的JSON
Map<Integer, String> map = new HashMap<>();
map.put(1, "VUE");
map.put(2, "React");
map.put(3, "Angular");
map.put(4, "jQuery");
//存Map
JSONObject js1 = JSONObject.fromObject(map);
System.out.println(js1);
//输出{"1":"VUE","2":"React","3":"Angular","4":"jQuery"}
//存自定义数据类型
JSONObject js2 = JSONObject.fromObject(
new Student(2, "李四", "2@t.tt", "111223"));
System.out.println(js2);
//输出{"phone":"111223","name":"李四","id":2,"isdeleted":0,"email":"2@t.tt"}
//有选择地对自定义数据类型中的属性封装
JsonConfig jc = new JsonConfig();
//将不需要封装的属性列出
jc.setExcludes(new String[]{"id", "name", "phone"});
JSONObject js3 = JSONObject.fromObject(
new Student(3, "王五", "3@t.tt", "111224"), jc);
System.out.println(js3);
//输出{"isdeleted":0,"email":"3@t.tt"}
//3)专门用来封装List、数组和Set,封装之后呈现格式2的JSON
//String[] strArray = {"Java", "C++", "Python"};
JSONArray ja1 = JSONArray.fromObject(strArray);
System.out.println(ja1);
//输出["Java","C++","Python"]
List<String> list = new ArrayList<>();
list.add("HTML5");
list.add("CSS3");
list.add("JS6");
JSONArray ja2 = JSONArray.fromObject(list);
System.out.println(ja2);
//输出["HTML5","CSS3","JS6"]
Set<String> set = new HashSet<>();
set.add("山东鲁能");
set.add("广州恒大");
set.add("上海申花");
set.add("大连一方");
JSONArray ja3 = JSONArray.fromObject(set);
System.out.println(ja3);
//输出["广州恒大","上海申花","山东鲁能","大连一方"]
}
}
2 AJAX和原生JS通过JSON传输实现级联两个组件
使用AJAX和原生的JS实现下拉列表选中省份(直辖市)时,市(区)自动出现在右边的下拉列表中。
- 编写dao层实现类
package com.test.dao;
import com.test.factory.Factory;
import com.test.po.City;
import com.test.po.Province;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import java.sql.Connection;
import java.util.List;
public class ProvinceCityDaoImpl implements ProvinceCityDaoIf{
Connection conn;
QueryRunner qr = new QueryRunner();
/**
* 拿取全部省份 省份字段:id name
*/
@Override
public List<Province> queryProvince() {
try {
String sql = "select * from province";
conn = Factory.getCon();
return qr.query(conn, sql, new BeanListHandler<Province>(Province.class));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据pid拿取城市 城市字段:id name pid(省份表的id)
*
* @param pid
*/
@Override
public List<City> queryCityByPid(Integer pid) {
try {
String sql = "select * from city where pid = ?";
conn = Factory.getCon();
return qr.query(conn, sql, new BeanListHandler<City>(City.class), pid);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
- 先将省份在下拉列表中显示
cascade.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>级联</title>
</head>
<body onload="showProvince()">
<label for="province">请选择省份:</label>
<select name="province" id="province">
<option value="0">===选择省份===</option>
</select>
<label for="city">请选择城市:</label>
<select name="city" id="city">
<option value="0">===选择城市===</option>
</select>
<script>
let request;
function create(){
request = new XMLHttpRequest();
}
function showProvince(){
create();
request.open("post", "showProvince", true);
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
request.onreadystatechange = function(){
if(request.readyState == 4){
if(request.status == 200){
let text = request.responseText;
//{"province":[{"name":"山东","id":1},
//{"name":"上海","id":2},
//{"name":"广东","id":3},
//{"name":"台湾","id":4}]}
/*
* 从服务器返回的数据是一个普通的字符串
* 我们无法方便地拿取内部封装的数据,
* 通过JS内置的转换器可以将一个标准的
* JSON字符串转换成JS对象
*
* 转换规则如下:
* 1)JSON的key值全部转换为JS对象的属性名
* 2)JSON的value值全部转换为JS对象的属性值
*
* JSON ---> Object
* 若使用第三种封装方式,可以直接parse为数组
* */
let obj = JSON.parse(text);
//Object
// province: Array(4)
// 0: {name: "山东", id: 1}
// 1: {name: "上海", id: 2}
// 2: {name: "广东", id: 3}
// 3: {name: "台湾", id: 4}
let array = obj.province;
//Array(4)
// 0: {name: "山东", id: 1}
// 1: {name: "上海", id: 2}
// 2: {name: "广东", id: 3}
// 3: {name: "台湾", id: 4}
//拿取省份下拉列表框
let dom_select = document.getElementById("province");
//将数据填入下拉列表中
for(let i = 0; i < array.length; i++){
let province = array[i];
let id = province.id;
let name = province.name;
/*
* 向下拉列表框中动态添加option下拉项
* 等号左边:options 中括号内为[index]
* 等号右边:Option 小括号内(页面显示的值,value值);
*
* */
dom_select.options[i + 1] = new Option(name, id);
}
}
}
};
request.send(null);
}
</script>
</body>
</html>
编写Servlet类,接收请求并返回省份的数据
package com.test.servlet;
import com.test.dao.ProvinceCityDaoIf;
import com.test.dao.ProvinceCityDaoImpl;
import com.test.po.Province;
import net.sf.json.JSONObject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
public class ShowProvince extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/plain;charset=utf-8");
PrintWriter out = response.getWriter();
ProvinceCityDaoIf dao = new ProvinceCityDaoImpl();
//拿取全部省份
List<Province> list = dao.queryProvince();
//第一种封装方法
JSONObject jo = new JSONObject();
jo.put("province", list);
System.out.println(jo);
out.print(jo);
out.close();
}
}
效果图:
- 再实现城市的级联显示
在select标签中添加οnchange=“showCity(this.value)”,this.value指的是当前选择的option标签对应的value。
向cascade.html中追加
function showCity(pid){
create();
//这里选用一次GET请求方式
//使用get时需要后面new一个Date(),
//因为是明文传输,浏览器的地址栏可能会有缓存之前的数据,
//所以要加一个每次都不一样的时间,即new Date(),防止浏览器使用之前的缓存发送请求
//另外,get默认是字符流,不需要定义字符集Content-Type
request.open("get", "showCity?pid=" + pid + "&time=" + new Date(), true);
request.onreadystatechange = function(){
if(request.readyState==4){
if(request.status == 200){
//当选中的为山东省
let text = request.responseText;
//[{"name":"济南","pid":1,"id":1},
// {"name":"青岛","pid":1,"id":2},
// {"name":"淄博","pid":1,"id":3},
// {"name":"枣庄","pid":1,"id":4},
// {"name":"烟台","pid":1,"id":5},
// {"name":"潍坊","pid":1,"id":6},
// {"name":"济宁","pid":1,"id":7},
// {"name":"泰安","pid":1,"id":8}]
//使用第三种封装方式,可以省一步,数组不需要再转类型
let array = JSON.parse(text);
//(8) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
//0: {name: "济南", pid: 1, id: 1}
//1: {name: "青岛", pid: 1, id: 2}
//2: {name: "淄博", pid: 1, id: 3}
//3: {name: "枣庄", pid: 1, id: 4}
//4: {name: "烟台", pid: 1, id: 5}
//5: {name: "潍坊", pid: 1, id: 6}
//6: {name: "济宁", pid: 1, id: 7}
//7: {name: "泰安", pid: 1, id: 8}
//拿取城市下拉列表框
let dom_select = document.getElementById("city");
//以防城市的列表框切换后还留存上一次的数据,
//向其中加入数据,若原来的省份对应的城市数量多于这次的数量,
//会出现两个省份的城市混排的现象
while(dom_select.length > 1){
dom_select.removeChild(dom_select.item(1));
}
for(let i = 0; i < array.length; i++){
let city = array[i];
let id = city.id;
let name = city.name;
dom_select.options[i + 1] = new Option(name, id);
}
}
}
};
request.send(null);
}
编写Servlet类,按接收GET请求的参数返回城市的数据
package com.test.servlet;
import com.test.dao.ProvinceCityDaoIf;
import com.test.dao.ProvinceCityDaoImpl;
import net.sf.json.JSONArray;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class ShowCity extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/plain;charset=utf-8");
ProvinceCityDaoIf dao = new ProvinceCityDaoImpl();
//使用第三种封装方式
JSONArray ja = JSONArray.fromObject(
dao.queryCityByPid(
Integer.parseInt(
request.getParameter("pid"))));
PrintWriter out = response.getWriter();
out.print(ja);
System.out.println(ja);
out.close();
}
}
效果图: