1. 后端Springboot

通过 https://start.spring.io/ 获得项目框架。在eclipse中导入下载的Maven项目。

  • Maven添加fastjson依赖包
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
  • 定义Controller
@RestController
public class GetJsonReq {

@CrossOrigin
@RequestMapping(value = "/simple")
// json的结构和内部字段名称可以与POJO/DTO/javabean完全对应
public Map<String, String> getJsonBean(@RequestBody Beauty beauty) {
Map<String, String> result = null;

if (beauty != null) {
System.out.println("美女的名字:" + beauty.getName());
System.out.println("美女的年龄:" + beauty.getAge());

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("美女出道日期:" + sdf.format(beauty.getDate()));

System.out.println("美女的收入:" + beauty.getSalary());

result = new HashMap<>();
result.put("code", "1");
result.put("msg", "ok");
}

return result;
}

@CrossOrigin
@RequestMapping(value = "/complex")
//json的结构较为复杂,不直接与POJO/DTO/javabean对应。
public Map<String, String> getJsonComplex(@RequestBody JSONObject param) {
Map<String, String> result = null;

if (param != null) {
JSONObject master = param.getJSONObject("master");
Beauty beauty = (Beauty) JSONObject.toJavaObject(master, Beauty.class);
System.out.println(beauty);

JSONArray mm = param.getJSONArray("MM");
for (int i = 0; i < mm.size(); i++) {
// 这里不能使用get(i),因为get(i)只会得到键值对。
JSONObject json = mm.getJSONObject(i);
Beauty bt = (Beauty) JSONObject.toJavaObject(json, Beauty.class);
System.out.println(bt);
}

result = new HashMap<>();
result.put("code", "1");
result.put("msg", "ok");
}

return result;
}
}
  • POJO/DTO/JavaBean
    注意Date字段要如何处理。
public class Beauty {
private String name;
private int age;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date date;
private double salary;

public Beauty() {

}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public Date getDate() {
return date;
}

public void setDate(Date date) {
this.date = date;
}

public double getSalary() {
return salary;
}

public void setSalary(double salary) {
this.salary = salary;
}

@Override
public String toString() {
return "Beauty [name=" + name + ", age=" + age + ", date=" + date + ", salary=" + salary + "]";
}

}
  • 将JSON转为Java对象使用@RequestBody 注解;将Java对象转换为JSON使用@ResponseBody注解。

一旦使用@ResponseBody注解返回流程将不在经过视图解析器,而是直接将数据写入到输出流中,通过response的body返回数据。如果处理请求方法返回的是 String 时@ResponseBody 注解不会进行 JSON 转换。响应的 Content-Type 为 text/plain;charset=ISO-8859-1。如果处理请求方法返回的是除了 String 类型以外的其他Object 类型时,@ResponseBody注解会进行 JSON 转换。响应的 Content-Type 为 application/json。

响应体的字符编码需要在@RequestBody 注解中设定:

//@RequestMapping(value = "/addUsers",produces = "text/plain;charset=utf-8") 返回String
//@RequestMapping(value = "/addUsers",produces = "application/json;charset=utf-8") 返回json对象
@RequestMapping(value = "/addUsers",produces = MediaType.APPLICATION_JSON_VALUE+";charset=utf-8")
@ResponseBody
@CrossOrigin(origins ="http://localhost:8888")
public Object addUsers(@RequestBody Users users)throws Exception{
System.out.println(users);
return users;
}

2. 前端通过Ajax发送json

  • 借助jQuery来发送Ajax请求。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>发送json</title>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<script type="text/javascript">function send1() {
var beauty = JSON.stringify({ //将JSON对象转换为字符串
"name": "小甜甜",
"age": 26,
"salary": 200000,
"date": "2019-08-05 08:04:13"
});

$.ajax({
type: 'POST',
url: "http://localhost:8080/simple",
data: beauty, //beauty是字符串
contentType: "application/json",
dataType: "json",
success: function(message) {
alert(JSON.stringify(message)) //将JSON对象转换为字符串
}
});
};

