@RequestBody

news2025/1/24 14:49:40

目录

概述

深入细节

案例

@RequestBody与前端传过来的json数据的匹配规则

指定模型中的属性对应什么key

用@Valid校验@RequestBody的参数

根据RequestBody的内容来区分使用哪个资源


概述

  • @RequestBody主要用来接收前端传递给后端的json字符串中的数据(请求体中的数据)
  • 而最常用的使用请求体传参的无疑是POST请求了,所以使用@RequestBody接收数据时,一般都用POST方式进行提交
  • 用途:用于获取HTTP请求的主体内容,通常用于读取非表单数据,如JSON或XML格式
  • 数据绑定:将HTTP请求体中的数据绑定到一个对象上,通常使用转换器如Jackson或Gson将JSON或XML转换成Java对象
  • 使用场景:适用于POST或PUT请求
  • 举例:

深入细节

  • (细节1) 在后端的同一个接收方法里,@RequestBody与@RequestParam()可以同时使用
  • @RequestBody最多只能有一个,而@RequestParam()可以有多个
  • (1)注意:一个请求,只有一个RequestBody;一个请求,可以有多个RequestParam
  • (2)注意:当同时使用@RequestParam()和@RequestBody时,@RequestParam()指定的参数可以是普通元素、数组、集合、对象等等(即:当,@RequestBody与@RequestParam()可以同时使用时,原SpringMVC接收参数的机制不变,只不过RequestBody接收的是请求体里面的数据;而RequestParam接收的是key-value里面的参数,所以它会被切面进行处理从而可以用普通元素、数组、集合、对象等接收),即:如果参数是放在请求体中,application/json传入后台的话,那么后台要用@RequestBody才能接收到;如果不是放在请求体中的话,那么后台接收前台传过来的参数时,要用@RequestParam来接收,或者形参前什么也不写也能接收
  • (3)注意:如果参数前写了@RequestParam(xxx),那么前端必须有对应的xxx名字才行(不管其是否有值,当然可以通过设置该注解的required属性来调节是否必须传),如果没有xxx名的话,那么请求会出错,报400
  • (4)注意:如果参数前不写@RequestParam(xxx)的话,那么前端如果有xxx名的话,那么就会自动匹配;没有的话,请求也能正确发送
  • 追注1:在Spring MVC中,当HTTP请求到达控制器的处理方法时,Spring会尝试将请求中的参数映射到方法的参数上;这是通过方法参数名称或注解提供的名称来进行的
  • 追注2:如果控制器方法的参数前没有@RequestParam注解,Spring MVC会根据非限定名称来尝试绑定方法参数,这涉及到以下几点行为:
  1. 参数名称匹配:如果HTTP请求中有与方法参数同名的参数,Spring会自动将该值注入到方法参数中
  2. 可选参数:如果HTTP请求中缺少对应同名参数,而方法参数没有使用@RequestParam标记为必需,那么请求仍会被正确映射且方法会被调用;在这种情况下,该参数可能会被赋予一个null值或基本类型的默认值(比如int类型的0);但这种行为可能会让方法中的参数接收到一个不是从请求直接提供的值,这可能会导致潜在的错误,除非有适当的空值处理逻辑
  3. 不明确的行为:如果没有@RequestParam明确指定参数,且请求中也没有同名参数,那么方法参数的值究竟是什么,可能不是那么明确;这可能取决于参数的类型及是否有默认构造方法等因素
  4. 参数类型转换:Spring会尝试将请求参数转换为方法参数的类型(例如,从字符串转换为整数);如果转换失败,可能会导致请求处理失败
  • 下面是一个无@RequestParam注解的例子:
  • 在这个例子中,如果请求中有category这个参数,那么它的值会被传递到category方法参数中
  • 如果没有,该方法参数的值将为null(对于对象)或基本类型的默认值
  • 综上所述,使用@RequestParam让你可以更明确地表达你期待的请求行为,包括参数是否必须、默认值是什么等
  • 而不使用注解,则采取更隐式的绑定方式,参数可有可无,当它们存在时会被匹配和使用;不存在时,请求也能正确发送,但你的方法应当能处理这种情况
  • 追注3:这里与feign消费服务时不同;feign消费服务时,如果参数前什么也不写,那么会被默认是@RequestBody的
  • (细节2) 如果后端参数是一个对象,且该参数前是以@RequestBody修饰的,那么前端传递json参数时,必须满足以下要求:
  1. 后端@RequestBody注解对应的类在将HTTP的输入流(含请求体)装配到目标类(即:@RequestBody后面的类)时,会根据json字符串中的key来匹配对应实体类的属性,如果匹配一致且json中的该key对应的值符合(或可转换为)(这一条会在下面详细分析)实体类的对应属性的类型要求时,会调用实体类的setter方法将值赋给该属性
  2. json字符串中,如果value为""的话,后端对应属性如果是String类型的,那么接受到的就是"",如果后端属性的类型是Integer、Double等类型,那么接收到的就是null
  3. json字符串中,如果value为null的话,后端对应收到的就是null
  4. 如果某个参数没有value的话,在传json字符串给后端时,要么干脆就不把该字段写到json字符串中;要么写value时,必须有值,null或""都行;千万不能有类似"stature":,这样的写法,如:

