SpringMVC和JSON的交互(即后台解析JSON字符串和向前台传递JSON字符串的过程)
一:概述
**springMVC中和json的交互:主要分为两点:**
一是传递过来的是json字符串,springMVC会先进行解析,
二是传递过来的是key:value那么springMVC可以不进行解析,
这里的解析指的是json和java对象之间的转换
二:流程图:
具体分析:
2.1:前端传来JSON对象(即key=value的字符串)
1.第一种方式就是请求的是key=value的字符串,controller对应方法在接收的时候就不需要用到@RequestBody。需要注意:默认提交的 contentType为 application/x-www-form-urlencoded,此时提交的JSON对象数据将会被格式化成:key1=value1&key2=value2。
向前台返回的是Java对象时,就需要在controller层的相应方法上加上 @ResponseBody 注解将我们的Java对象,转成json格式的字符串,这样前端页面才可以解析。
具体实现如下:
前端代码:
//前端代码:点击按钮,通过jQuery发送Ajax请求
$(function(){
$("#login").click(function(){
$.ajax({
url:"/login",
type:"POST",
//data是JSON对象。
//默认的 contentType为 application/x-www-form-urlencoded。会被解析为key1=value1&key2=value2
data:{name:$("#name").val(),id:$("#id").val()},
dataType:"json",
success:function (data){
if(data.code==200){
alert("登录成功")
}
$("#msg").html(data.msg);
}
})
});
});
后端Controller代码:
@ResponseBody
@PostMapping("/login")
public Map<String, Object> login(Student student1, HttpServletRequest request){
System.out.println(student1);
Map<String, Object> map = new HashMap<>();
Student student = studentservice.login(student1);
if(student == null){
map.put("code", 600);
map.put("msg", "登陆失败");
return map;
}
map.put("code", 200);
map.put("msg", "登陆成功");
return map;
}
错误情况1:
1. 前端设置contentType:contentType:“application/json;charset=utf-8”;
2. 后端 Student student(无@RequestBody注解)type:"POST", contentType:"application/json;charset=utf-8",
此时点击按钮出发Ajax,后台无明显异常,但是student对象中无任何属性。前台传入name、id属性,后端无法获取到。
原因: 设置为 contentType:“application/json;charset=utf-8” 时,data只能是json字符串。且后端需@RequestBody解析JSON字符串。此时后端常规解析data内容,解析不到。
错误情况2:
1. 前端不设置contentType;即默认为 application/x-www-form-urlencoded;
2. 后端形参加上@RequestBody Student studenttype:"POST", //不设置 contentType;即默认为 application/x-www-form-urlencoded。 // contentType:"application/json;charset=utf-8",
此时点击按钮出发Ajax,后台警告如下
[QC] WARN [http-nio-8080-exec-4] org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.logException(199) | Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type ‘application/x-www-form-urlencoded;charset=UTF-8’ not supported]
原因: 设置为 contentType:“application/x-www-form-urlencoded” 时,data会被解析为key1=value1&key2=value2。即发向后端的数据不是JSON字符串,不能用@RequestBody解析。当我们使用 application/x-www-form-urlencoded 时,Spring不会将其理解为RequestBody .所以,如果我们要使用这个 我们必须删除 @RequestBody 注解.
错误情况3:
1. 前端设置contentType:contentType:“application/json;charset=utf-8”;
2. 后端形参加上@RequestBody Student studenttype:"POST", contentType:"application/json;charset=utf-8",
此时点击按钮出发Ajax,后台警告如下
[QC] DEBUG [http-nio-8080-exec-4] org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(174) |
Could not resolve parameter [0] in public java.util.Map<java.lang.String, java.lang.Object> cn.cdqf.controller.StudentController.login(cn.cdqf.pojo.Student,javax.servlet.http.HttpServletRequest): JSON parse error: error parse new;
nested exception is com.alibaba.fastjson.JSONException: error parse new
原因: 设置为 contentType:“application/json;charset=utf-8” 时,data只能是json字符串。即此时发向后端的数据不是JSON字符串(是JSON对象),使用@RequestBody解析会错误。
2.2:前端传来JSON字符串
1、从图中我们可以看出来,前台请求的数据如果是json字符串,我们需要在controller层的相应方法里的形参旁添加@RequestBody注解,先将json字符串转成java对象。同时前端页面需指定contentType:“application/json; charset=utf-8”,
具体实现如下:
前端代码:
//前端代码:点击按钮,通过jQuery发送Ajax请求
$(function(){
$("#login").click(function() {
$.ajax({
url:"/login",
type:"POST",
contentType:"application/json; charset=utf-8",
data:JSON.stringify({name:$("#name").val(),id:$("#id").val()}),
dataType:"json",
success:function (data){
if(data.code==200){
alert("登录成功")
}
$("#msg").html(data.msg);
}
})
});
});
后端Controller代码:
@ResponseBody
@PostMapping("/login")
public Map<String, Object> login(@RequestBody Student student1, HttpServletRequest request){
System.out.println(student1);
Map<String, Object> map = new HashMap<>();
Student student = studentservice.login(student1);
if(student == null){
map.put("code", 600);
map.put("msg", "登陆失败");
return map;
}
map.put("code", 200);
map.put("msg", "登陆成功");
return map;
}
错误情况1:
1. 前端设置contentType:contentType:“application/json;charset=utf-8”;
2. 后端 Student student(无@RequestBody注解)type:"POST", contentType:"application/json;charset=utf-8",
此时点击按钮出发Ajax,后台无明显异常,但是student对象中无任何属性。前台传入name、id属性,后端无法获取到。
错误情况2:
1. 前端不设置contentType;即默认为 application/x-www-form-urlencoded;
2. 后端形参加上@RequestBody Student studenttype:"POST", //不设置 contentType;即默认为 application/x-www-form-urlencoded。 // contentType:"application/json;charset=utf-8",
此时点击按钮出发Ajax,后台警告如下
[QC] WARN [http-nio-8080-exec-4] org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.logException(199) | Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type ‘application/x-www-form-urlencoded;charset=UTF-8’ not supported]
错误情况3:
1. 前端不设置contentType;即默认为 application/x-www-form-urlencoded;
2. 后端 Student student(无@RequestBody注解)type:"POST", // contentType:"application/json;charset=utf-8",
此时点击按钮出发Ajax,后台无明显异常,但是student对象中无任何属性。前台传入name、id属性,后端无法获取到。
要分析以上问题,应理解@RequestBody和Content-Type:
后端@RequestBody注解对应的类在将HTTP的输入流(含请求体)装配到目标类(即:@RequestBody后面的类)时,会根据json字符串中的key来匹配对应实体类的属性,如果匹配一致且json中的该key对应的值符合(或可转换为)实体类的对应属性的类型要求时,会调用实体类的setter方法将值赋给该属性。
@RequestBody是通过无参构造器new的对象,然后通过set方法设置,如果在实体类中添加了有参构造器,没加无参构造器,接收参数时异常。
contentType: “application/json” 则data只能是json字符串。关于@RequestBody可详见文章:
https://blog.csdn.net/justry_deng/article/details/80972817/
https://blog.csdn.net/weixin_38004638/article/details/99655322
关于Content-Type的理解可详见文章:
https://www.cnblogs.com/tugenhua0707/p/8975121.html