function send2() {
var beauty = JSON.stringify({
"MM": [{
"name": "春花",
"age": 27,
"salary": 20000,
"date": "2017-05-19 09:33:14"
}, {
"name": "秋香",
"age": 30,
"salary": 30000,
"date": "2019-10-21 17:04:33"
}],
"master": {
"name": "小甜甜",
"age": 26,
"salary": 200000,
"date": "2019-08-05 08:04:13"
}
});

$.ajax({
type: "POST",
url: "http://localhost:8080/complex",
contentType: "application/json; charset=utf-8",
data: beauty,
dataType: "json",
success: function(message) {
alert("提交成功" + JSON.stringify(message));
},
error: function(message) {
alert("提交失败" + JSON.stringify(message));
}
});
}</script>

<input type="button" name="btn1" id="s1" onclick="send1()" value="发送简单json" />
<br />
<hr />
<input type="button" name="btn2" id="s2" onclick="send2()" value="发送复杂json" />
</body>
</html>

这里要注意:

  1. script标签引入js的形式必须是双标签,形如:
    <script src="…js" …></script>
    如果是形如<script src="…js" … />的单标签,将无法引入js。
  2. 页面提交的数据默认content-type是application/x-www-form-urlcoded的编码(键值对)。而@RequestBody注解只有在编码为application/json时才能将JSON 格式的数据转为 Java 对象。
  3. 对于jQuery一般是使用$.ajax来发送json请求,因为只有它可以设置编码格式(application/json)。
  • HTML5中如何实现JSON对象与字符串之间的相互转换?
//string -> json
JSON.parse("...")

//json -> string
JSON.stringify(obj)

3. 跨域访问

  • 同源策略
    ajax请求须受到同源策略的影响。
  • 跨域请求
    在 JavaScript 的请求中当一个请求 URL 的协议、域名、端口三者之间任意一个与当前页面 URL 不同时即为跨域。
  • ajax请求如何受同源策略限制
    一个页面的URL(origin)与同一页面中ajax访问的URL出现跨域时,ajax请求被服务器端block。
  • 处理方式

前端:jsonp(json with padding)
jsonp的原理就是script标签不受同源策略的影响,所以通过script的src属性来实现跨域。

//原生js
var script = document.createElement("script");
script.src = "https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);

//在页面中,返回的JSON作为参数传入回调函数中
functionhandleResponse(response){
// 对response数据进行操作代码
}

//jQuery GET
$.ajax({
async : true,
url : "https://api.douban.com/v2/book/search",
type : "GET",
dataType : "jsonp", // 返回的数据类型,设置为JSONP方式
jsonp : 'callback', //指定一个查询参数名称来覆盖默认的 jsonp 回调参数名 callback
jsonpCallback: 'handleResponse', //设置回调函数名
data : {
q : "javascript",
count : 1
},
success: function(response, status, xhr){
console.log('状态为:' + status + ',状态是:' + xhr.statusText);
console.log(response);
}
});

//jQuery POST
$.ajax({
url:'http://localhost:8888/other/other.jsp',
type:'post',
data:{'params':'fromjsonp'},
dataType: "jsonp",
jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
success: function(data){
alert("through jsonp,receive data from other domain : "+data.result);
},
error: function(){
alert('fail');
}
});

后端:@CrossOrigin

@Controller
@RequestMapping("/user")
public class UsersController {

@RequestMapping(value = "/addUsers",produces = MediaType.APPLICATION_JSON_VALUE+";charset=utf-8")
@ResponseBody
//限定发送 ajax的页面的初始url,即origins(可多个origin url)。其他的不受理。
//不给出origins则处理所有origin url的跨域 ajax请求。
@CrossOrigin(origins ="http://localhost:8888")
public Object addUsers(@RequestBody Users users)throws Exception{
System.out.println(users);
return users;
}
}

4. 使用Java如何模拟客户端发送json的http请求?

  • 看这里