案例

  • 先给出两个等下要用到的实体类
  • User实体类:
  • Team实体类:
  • @RequestBody直接以String接收前端传过来的json数据:
  • 后端对应的Controller:
  • 使用PostMan测试:
  • @RequestBody以简单对象接收前端传过来的json数据:
  • 后端对应的Controller:
  • 使用PostMan测试:
  • @RequestBody以复杂对象接收前端传过来的json数据:
  • 后端对应的Controller:
  • 使用PostMan测试(传递的json字符串中必须要有key,否则请求会出错):
  • @RequestBody与简单的@RequestParam()同时使用:
  • 后端对应的Controller:
  • 使用PostMan测试:
  • @RequestBody与复杂的@RequestParam()同时使用:
  • 后端对应的Controller:
  • 使用PostMan测试:
  • @RequestBody接收请求体中的json数据;不加注解接收URL中的数据并组装为对象:
  • 后端对应的Controller:
  • 使用PostMan测试:
  • 注意:如果在后端方法参数前,指定了@RequestParam()的话,那么前端必须要有对应字段才行(当然可以通过设置该注解的required属性来调节是否必须传),否则会报错;如果参数前没有任何该注解,那么前端可以传这个参数,也可以不传,如:
  • 上图中,如果我们传参中没有指定token,那么请求能正常进去,但是token为null;如果在String token前指定了@RequestParam(“token”),那么前端必须要有token这个键,请求才能正常进去,否则报400错误

@RequestBody与前端传过来的json数据的匹配规则

  • 声明:根据不同的Content-Type等情况,Spring-MVC会采取不同的HttpMessageConverter实现来进行信息转换解析
  • 说明:request的body部分的数据编码格式由header部分的Content-Type指定
  • 下面介绍的是最常用的:前端以Content-Type为application/json,传递json字符串数据;后端以@RequestBody模型接收数据的情况
  • 解析json数据大体流程概述:Http传递请求体信息,最终会被封装进com.fasterxml.jackson.core.json.UTF8StreamJsonParser中(提示:Spring采用CharacterEncodingFilter设置了默认编码为UTF-8),然后在public class BeanDeserializer extends BeanDeserializerBase implements java.io.Serializable中,通过 public Object deserializeFromObject(JsonParser p, DeserializationContext ctxt) throws IOException方法进行解析
  • 核心逻辑分析示例:
  • 假设前端传的json串是这样的: {"name1":"兔子队列","age":20,"mot":"好焦虑"} 后端的模型只有name和age属性,以及对应的setter/getter方法
  • 给出一般用到的deserializeFromObject(JsonParser p, DeserializationContext ctxt)方法的核心逻辑:

指定模型中的属性对应什么key

  • 给出Controller中的测试类:
  • 给出模型中的属性(setter/getter方法没截出来):
  • 使用postman测试一下,示例:
  • 解释1:@JsonAlias注解,实现:json转模型时,使json中的特定key能转化为特定的模型属性;但是模型转json时,对应的转换后的key仍然与属性名一致,见:上图示例中的name字段的请求与响应;以下图进一步说明:
  • 此时,json字符串转换为模型时,json中key为Name或为name123或为name的都能识别
  • 解释2:@JsonProperty注解,实现:json转模型时,使json中的特定key能转化为指定的模型属性;同样的,模型转json时,对应的转换后的key为指定的key,见:示例中的motto字段的请求与响应;以下图进一步说明:
  • 此时,json字符串转换为模型时,key为MOTTO的能识别,但key为motto的不能识别
  • 解释3:@JsonAlias注解需要依赖于setter、getter,而@JsonProperty注解不需要
  • 解释4: 在不考虑上述两个注解的一般情况下,key与属性匹配时,默认大小写敏感
  • 解释5: 有多个相同的key的json字符串中,转换为模型时,会以相同的几个key中,排在最后的那个key的值给模型属性复制,因为setter会覆盖原来的值;见示例中的gender属性
  • 解释6: 后端@RequestBody注解对应的类在将HTTP的输入流(含请求体)装配到目标类(即:@RequestBody后面的类)时,会根据json字符串中的key来匹配对应实体类的属性,如果匹配一致且json中的该key对应的值符合(或可转换为)实体类的对应属性的类型要求时,会调用实体类的setter方法将值赋给该属性

