Spring之RequestBody的使用姿势小结

简介: SpringMVC中处理请求参数有好几种不同的方式,如我们常见的下面几种根据 HttpServletRequest 对象获取根据 @PathVariable 注解获取url参数根据 @RequestParam 注解获取请求参数根据Bean的方式获取请求参数根据 @ModelAttribute 注解获取请求参数

image.png


SpringMVC中处理请求参数有好几种不同的方式,如我们常见的下面几种


  • 根据 HttpServletRequest 对象获取
  • 根据 @PathVariable 注解获取url参数
  • 根据 @RequestParam 注解获取请求参数
  • 根据Bean的方式获取请求参数
  • 根据 @ModelAttribute 注解获取请求参数


对上面几种方式有兴趣的可以看一下这篇博文: SpringMVC之请求参数的获取方式


除了上面的几种方式之外,还有一种 @RequestBody 的使用方式,本文则主要介绍这种传参的使用姿势和相关注意事项


I. 使用姿势



1. 服务接口




借助Spring框架,使用@RequestBody并没有什么难度,很简单的就可以写一个使用case出来,如下


@Slf4j
@RestController
public class ReqBodyController {
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Req {
        private String key;
        private Integer size;
    }
    @RequestMapping(value = "/body", method = {RequestMethod.POST, RequestMethod.GET, RequestMethod.OPTIONS})
    public BaseRsp body(@RequestBody Req req) {
        log.info("req: {}", req);
        return new BaseRsp<>(req);
    }
}
复制代码


看上面的实现,和我们通常的写法并无差别,无非是将以前的 @RequsetParam 注解换成 @RequsetBody 注解,而且这个注解内部只有一个filed,比RequsetParam还少


@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestBody {
    // 默认参数必须存在,否则会抛一个异常
    boolean required() default true; 
}
复制代码


看到上面的实现,估计也可以猜出,这个注解对于后端而言,写没啥问题,关键是如何用(具体来讲是如何给前端用)


2. 接口调用



上面写完了,接下来的重点就是如何使用了,在使用之前,有必要了解下 RequestBody 这个注解出现的原有以及应用场景(换句话说它和RequestParam有什么区别,为什么要单独的搞一个这个东西出来)


RequestBody


@requestBody注解常用来处理content-type不是默认的application/x-www-form-urlcoded编码的内容,比如说:application/json或者是application/xml等。一般情况下来说常用其来处理application/json类型。


a. content-type定义


在进入下一步之前,有必要说一下Content-Type这个http请求头的作用了,下面一段来自其他博文,原文链接见最后


MediaType,即是Internet Media Type,互联网媒体类型;也叫做MIME类型,在Http协议消息头中,使用Content-Type来表示具体请求中的媒体类型信息。


常见媒体格式如下:


  • text/html : HTML格式
  • text/plain :纯文本格式
  • text/xml :  XML格式
  • image/gif :gif图片格式
  • image/jpeg :jpg图片格式
  • image/png:png图片格式


以application开头的媒体格式类型:


  • application/xhtml+xml :XHTML格式
  • application/xml     : XML数据格式
  • application/atom+xml  :Atom XML聚合格式
  • application/json    : JSON数据格式
  • application/pdf       :pdf格式
  • application/msword  : Word文档格式
  • application/octet-stream : 二进制流数据(如常见的文件下载)
  • application/x-www-form-urlencoded : 中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)


b. content-type 实例说明


上面算是基本定义和取值,下面结合实例对典型的几种方式进行说明


  • application/x-www-form-urlencoded:数据被编码为名称/值对。这是标准的编码格式。
  • multipart/form-data: 数据被编码为一条消息,页上的每个控件对应消息中的一个部分。
  • text/plain: 数据以纯文本形式(text/json/xml/html)进行编码,其中不含任何控件或格式字符


对于前端使用而言,form表单的enctype属性为编码方式,常用有两种:

application/x-www-form-urlencodedmultipart/form-data,默认为application/x-www-form-urlencoded


Get请求


发起Get请求时,浏览器用application/x-www-form-urlencoded方式,将表单数据转换成一个字符串(key1=value1&key2=value2...)拼接到url上,这就是我们常见的url带请求参数的情况


Post表单


