五、JSON数据交互
1. JSON简介
- JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式
- 基于ECMAScript的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据
- 简洁和清晰的层次结构使得JSON成为理想的数据交换语言
- 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center">
<h1>首页</h1>
<a href="views/json.jsp">JSON</a><br>
<a href="views/request.jsp">请求</a><br>
<a href="views/response.jsp">响应</a><br>
</div>
</body>
</html>
json.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
<script type="text/javascript">
//JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
//这是一个对象,注意键名也是可以使用引号包裹的
var obj = {
name: 'tom',
age: 20
};
//这是一个 JSON 字符串,本质是一个字符串
var json = '{"name": "jerry", "age": 19}';
//JSON字符串转换为JS对象,使用JSON.parse()方法:
var obj2 = JSON.parse(json);
//JS对象转换为JSON字符串,使用JSON.stringify()方法:
var json2 = JSON.stringify(obj);
</script>
</head>
<body>
</body>
</html>
2. SpringMVC处理异步请求
2.1 请求
- 客户端请求的是key/value值,contentType为application/x-www-form-urlencoded默认值,服务器端不需要处理,即可获取数据
- 客户端请求的是json字符串,需要指定contentType为application/json,并且在服务器端需要使用@RequestBody注解将json串转成java对象
2.2 响应
需要使用@ResponseBody注解将java对象转成json串输出
3. 实现过程
3.1 导入jackson包
maven依赖配置
<dependencies>
<!-- spring核心包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springbean包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springcontext包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- spring表达式包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springAOP包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springAspects包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- spring对web的支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- springwebMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<!-- 配置javaweb环境 -->
<!-- servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<!-- jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.5</version>
</dependency>
</dependencies>
注意:spring4.x须使用jackson2.x版本,而spring3.x版本使用jackson1.x版本
3.2 配置
在处理器适配器中配置json转换器
注意:如果使用<mvc:annotation-driven/>
则不用定义上边的内容
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- springmvc的注解式开发 -->
<!-- 开启组件扫描 -->
<context:component-scan base-package="com.newcapec.controller"/>
<!-- MVC注解驱动 -->
<mvc:annotation-driven/>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 配置视图地址的前缀和后缀:简化视图地址 -->
<property name="prefix" value="/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
3.3 POJO
Dept.java
public class Dept {
private Integer deptno;
private String dname;
public Integer getDeptno() {
return deptno;
}
public void setDeptno(Integer deptno) {
this.deptno = deptno;
}
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
@Override
public String toString() {
return "Dept{" +
"deptno=" + deptno +
", dname='" + dname + '\'' +
'}';
}
}
Emp.java
public class Emp {
private Integer empno;
private String ename;
private String job;
private Double sal;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date hiredate;
private Dept dept;
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Double getSal() {
return sal;
}
public void setSal(Double sal) {
this.sal = sal;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"empno=" + empno +
", ename='" + ename + '\'' +
", job='" + job + '\'' +
", sal=" + sal +
", hiredate=" + hiredate +
", dept=" + dept +
'}';
}
}
3.4 请求key/value
request.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
//key-value值
function sendKeyValue() {
//js的字面量对象
var emp = {
empno: 101,
ename: 'tom',
job: 'staff',
sal: 4500,
hiredate: '2020-01-09',
'dept.deptno': 10,
'dept.dname': 'hr'
};
//发送异步请求
$.ajax('sendKeyValue.do', {
type: 'post',
data: emp,
//内容类型:将数据转换为keyValue向服务器提交
contentType: 'application/x-www-form-urlencoded',
success: function(resp) {
alert(resp);
}
});
}
</script>
</head>
<body>
<div style="text-align: center">
<p><a href="javascript:sendKeyValue()">向服务器端发送key/value值</a></p>
<p><a href="javascript:sendJson()">向服务器端发送json值</a></p>
</div>
</body>
</html>
Controller:
@Controller
public class JsonController {
@RequestMapping("/sendKeyValue.do")
public void sendKeyValue(Emp emp, HttpServletResponse response) throws IOException {
System.out.println("请求数据:" + emp);
response.getWriter().write("success");
}
}
测试结果:
3.5 请求json字符串
页面js:
//json字符串格式
function sendJson() {
//js的字面量对象
var emp = {
empno: 102,
ename: 'jack',
job: 'manager',
sal: 6800,
hiredate: '2020-01-09',
dept: {
deptno: 20,
dname: 'sale'
}
};
//发送异步请求
$.ajax('sendJson.do', {
type: 'post',
data: JSON.stringify(emp),
//内容类型:告知服务器提交数据为json字符串
contentType: 'application/json',
success: function(resp) {
alert(resp);
}
});
}
Controller:
@Controller
public class JsonController {
/**
* @RequestBody
* 位置:形参
* 作用:将提交的json字符串,转换为Java对象
*/
@RequestMapping("/sendJson.do")
public void sendJson(@RequestBody Emp emp, HttpServletResponse response) throws IOException {
System.out.println("请求数据:" + emp);
response.getWriter().write("success");
}
}
测试结果:
3.6 响应json对象
response.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
function responseObject() {
$.ajax('responseObject.do', {
type: 'get',
success: function(resp) {
//在回调函数的参数中直接获取是js的字面对象
// alert(resp);
var str = '<p>员工编号:' + resp.empno + '</p>';
str += '<p>员工姓名:' + resp.ename + '</p>';
str += '<p>员工岗位:' + resp.job + '</p>';
str += '<p>员工薪资:' + resp.sal + '</p>';
str += '<p>入职日期:' + resp.hiredate + '</p>';
$('#data').html(str);
}
});
}
</script>
</head>
<body>
<div style="text-align: center">
<p><a href="javascript:responseObject()">获取单条数据</a></p>
<p><a href="javascript:responseList()">获取批量数据</a></p>
<div id="data">
</div>
<table border="1" width="500" align="center">
<thead>
<tr>
<th>员工编号</th>
<th>员工姓名</th>
<th>员工岗位</th>
<th>员工薪资</th>
<th>入职日期</th>
</tr>
</thead>
<tbody id="tab"></tbody>
</table>
</div>
</body>
</html>
Controller:
@Controller
public class JsonController {
/**
* 响应json数据
* 1.响应单个数据(一个实体对象)
*
* @ResponseBody
* 位置:方法,返回值
* 作用:将该方法的返回值转换为json字符串向客户端响应
*/
@ResponseBody
@RequestMapping("/responseObject.do")
public Emp responseObject(){
//模拟数据库中的查询
Emp emp = new Emp();
emp.setEmpno(201);
emp.setEname("chris");
emp.setJob("manager");
emp.setHiredate(new Date());
emp.setSal(6300.0);
//在同步请求中,将数据存放在域对象中...
//异步请求:直接返回对象
return emp;
}
}
测试结果:
3.7 响应json数组
页面js:
function responseList() {
$.ajax('responseList.do', {
type: 'get',
success: function(resp) {
//在回调函数的参数中直接获取是js的字面对象数组
var str = '';
for(var i in resp) {
var emp = resp[i];
str += '<tr>';
str += '<td>' + emp.empno + '</td>';
str += '<td>' + emp.ename + '</td>';
str += '<td>' + emp.job + '</td>';
str += '<td>' + emp.sal + '</td>';
str += '<td>' + emp.hiredate + '</td>';
str += '</tr>';
}
$('#tab').html(str);
}
});
}
Controller方法:
@Controller
public class JsonController {
/**
* 响应json数据
* 2.响应批量数据(一个集合,集合中存放的是多个实体对象)
*
* @ResponseBody
* 位置:方法,返回值
* 作用:将该方法的返回值转换为json字符串向客户端响应
*/
@ResponseBody
@RequestMapping("/responseList.do")
public List<Emp> responseList(){
//模拟数据库中的查询
Emp emp1 = new Emp();
emp1.setEmpno(201);
emp1.setEname("chris");
emp1.setJob("manager");
emp1.setHiredate(new Date());
emp1.setSal(6300.0);
Emp emp2 = new Emp();
emp2.setEmpno(202);
emp2.setEname("tom");
emp2.setJob("manager");
emp2.setHiredate(new Date());
emp2.setSal(6300.0);
Emp emp3 = new Emp();
emp3.setEmpno(203);
emp3.setEname("cherry");
emp3.setJob("manager");
emp3.setHiredate(new Date());
emp3.setSal(6300.0);
List<Emp> list = new ArrayList<>();
list.add(emp1);
list.add(emp2);
list.add(emp3);
//在同步请求中,将数据存放在域对象中...
//异步请求:直接返回对象
return list;
}
}
测试结果:
3.8 日期类型处理
POJO类中有日期类型的属性,只需在属性上加上@JsonFormat注解即可
public class Emp {
private Integer empno;
private String ename;
private String job;
private Double sal;
/**
* @DateTimeFormat 将客户端提交的字符串转换为Date类型
* @JsonFormat 将日期类型转换为指定格式字符串
*/
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date hiredate;
private Dept dept;
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Double getSal() {
return sal;
}
public void setSal(Double sal) {
this.sal = sal;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"empno=" + empno +
", ename='" + ename + '\'' +
", job='" + job + '\'' +
", sal=" + sal +
", hiredate=" + hiredate +
", dept=" + dept +
'}';
}
}