用@Valid校验@RequestBody的参数

  • 如果希望通过注解校验post请求的body,需要用到@Valid注解
  • 在接收request实体类添加注解进行校验,例如用@NotNull进行判空校验
  • 如果入参是List,单独用@Valid不生效,需要在Controller上加@Validated注解
  • 结合统一异常处理,处理MethodArgumentNotValidException和ConstraintViolationException,可以返回注解配置的错误信息:

根据RequestBody的内容来区分使用哪个资源

  • 如果使用Spring,可以通过@RequestBody将请求体的json转换为Java对象,但如果URI相同,而请求体的内容不同,应该怎么办?
  • 问题来源(stackoverflow):
  • Spring @RequestBody without using a pojo?
  • 稍微研究了一下,如果将@RequestBody指定为Map,那么请求体(键、值)会存储到Map对象中
  • 案例:
  • 发送POST请求,虽然URI相同,但是请求体却不同
  • 不过,携带了一个名为type的共同数据,并通过type的值来判别不同的情况
  • 这次准备了两个type的值:concert和trip
  • 控制器的实现:
  • 在控制器的实现中,指定 @RequestBody 为 Map<String, Object> 类型
  • 通过指定 Map,可以将请求体以键值对的形式存储
  • 查看 type 键的值,以此判断是哪一种类型的请求,并将请求转换为相应的类
  • 在转换过程中使用了 Jackson 的 ObjectMapper 类进行转换
  • 这里,我们将其转换为相应类的对象,输出到标准输出并结束
  • 尝试发送 concert 的请求
  • 结果的标准输出
  • 尝试发送 trip 的请求
  • 结果的标准输出
  • 所以正确地将其转换为对应的类是可能的
  • 整体代码:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1495169.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI资讯2024-03-06|超越GPT-4的大模型一夜来袭,霸主之位花落谁家

全球最强大模型一夜易主&#xff0c;GPT-4时代终结 新一代AI模型Claude 3系列的登场&#xff0c;如同一场风暴席卷AI领域。GPT-4被迅速抛入阴影&#xff0c;Anthropic的最新力作完胜天下&#xff0c;以无可匹敌之势彰显其强大。Claude 3在多模态和语言能力方面都凌驾于GPT-4之上…

Mendix 开发实践指南|Mendix 环境搭建

在上一篇文章中&#xff0c;我们深入探讨了Mendix平台的一些关键概念&#xff0c;从而获得了对Mendix模型驱动设计哲学的清晰理解。随着这些核心理念的掌握&#xff0c;我们自然会产生一系列实践层面的问题&#xff0c;尤其是关于如何开始使用Mendix进行开发的细节。 本篇文章…

【力扣 - 无重复字符的最长字符串】

题目描述 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所以其长度为 3。 示例 2: 输入: s "bbbbb" 输出: 1 …

2024年最新Android面试精讲,面试题附答案

一. 开发背景 想要成为一名优秀的Android开发&#xff0c;你需要一份完备的知识体系&#xff0c;在这里&#xff0c;让我们一起成长为自己所想的那样。 Android 相关 1. Android 之 SharedPreferences 内部原理浅析 2. Android 源码分析-消息队列和 Looper 3. Android 源码分析…

状压dp详解,棋盘式、集合型,OJ详解

文章目录 零、引例-小国王1.问题描述2.暴力枚举3.多维dp4.维度压缩 一、状压dp1.认识状压dp2.棋盘式(基于连通性)2.1小国王2.1.1题目链接2.1.2思路分析2.1.3AC代码 2.2玉米田2.2.1题目链接2.2.2思路分析2.2.3AC代码 2.3炮兵阵地2.3.1题目链接2.3.2思路分析2.3.3AC代码 2.4蒙德里…

网络、网络协议模型、UDP编程——计算机网络——day01

今天来到了网络编程&#xff0c;主要讲了网络、网络协议模型以及UDP编程 网络 网络主要是进行&#xff1a;数据传输和数据共享 网络协议模型 OSI协议模型应用层 实际发送的数据表示层 发送的数据是否加密会话层 是否建立会话连接传…

激光炸弹c++

题目 输入样例&#xff1a; 2 1 0 0 1 1 1 1输出样例&#xff1a; 1 思路 由题知本题要求某个区间内数的和&#xff0c;联想到二维前缀和。我们可以先使用二维前缀和模板计算各区间的价值。然后枚举以某点为右下角&#xff0c;大小为R*R的正方形价值&#xff0c;取最大值。 …

06 - 镜像管理之:基础知识