发起post请求时,如果没有传文件,浏览器也是将form表单的数据封装成k=v的结果丢到http body中,拿开源中国的博客提交的表单为例,一个典型的post表单,上传的数据拼装在form data中,为kv结构


image.png

如果有传文件的场景,Content-Type类型会升级为multipart/form-data,这一块不详细展开,后面有机会再说


Post json串


post表单除了前面一种方式之外,还有一种也是我们常见的,就是讲所有的表单数据放在一个大的json串中,然后丢给后端,这里也有一个在线的实例,某电商平台的商品发表,截图如下


image.png


注意看上面的Request Payload,是一个大的json串,和前面差别明显


c. RequestBody请求


根据RequestBody的定义,要想访问前面定义的那个接口,使用传统的表单传递方式是不行的,curl命令测试如下


curl -X POST -d 'key=haha&size=123' http://127.0.0.1:19533/body
复制代码


后端对应的输出如下(抛了一个异常,表示@RequestBody注解修饰rest接口,不支持 Content type 'application/x-www-form-urlencoded;charset=UTF-8'

image.png


因此使用姿势需要显示添加请求头,传参也改变一下

curl -l -H "Content-type: application/json" -X GET -d '{"key": "!23", "size": 10}' http://127.0.0.1:19533/body
复制代码


返回结果如下

image.png


3. 注意事项



a. content-type显示指定


根据前面的说明,可以知道 @RequestBody 这个注解的使用,使得REST接口接收的不再content-type为application/x-www-form-urlencoded的请求, 反而需要显示指定为application/json


b. 请求方法


RequestBody支持GET方法么?前面都是采用post提交参数,如果改成GET会怎样?


curl测试方式

curl -l -H "Content-type: application/json" -X GET -d '{"key": "!23", "size": 10}' http://127.0.0.1:19533/body\?key\=app
复制代码


对应的后端debug截图如下,发现使用GET方式,并没有问题,依然可以获取到参数


image.png


换成大名鼎鼎的POSTMAN来测试


使用post方法请求时,截图如下,主要就是修改header的content-type,然后在body中添加json串格式的请求

image.png


然而改成get之后,body都直接灰掉了,也就是它不支持在get请求时,提交Body数据

image.png


url请求方式


接下来直接换成url的请求方式,看是否直接支持get请求

http://127.0.0.1:19533/body?{"key": "!23", "size": 10}
复制代码


浏览器中输入时,服务器400, 换成curl方式请求,抛的是缺少RequestBody的异常,也就是说,将json串拼接到url中貌似不行(也有可能是我的使用姿势不对。。。)


小结

  • 到这里小结一下,使用RequestBody获取参数时,还是老老实实的选择POST方法比较合适,至于原因,跟大众,随主流,跟着大家的习惯走比较好


c. 参数获取


这个主要就是后端编写接口时,获取RequestBody参数的问题了,通过测试,发现在HttpServletRequest参数中,居然拿不到提交的RequestBody参数,演示如下

请求url为


curl -l -H "Content-type: application/json" -X POST -d '{"key": "!23", "size": 10}' http://127.0.0.1:19533/body\?url\=ddd
复制代码


对应的debug截图如下,url参数可以拿到,RequestBody参数没有


image.png


首先声明,下面的这段分析,没有看源码,纯属于个人推断,如有问题,对被误导的朋友表示歉意,也希望对此有了解的朋友,多多批评指正


从传文件的思路出发,前端传文件给后端时,后端是基于流的方式,将上传的二进制流,写入到`MultipartFile`;而二进制流读完之后,没法再重复的读
RequestBody可能也是这么个逻辑,首先是从HttpServletRequest的Reader流中读取body参数并封装到上面的req对象,而不会像url参数一样,写回到`javax.servlet.ServletRequest#getParameterMap`
复制代码


对上面的猜测做一个小小的验证,改成直接从HttpServletRequest的Reader流中获取请求body参数

@RequestMapping(value = "/body", method = {RequestMethod.POST, RequestMethod.GET, RequestMethod.OPTIONS})
public BaseRsp body(HttpServletRequest request) throws IOException {
    BufferedReader reader = request.getReader();
    StringBuilder builder = new StringBuilder();
    String line = reader.readLine();
    while (line != null) {
        builder.append(line);
        line = reader.readLine();
    }
    reader.close();
    String reqBody = builder.toString();
    Req req = JSON.parseObject(reqBody, Req.class);
    log.info("req: {}, request: {}", req, request.getParameterMap());
    return new BaseRsp<>(req);
}
复制代码


验证如下

image.png


其实到这里,有个有意思的地方已经引起了我的好奇,那就是在Spring容器中HttpServletRequest这个东西,是怎么运转的,后面有机会再聊,此处不展开...


4. 小结



  • ReuqestBody 主要是处理json串格式的请求参数,要求使用方指定header content-type:application/json
  • RequestBody 通常要求调用方使用post请求
  • RequsetBody参数,不会放在HttpServletRequest的Map中,因此没法通过javax.servlet.ServletRequest#getParameter获取



相关文章
|
前端开发 Java 数据格式
Spring @RequestBody与@ResponseBody注解
Spring的注解非常多,这篇文章我们说一下它的@RequestBody 和 @ResponseBody注解。 @ResponseBody 简单说,@ResponseBody注解将HttpRequest的请求体映射为Java的POJO对象。
|
JSON 前端开发 Java
Spring MVC常用注解--“姐妹花”@RequestBody和@ResponseBody
在这篇短文中,我们简要地介绍了Spring MVC中常用的注解 @RequestBody和@ResponseBody。
2768 0
|
7月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1135 0
|
8月前
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
896 0
|
4月前
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
439 4
|
4月前
|
Java 测试技术 数据库连接
【SpringBoot(四)】还不懂文件上传?JUnit使用?本文带你了解SpringBoot的文件上传、异常处理、组件注入等知识!并且带你领悟JUnit单元测试的使用!
Spring专栏第四章,本文带你上手 SpringBoot 的文件上传、异常处理、组件注入等功能 并且为你演示Junit5的基础上手体验
960 2
|
11月前
|
前端开发 Java 数据库
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 介绍
本课介绍Spring Boot集成Thymeleaf模板引擎。Thymeleaf是一款现代服务器端Java模板引擎,支持Web和独立环境,可实现自然模板开发,便于团队协作。与传统JSP不同,Thymeleaf模板可以直接在浏览器中打开,方便前端人员查看静态原型。通过在HTML标签中添加扩展属性(如`th:text`),Thymeleaf能够在服务运行时动态替换内容,展示数据库中的数据,同时兼容静态页面展示,为开发带来灵活性和便利性。
467 0
|
11月前
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于 xml 的整合
本教程介绍了基于XML的MyBatis整合方式。首先在`application.yml`中配置XML路径,如`classpath:mapper/*.xml`,然后创建`UserMapper.xml`文件定义SQL映射,包括`resultMap`和查询语句。通过设置`namespace`关联Mapper接口,实现如`getUserByName`的方法。Controller层调用Service完成测试,访问`/getUserByName/{name}`即可返回用户信息。为简化Mapper扫描,推荐在Spring Boot启动类用`@MapperScan`注解指定包路径避免逐个添加`@Mapper`
592 0
|
11月前
|
Java 测试技术 微服务
微服务——SpringBoot使用归纳——Spring Boot中的项目属性配置——少量配置信息的情形
本课主要讲解Spring Boot项目中的属性配置方法。在实际开发中,测试与生产环境的配置往往不同,因此不应将配置信息硬编码在代码中,而应使用配置文件管理,如`application.yml`。例如,在微服务架构下,可通过配置文件设置调用其他服务的地址(如订单服务端口8002),并利用`@Value`注解在代码中读取这些配置值。这种方式使项目更灵活,便于后续修改和维护。
205 0
|
11月前
|
SQL Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— application.yml 中对日志的配置
在 Spring Boot 项目中,`application.yml` 文件用于配置日志。通过 `logging.config` 指定日志配置文件(如 `logback.xml`),实现日志详细设置。`logging.level` 可定义包的日志输出级别,例如将 `com.itcodai.course03.dao` 包设为 `trace` 级别,便于开发时查看 SQL 操作。日志级别从高到低为 ERROR、WARN、INFO、DEBUG,生产环境建议调整为较高级别以减少日志量。本课程采用 yml 格式,因其层次清晰,但需注意格式要求。
1048 0