SpringMVC和JSON的交互(@RequestBody注解使用及前端contentType设置)

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 student

type:"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 student

type:"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 student

type:"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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值