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

Spring学习笔记_41——@RequestBody

Spring学习笔记_38——@RequestParam
Spring学习笔记_39——@PathVariable
Spring学习笔记_40——@RequestHeader

@RequestBody

1. 介绍

@RequestBody 是 Spring 框架中用于处理 HTTP 请求的一个非常关键的注解。它主要用于将客户端发送的 HTTP 请求体中的 JSON、XML 或其他格式的数据转换到Java 方法参数上,这个转换过程通常需要一个消息转换器(Message Converter),如 MappingJackson2HttpMessageConverter 用于 JSON 数据的转换。

这个注解通常用在基于 REST 风格的 Web 服务开发中,特别是在处理 POST 和 PUT 请求时非常有用。

2. 注解细节

  1. 自动绑定:
    • Spring 使用 HTTP 消息转换器(如 MappingJackson2HttpMessageConverter 用于 JSON)将请求体中的数据自动转换为 Java 对象。
    • 转换过程依赖于请求的内容类型(Content-Type),如 application/jsonapplication/xml
  2. 注解位置:
    • @RequestBody 只能用于方法的参数上。
    • 不能用于类定义或方法返回类型上。
  3. 方法参数类型:
    • @RequestBody 通常与 POJO(Plain Old Java Object)一起使用,但也可以与 Map、List 等集合类型一起使用,只要这些类型能够由 HTTP 消息转换器正确解析。
  4. 自定义消息转换器:
    • 如果需要处理特定的数据格式,可以自定义 HTTP 消息转换器,并注册到 Spring 的 WebMvcConfigurerWebFluxConfigurer 中。
  5. 异常处理:
    • 如果请求体中的数据格式不正确或无法转换为指定的 Java 类型,Spring 会抛出一个 HttpMessageNotReadableException 异常。
    • 可以使用 @ControllerAdvice@ExceptionHandler 来全局或局部处理这些异常。

3. 场景

  1. 接收 JSON 数据:当客户端发送 JSON 格式的数据给服务器时,可以通过 @RequestBody 将这些数据自动映射到一个 Java 对象中。
  2. 接收 XML 数据:与 JSON 类似,如果客户端发送的是 XML 格式的数据,也可以通过配置相应的消息转换器来实现数据的自动映射。
  3. 接收其他格式的数据:只要存在对应的消息转换器,几乎可以支持任何类型的数据格式。

  1. POST 请求:客户端发送 JSON 或 XML 格式的数据到服务器,服务器使用 @RequestBody 将这些数据自动转换为 Java 对象。
  2. PUT 请求:与 POST 类似,用于更新资源,客户端发送的数据也会被 @RequestBody 转换。

4. 源码