1 了解镜像 Docker镜像是一个特殊的文件系统&#xff0c;除了提供容器运行时所需的程序、库、资源、配置等文件外&#xff0c;还包含了一些为运行时准备的一些配置参数&#xff08;如匿名卷、环境变量、用户等&#xff09;。 但注意&#xff0c; 镜像不包含任何动态数据&#…

【DataRoom】- 基于VUE的开源的大屏可视化设计器

【DataRoom】- 基于VUE的开源的大屏可视化设计器 DataRoom是一款基于SpringBoot、MyBatisPlus、Vue、ElementUI、G2Plot、Echarts等技术栈的大屏设计器&#xff0c;具备大屏设计、预览能力&#xff0c;支持MySQL、Oracle、PostgreSQL、SQLServer、ElasticSearch、JSON、JS、HTT…

springcloud:3.7测试线程池服务隔离

服务提供者【test-provider8001】 Openfeign远程调用服务提供者搭建 文章地址http://t.csdnimg.cn/06iz8 相关接口 测试远程调用&#xff1a;http://localhost:8001/payment/index 服务消费者【test-consumer-resilience4j8004】 Openfeign远程调用消费者搭建 文章地址http://t…

Dubbo的线程模型

1 线程模型概述 Dubbo默认的底层网络通信使用的是Netty。 服务提供方NettyServer使用两级线程池&#xff0c;其EventLoopGroup&#xff08;boss&#xff09;主要用来接收客户端的连接请求&#xff0c;并把完成TCP三次握手的连接分发给EventLoopGroup&#xff08;worker&#…

【音视频开发好书推荐】RTC程序设计:实时音视频权威指南

目录 1、WebRTC概述2、好书推荐3、本书内容4、本书特色5、作者简介6、谁适合看这本书 1、WebRTC概述 WebRTC&#xff08;Web Real-Time Communication&#xff09;是一个由Google发起的实时音视频通讯C开源库&#xff0c;其提供了音视频采集、编码、网络传输&#xff0c;解码显…

【考研数学】基础660太难了?一个办法搞定660

觉得题目太难&#xff0c;大概率是题目超出了自己当前的水平 题型没见过&#xff0c;或者太复杂&#xff0c;属于跳级学习了&#xff0c;正确的思路就是回归到自己的水平线&#xff0c;题目略难即可。 这样做题的话&#xff0c;大部分题目涉及的点不会超出自己的能力范围&…

【详识JAVA语言】String 类1

String类的重要性 在C语言中已经涉及到字符串了&#xff0c;但是在C语言中要表示字符串只能使用字符数组或者字符指针&#xff0c;可以使用标准库提 供的字符串系列函数完成大部分操作&#xff0c;但是这种将数据和操作数据方法分离开的方式不符合面相对象的思想&#xff0c;而…

python之海龟绘图

海龟绘图&#xff08;turtle&#xff09;是一个Python内置的绘图库&#xff0c;也被称为“Turtle Graphics”或简称“Turtles”。它采用了一种有趣的绘图方式&#xff0c;模拟一只小海龟在屏幕上爬行&#xff0c;而小海龟爬行的路径就形成了绘制的图形。这种绘图方式最初源自20…

考研数学——高数:多元函数微分法及其应用

因为复习阶段全篇很细节的写下来一来比较费时间&#xff0c;二容易导致为了记笔记而记。 接下来的内容只会保留上课中比较有意义的地方&#xff0c;以及有自己助于理解的想法 全微分 助记&#xff1a; 证明是否可微&#xff0c;首先判断两个偏导数是否存在&#xff0c;不存在则…

插入排序和归并排序

插入排序&#xff0c;Insertion Sort. 给出伪代码 for i 1,2,...,n-1Insert A[i] into Sorted array A[0:i-1]by swaping down to the correct position. 冒泡排序 冒泡排序就是一种插入排序算法。 i ← 1 while i < length(A)j ← iwhile j > 0 and A[j-1] > A…

FlyClient SPV client轻量化

这篇文章主要是为了构建一种轻客户端的算法。 如果使用SPV 的方式验证交易&#xff0c;每个client上面需要存储非常多的header。使用 proofs of proof-of-work 的方式&#xff0c;使得请客户端仅仅下载少量的区块头就能验证这一条链的安全性&#xff0c;然后再对包含交易的区块…

【详识JAVA语言】String类2

常用方法 字符串的不可变性 String是一种不可变对象. 字符串中的内容是不可改变。字符串不可被修改&#xff0c;是因为&#xff1a; 1. String类在设计时就是不可改变的&#xff0c;String类实现描述中已经说明了 以下来自JDK1.8中String类的部分实现&#xff1a; String类…