当前位置: 首页 > news >正文

@RequestBody注解的使用及源码解析

前言

@RequestBody 注解是我们进行JavaEE开发,最常见的几个注解之一,这篇博文我们以案例和源码相结合,帮助大家更好的了解 @RequestBody 注解

使用案例

1.自定义实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {private String username;private String password;@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +", password='" + password + '\'' +'}';}
}
@RestController
@RequestMapping("/request_body")
public class RequestBodyController {@PostMapping("/entity")public String entity(@RequestBody User user) {return user.toString();}}

 2.使用 Map 接收
@PostMapping("/map")
public String map(@RequestBody Map<String, User> map) {return map.toString();
}

3.自定义实体类 (复杂对象)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Complex {private String tag;private List<User> list;private User[] array;private Map<String, User> map;
}
@PostMapping("/complex")
public String complex(@RequestBody Complex complex) {return complex.toString();
}

请求参数
{"tag": "complex","list": [{"username": "anna","password": "123"},{"username": "bob","password": "456"}],"array": [{"username": "cindy","password": "135"},{"username": "david","password": "246"}],"map": {"u1": {"username": "eric","password": "159"},"u2": {"username": "frank","password": "357"}}
}
4.Content-Type 为 application/xml
添加 POM 文件
<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId><version>2.16.1</version>
</dependency>
接口方法 (和案例1只有方法名不一样)
@PostMapping("/xml")
public String xml(@RequestBody User user) {return user.toString();
}
请求头设置

将 Content-Type 设置为 application/xml (一般情况下 Content-Type 为 application/json

传递参数
<User><username>tom</username><password>123</password>
</User>
响应结果

源码解析

InvocableHandlerMethod#getMethodArgumentValues

参数的处理分为两个阶段:

  1. 判断当前环境中存在的resolvers,是否支持解析当前参数
  2. 处理参数
判断是否支持解析当前参数

我的环境中存在27个resolvers,通过命名我们大概可以猜测出 RequestResponseBodyMethodProcessor 是处理 @RequestBody 注解的 resolver

RequestResponseBodyMethodProcessor#supportsParameter

即如果参数上存在 @RequestBody 注解,则使用 RequestResponseBodyMethodProcessor 处理参数

RequestResponseBodyMethodProcessor#resolveArgument

RequestResponseBodyMethodProcessor 的 resolveArgument 方法会遍历当前环境中的 HttpMessageConverters,如果存在一个 HttpMessageConverter 的 canRead 方法返回 true,则使用该 HttpMessageConverter 的 read 方法读取数据。

案例1、2、3 的原理其实是一样的,request 的 Content-Type 为 application/json,spring-boot-starter-web 会引入 json 相关依赖,所以默认情况下,SpringMVC 有把 json 对象转换成 key-value 形式数据结构的能力

案例4 我们引用了相关依赖,使得 SpringMVC 有把 xml 对象转换成 key-value 形式数据结构的能力

小结

如果 request 的 Content-Type 为 xxx,并且存在一个 HttpMessageConverter 支持解析 Content-Type 为 xxx 的数据,通过 @RequestBody 注解,就可以将数据绑定到 key-value 形式的数据结构上 

扩展:自定义HttpMessageConverter,处理指定 Content-Type 的请求

创建HttpMessageConverter
public class UserTextPlainHttpMessageConverter implements HttpMessageConverter {@Overridepublic boolean canRead(Class clazz, MediaType mediaType) {return clazz == User.class && "text".equals(mediaType.getType()) && "plain".equals(mediaType.getSubtype());}@Overridepublic boolean canWrite(Class clazz, MediaType mediaType) {return false;}@Overridepublic List<MediaType> getSupportedMediaTypes() {return Collections.singletonList(MediaType.TEXT_PLAIN);}@Overridepublic Object read(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {try (InputStream inputStream = inputMessage.getBody();BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {String line;StringBuilder sb = new StringBuilder();while ((line = reader.readLine()) != null) {sb.append(line);}ObjectMapper objectMapper = new ObjectMapper();return objectMapper.readValue(sb.toString(), User.class);} catch (Exception e) {throw new RuntimeException(e);}}@Overridepublic void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {}
}
创建配置类
@Configuration
public class MessageConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {converters.add(new UserTextPlainHttpMessageConverter());}}
接口方法 (和案例1、4 只有方法名不一样)
@PostMapping("/convert")
public String convert(@RequestBody User user) {return user.toString();
}
Postman设置
 Content-Type 设置为 text/plain

body 传参类型为 text

接口响应

http://www.lryc.cn/news/396412.html

相关文章:

  • linux 服务器数据备份 和 mysql 数据迁移
  • 安防视频监控/云存储/视频汇聚EasyCVR平台播放设备录像不稳定,是什么原因?
  • S32V234平台开发(一)快速使用
  • C# 如何防止反编译?C#程序加密混淆保护方法大全
  • 企业数字化转型中的低代码开发平台应用:释放创新潜能
  • 因为目录问题开通的另外一个网站的美化过程
  • RedHat运维-Ansible自动化运维基础24-寻找问题常用模块
  • windows USB 设备驱动开发-USB带宽
  • 哪有什么「历史的垃圾时间」,有的只是你对自己的不诚实
  • 全志A527 T527 android13支持usb摄像头
  • 邦芒贴士:做到这8点工作生活中才能少犯错
  • 代码随想录算法训练营第7天
  • 苹果开发者取消自动续费
  • Phospho:LLM应用的文本分析利器
  • 微深节能 料场堆取料无人操作系统 格雷母线
  • Invoice OCR
  • 无菌隔离器内操作规范性的验证之气流流型验证-北京中邦兴业
  • 【YOLOv8系列】(一)YOLOv8介绍:实时目标检测的最新突破
  • 如何视频提取字幕?推荐5款视频字幕提取软件
  • 独孤思维:副业项目实操3天出单了
  • 包装器 std::function
  • Java | Leetcode Java题解之第219题存在重复元素II
  • 800 元打造家庭版 SOC 安全运营中心
  • vite项目使用qiankun构建hash路由微前端
  • 通过rpmbuild构建Elasticsearch-7.14.2-search-guard的RPM包
  • js 图片放大镜
  • 数据模型-ER图在数据模型设计中的应用
  • C++ //练习 14.46 你认为应该为Sales_data类定义上面两种类型转换运算符吗?应该把它们声明成explicit的吗?为什么?
  • tensorflow张量生成以及常用函数
  • 如何在 Windows 10 上恢复未保存的 Word 文档