/*** @author Arjen Poutsma* @since 3.0* @see RequestHeader* @see ResponseBody* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestBody {// Spring3.2版本开始提供的boolean类型的属性// 表示是否必须有请求体。// true:必须有请求体// false:可以没有请求体// 如果为true时,未获取到请求体的数据时会强制报错。// 默认值为trueboolean required() default true;}

5. Demo

实体类

public class User {private String username;private String password;// Getters and Setters
}

Controller类

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class UserController {@PostMapping("/login")public String login(@RequestBody User user) {// 处理登录逻辑return "Hello, " + user.getUsername();}
}

6. 注意事项

  • 数据验证:通常情况下,接收到的数据需要进行验证,确保数据的有效性。可以结合使用 @Valid@Validated 注解来实现数据校验。
  • 内容类型:默认情况下,@RequestBody 只接受 application/json 类型的数据。如果需要支持其他类型,可以在 @PostMapping@RequestMapping 中指定 consumes 属性。
  • 错误处理:如果数据转换失败或数据不符合预期格式,Spring 会抛出异常。可以通过配置全局异常处理器来统一处理这些异常。

7. 补充-消息转换器

在 Spring 框架中,消息转换器(Message Converters)是用于将 HTTP 请求和响应的消息体(即请求体和响应体)转换为 Java 对象,或者将 Java 对象转换为消息体的关键组件。它们在处理 @RequestBody@ResponseBody 注解时起着至关重要的作用。

7.1 工作原理
  1. 请求处理
    • 当客户端发送一个 HTTP 请求时,请求体中的数据需要被转换为一个 Java 对象。Spring 会根据请求头中的 Content-Type 来选择合适的消息转换器。
    • 例如,如果 Content-Typeapplication/json,Spring 会选择 MappingJackson2HttpMessageConverter 来将 JSON 数据转换为 Java 对象。
  2. 响应处理
    • 当控制器方法返回一个 Java 对象时,Spring 需要将这个对象转换为 HTTP 响应体。Spring 会根据响应头中的 Accept 来选择合适的消息转换器。
    • 例如,如果 Acceptapplication/json,Spring 会选择 MappingJackson2HttpMessageConverter 来将 Java 对象转换为 JSON 数据。
7.2 内置消息转换器

Spring 提供了多个内置的消息转换器,常见的包括:

  1. StringHttpMessageConverter
    • 用于处理纯文本数据,支持 text/plain 类型。
  2. FormHttpMessageConverter
    • 用于处理表单数据,支持 application/x-www-form-urlencodedmultipart/form-data 类型。
  3. MappingJackson2HttpMessageConverter
    • 用于处理 JSON 数据,支持 application/json 类型。依赖于 Jackson 库。
  4. Jaxb2RootElementHttpMessageConverter
    • 用于处理 XML 数据,支持 application/xml 类型。依赖于 JAXB 库。
  5. MappingJackson2XmlHttpMessageConverter
    • 用于处理 XML 数据,支持 application/xml 类型。依赖于 Jackson 的 XML 扩展库。
7.3 自定义消息转换器

如果内置的消息转换器不能满足需求,可以创建自定义的消息转换器。自定义消息转换器需要实现 HttpMessageConverter 接口。

消息转换器可以在 Spring 配置文件中或通过 Java 配置类进行配置。以下是一个示例,展示如何在 Java 配置类中添加自定义消息转换器:

import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.List;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {// 添加自定义消息转换器converters.add(new MyCustomMessageConverter());// 配置默认的消息转换器converters.add(new MappingJackson2HttpMessageConverter());}// 定义自定义消息转换器public class MyCustomMessageConverter implements HttpMessageConverter<MyCustomType> {// 实现 HttpMessageConverter 接口的方法}
}
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;public class MyCustomMessageConverter extends AbstractHttpMessageConverter<MyCustomType> {private final JAXBContext jaxbContext;public MyCustomMessageConverter() {super(MediaType.APPLICATION_XML);try {this.jaxbContext = JAXBContext.newInstance(MyCustomType.class);} catch (JAXBException e) {throw new RuntimeException("Unable to create JAXBContext", e);}}@Overrideprotected boolean supports(Class<?> clazz) {return MyCustomType.class.isAssignableFrom(clazz);}@Overrideprotected MyCustomType readInternal(Class<? extends MyCustomType> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {try {Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();return (MyCustomType) unmarshaller.unmarshal(inputMessage.getBody());} catch (JAXBException e) {throw new HttpMessageNotReadableException("Could not read XML: " + e.getMessage(), e, inputMessage);}}@Overrideprotected void writeInternal(MyCustomType t, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {try {Marshaller marshaller = jaxbContext.createMarshaller();marshaller.marshal(t, outputMessage.getBody());} catch (JAXBException e) {throw new HttpMessageNotWritableException("Could not write XML: " + e.getMessage(), e);}}
}
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;public class MyTextMessageConverter implements HttpMessageConverter<MyTextData> {// 指定这个转换器支持的媒体类型@Overridepublic boolean canRead(Class<?> clazz, MediaType mediaType) {return clazz.equals(MyTextData.class) && MediaType.TEXT_PLAIN.isCompatibleWith(mediaType);}// 指定这个转换器支持的媒体类型@Overridepublic boolean canWrite(Class<?> clazz, MediaType mediaType) {return clazz.equals(MyTextData.class) && MediaType.TEXT_PLAIN.isCompatibleWith(mediaType);}// 从输入消息中读取数据,转换为MyTextData对象@Overridepublic MyTextData read(Class<? extends MyTextData> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {String text = new InputStreamReader(inputMessage.getBody(), Charset.forName(inputMessage.getHeaders().getContentType().getCharset().name())).readLine();return new MyTextData(text);}// 将MyTextData对象写入输出消息@Overridepublic void write(MyTextData myTextData, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {OutputStreamWriter writer = new OutputStreamWriter(outputMessage.getBody(), Charset.forName(contentType.getCharset().name()));writer.write(myTextData.getText());writer.flush();}// 返回这个转换器支持的媒体类型列表@Overridepublic List<MediaType> getSupportedMediaTypes() {return Collections.singletonList(MediaType.TEXT_PLAIN);}
}

http://www.mrgr.cn/news/77819.html

相关文章:

  • 分布式系统稳定性建设-性能优化篇
  • 【通俗理解】隐变量的变分分布探索——从公式到应用
  • java http body的格式 ‌application/x-www-form-urlencoded‌不支持文件上传
  • MongoDB调优利器:掌握性能分析工具mongostat
  • rust中解决DPI-1047: Cannot locate a 64-bit Oracle Client library问题
  • egrep grep 区别
  • HarmonyOS4+NEXT星河版入门与项目实战(11)------Button组件
  • 战争迷雾FogOfWar---Unity中实现
  • 解决Electron拖拽窗口点击事件失效问题
  • 「Mac玩转仓颉内测版28」基础篇8 - 元组类型详解
  • 分享一下arr的意义(c基础)(必看)(牢记)
  • 爬虫重定向问题解决
  • tcp/ip异常断开调试笔记——lwip
  • Oracle 19C 安装RAC磁盘投票失败
  • Vue实训---1-创建Vue3项目
  • 【大数据学习 | Spark-Core】Spark提交及运行流程
  • 【蓝桥杯C/C++】翻转游戏:多种实现与解法解析
  • 14.C++STL1(STL简介)
  • 【蓝桥杯C/C++】深入解析I/O高效性能优化:std::ios::sync_with_stdio(false)
  • minikube单机k8s出现Listen: listen tcp :53: bind: permission denied
  • 【题解】—— LeetCode一周小结46
  • CSRF保护--laravel进阶篇
  • 【大数据学习 | Spark-Core】spark-shell开发
  • 《线性代数的本质》
  • 【计算机网络】网段划分
  • C#语言入门