SpringMVC controller层 @RequestParam与@RequestBody的用法

目录

​编辑

前言

get请求与post请求

ApiPost的用法

get请求

get+application/json

1.无注解情况

2.有注解情况

总结:


结论:@RequestParam---url后面的参数    @RequestBody post 是body参数

先看User类:

前言

get请求与post请求接收参数的形式是不一样的,要想搞清楚 @RequestParam与@RequestBody的用法,就必须知道get请求和post请求的差异。

get请求与post请求

共同点:本质上都是TCP连接

区别:  

 1、参数位置

由于GET请求是直接把请求参数拼接到url上,浏览器往往会对url长度进行限制,所以会对请求参数的大小有所限制,而POST请求是把请求参数放到body中,因此大小没有限制。

表单的 method 和 enctype属性

具体来说, 表单提交其实有两种方式, get 和 post, 可以通过 method 属性指定. 比如下面是一个 post 方式提交的表单:

<form action="xxx.jsp" method="post">...</form>

而这样则是 get 方式:

<form action="xxx.jsp" method="get">...</form>

你可能注意到前面的表单是没有指定 method 属性, 那么则使用缺省方式, 在 html 规范中, 缺省即为 get 方式.

其实表单中还有另外一个重要属性, 也就是 enctype, 它是 encoding type 的缩写, 意思即为"编码类型"(或"内容类型(content type)")

具体也有两个值:

  • application/x-www-form-urlencoded
  • multipart/form-data

缺省即为 application/x-www-form-urlencoded. 所以, 前面例子中的表单等价为:

<form action="form_get_target_default.jsp" method="get" enctype="application/x-www-form-urlencoded">...</form>

综上, 表单 get 方式的提交就是使用 urlencoded 把表单数据以 url 查询字符串的形式放到 url 末尾发送到服务端。

表单提交时,请求头设置为application/x-www-form-urlencoded,POST和GET的区别

请求方式编码方式参数存放位置相同点
GETapplication/x-www-form-urlencoded

URL中:

form数据转换成一个字串(name1=value1&name2=value2…),然后把这个字串append到url后面,用?分割

get 方式中queryString的值,和post方式中 body data的值都会被Servlet接受到并转化到Request.getParameter()参数集中,所以@RequestParam可以获取的到。
POSTapplication/x-www-form-urlencodedBody中:浏览器把form数据封装到http body中,然后发送到server

2、GET请求

GET 请求不存在请求实体部分,键值对参数放置在 URL 尾部,浏览器把form数据转换成一个字串(name1=value1&name2=value2…),然后把这个字串追加到url后面,用?分割,加载这个新的url。因此请求头不需要设置 Content-Type 字段,设置了也不会去使用。值得一提的是,GET 参数的编码方式是无法人为干涉的,这导致了不同浏览器有不同的编码方式。

3、POST请求

Http Header中有键值对,有一个键值对就是Content-Type,其值一般有这三种:

application/x-www-form-urlencoded数据被编码为名称/值对。这是标准的编码格式。默认行为。会将表单内的数据转换拼接成 key-value 对(非 ASCII 码进行编码)
multipart/form-data() 数据被编码为一条消息,页上的每个控件对应消息中的一个部分,必须让 表单的 enctype 等于 multipart/form-data。
text/plain(接口测试文档里标的是raw)数据以纯文本形式(text/json/xml/html)进行编码,其中不含任何控件或格式字符(中文不进行编码)。主要有application/json、text/xml等

ApiPost的用法

点击查看:参考Postman用法

ApiPost的body的类型主要由三种类型的参数: form-data、x-www-form-urlencoded、raw。

由于post请求的参数才放到请求体(Body)里面,get的请求参数一般都直接跟在url后面,所以这里Body里面参数都是指的post请求参数,那post请求测试时怎么判断选择哪个格式的来发送参数呢?

1、form-data(multipart/form-data),支持上传文件的表单类型:
form-data对应着http请求中的Content-Type=multipart/form-data, 一般在表单中如果需要进行文件上传时,就需要使用该格式。

它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件File。当上传的字段是文件时,会有Content-Type来说明文件类型;content-disposition用来说明一些字段信息;
由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对,它采用了键值对的方式,所以可以上传多个文件

2、 x-www-form-urlencoded,表单类型的接口请求:

对应着http请求中的Content-Type为application/x-www-from-urlencoded,会将表单内的数据转换为键值对,比如,name=python&age = 22,这种方式只能以键值对形式发送参数,一般如果不指定content-type,默认便是application/x-www-form-urlencoded,

如b站的注册接口采用的就是这种方式发送消息,如下图,通过抓包获取到Content-Type为application/x-www-from-urlencoded,参数数据就是以键值对的形式发送的。

3、raw(支持各种原生的类型,JSON类型的接口请求),如:Content-Type=application/json时,则可以使用这种方式,这个是实际接口测试中,使用到最多的方式了。越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串
他是可以上传任意格式的参数,可以上传text、json、xml、html、js

get请求

get+application/json

1.无注解情况

接口如下:

各种请求状况如下:

  1. application/json

①不传参

结果:      

ApiPost:提示服务器错误,也就是后端代码出了错误  

IntelliJ IDEA:出现错误

报错:Optional int parameter 'a' is present but cannot be translated into a null value due to being declared as a primitive type. Consider declaring it as object wrapper for the corresponding primitive type.

翻译:

分析:后端设置的参数的类型如果是基本数据类型 如 int, long,char 等8中基本类型,并且前端没有传这个参数,那么就会报这一个错误。这个意思是说,参数xxx是可选的,但是它本身是个基本类型数据,没有办法被转换成null值,让你考虑它把变为当前基本类型的包装类如Long,Integer等,那么你把它转换成对应的包装类就可以了。

java基本数据类型:

  1. 整数类型:byte,1字节,8位,最大存储数据量是255,存放的数据范围是-128~127之间。
  2. 整数类型:short,2字节,16位,最大数据存储量是65536,数据范围是-32768~32767之间。
  3. 整数类型:int,4字节,32位,最大数据存储容量是2的32次方减1,数据范围是负的2的31次方到正的2的31次方减1。
  4. 整数类型:long,8字节,64位,最大数据存储容量是2的64次方减1,数据范围为负的2的63次方到正的2的63次方减1。
  5. 浮点类型:float,4字节,32位,数据范围在3.4e-45~1.4e38,直接赋值时必须在数字后加上f或F。
  6. 浮点类型:double,8字节,64位,数据范围在4.9e-324~1.8e308,赋值时可以加d或D也可以不加。
  7. 字符型:char,2字节,16位,存储Unicode码,用单引号赋值。
  8. 布尔型:boolean,只有true和false两个取值
     

②传参

考虑到上面的的情况是无参数的情况,因此,加上参数是不是就可以使用了呢?下面测试一下。

结果:

apiPost:

Intellig IDEA :

同样的错误。

③传参,但接口是Integer,接口不再是基本数据类型int

结果:

IntelliJ IDEA:

ApiPost:

总结:

测试时,无论请求中加不加参数,后端的接口都看不到a变量,也就是前端的键a。说明不加注解的get方法不接收application/json形式的请求。

接口参数为基本数据类型时,由于看不到json中的参数,则报错。接口封装类型时,接收不到就默认为null。

④传参,接口为自定义类型User

接口如下:

测试如下:

结果:

ApiPost:

IntelliJ IDEA:

总结:说明了不接@RequestParam或者@RequestBody注解,接口看不到前端的json数据(body->application/json)。

那么问题来了,get请求+application/json的请求方式时不推荐的,很少有人这样用,如果非要用,那怎么样才能实现呢?其实就是加注解,加什么注解呢?

接下来我们用测试以下加注解的情况。

2.有注解情况

我们以后写接口,尽量避免用基本数据类型做形参。所以我们只测试封装数据类型和自定义数据类型。

①get+@RequestParam注解+Integer形参

接口如下:

结果:

ApiPost:

现在提示的意思是,错误的请求,也就是我们的请求方式是有问题的,也就是说get请求中标注为@RequestParam的参数,不能application/json的方式进行请求。

IntelliJ IDEA

报错:Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required Integer parameter 'a' is not present]。

翻译:必需的整型参数a没有被提供。

①get+@RuquestBody注解+Integer形参

结果:

ApiPost:错误的请求

IntrlliJ IDEA:

报错:

2023-12-15 11:42:50.796  WARN 132248 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.lang.Integer` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.Integer` out of START_OBJECT token  at [Source: (PushbackInputStream); line: 1, column: 1]]

意思是:无法反序列化“java.lang.Integer”实例。这里大家可能不是很明白为什么用@RequestParam和@RequestBody提示的错误信息是不一样的。其实从服务端提供的错误信息我们也可以看出为什么。

使用@RequestParam时,提示信息为参数a没有被提供,也就是尽管我们前面传递了参数a,但是后端时看不到的。使用@RequestBody显然是看到了a,所以才会说无法反序列化Intger类型的实例。反序列化就是将json字符串反序列化为Integer实例。

总结:

经过上面的测试,我们发现,对于get+application/json这种形式的请求,后端不加@RequestParam和@RequestBody注解是接收不到参数的,认为没有传参。

于是int等基本类型的形参就会报错,Integer封装类型的参数以及自定义Use类型自动转换为null。

加@RequestParam同样看不见参数,认为没传参。加@RequestBody看得到参数,能顺利接收自定义类型User,因为它可以将User的json字符串的反序列化为User对象(测试如下)。

结果:

ApiPost:

IntelliJ IDEA:

成功!!!

所以说,@RequestBody的作用就是,将application/json字符串反序列化为自定义类型。@RequestParam没有这个作用,所以他不能接受application/json类型的请求。

get+

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值