@RequestBody大解密,说点你不知道的 | SpringMVC第5篇

2021-06-25 21:30:11 浏览数 (1)

1、本文内容

1、掌握接收 json 格式数据的使用步骤及原理

2、掌握@RequestBody 注解的用法

3、(重点)通过源码来分析控制器具体可以接收哪些参数

2、软件版本

1、idea 2020.3.3

2、jdk1.8

3、≥maven3.6.1

4、spring5.3.6

5、apache-tomcat-9.0.46

3、json 格式数据的好处

当 http 请求传输的数据格式比较复杂的时,可以采用 json 格式

  • 数据量更小
  • 组装数据更容易
  • 数据结构看起来更清晰

4、Http 发起 json 格式的请求

1、头中需要设置 Content-Type 的值为 application/json

2、请求 body 中数据格式为 json 文本

5、我们来实现一个需求

http 发送 json 格式的请求,如:

代码语言:javascript复制
## 发送json请求(body中数据为json格式)
POST http://localhost:8080/chat03/user/add.do
Content-Type: application/json;charset=UTF-8

{
  "name": "路人",
  "age": 10,
  "address": "上海"
}

我们希望下面这个方法可以处理这个请求,由 springmvc 负责将 body 中的 json 格式的数据转换为 UserDto 对象,然后传递给下面的 add 方法。

代码语言:javascript复制
@PostMapping("/user/add.do")
public ModelAndView add(UserDto user)
代码语言:javascript复制
public class UserDto {
    //姓名
    private String name;
    //年龄
    private Integer age;
    //地址
    private String address;

    //省略get、set

    @Override
    public String toString() {
        return "UserDto{"  
                "name='"   name   '''  
                ", age="   age  
                ", address='"   address   '''  
                '}';
    }
}

6、SpringMVC 接受 json 格式数据(3 个步骤)

步骤 1:maven 添加 jackson 配置

代码语言:javascript复制

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.11.4</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.11.4</version>
</dependency>

jackson 是一个 json 工具包,可以将 json 格式的字符串和 java 对象互转。 而我们 body 中的数据是 json 格式的,controller 中方法是 java 对象,所以需要将 json 数据转换为 java 对象。 而 json 库有很多,比如 jackson、gson、fastjson,此处我们使用 springmvc 推荐的 jackson。

步骤 2:springmvc 中添加 mvc 驱动配置

代码语言:javascript复制

<mvc:annotation-driven/>

这 2 个步骤配置好了之后,springmvc 就被赋予了一个强大的功能,有能力将 http请求 body 中 json 格式的数据转换为 java 对象。

透露一下原理:springmvc 容器中被添加了一个 MappingJackson2HttpMessageConverter 对象,这个类可以将 body 中 json 格式的数据转换为 java 对象,内部用到的是 jackson。 MappingJackson2HttpMessageConverter 这类就是在步骤 1 添加的 maven 包中。

步骤 3:方法参数使用@RquestBody 注解标注

当我们希望 controller 中处理器的方法参数的数据来源于 http 请求的 body 时,需要在参数的前面加上@RequestBody 注解

代码语言:javascript复制
@PostMapping("/user/add.do")
public ModelAndView add(@RequestBody UserDto user) {
    System.out.println("user:"   user);

    ModelAndView modelAndView = new ModelAndView();
    modelAndView.setViewName("/WEB-INF/view/result.jsp");
    modelAndView.addObject("msg", user);
    return modelAndView;
}

就这么简单,此时这个方法就可以接受 json 格式的数据,springmvc 会自动将 body 中 json 格式的字符串转换为 UserDto 对象,然后传递给上面的 add 方法的第一个参数。

案例代码

1、拉取代码

代码语言:javascript复制
https://gitee.com/javacode2018/springmvc-series

2、导入 idea

3、发布到 tomcat

4、运行用例,用例的位置

输出的结果如下,可以看出 json 数据被 UserDto 接收成功了。

7、@RequestBody 注解

作用

用来接收 http 请求 body 的数据。

HTTP 请求大家比较熟悉,比如 POST 方式提交的请求,是有个 body 部分的,在 springmvc 中,我们希望控制器的方法中某个参数的值为 http 请求中的 body 的值,那么只需要在这个参数的前面加上@RequestBody 注解,springmvc 会将 http 请求中 body 的数据读取出来,然后传递给这个参数。

来看 2 个案例。

案例 1:使用 String 类型接受 body

代码语言:javascript复制
public void m1(@RequestBody String body)

springmvc 会将请求中 body 部分的数据读取出来,转换为 String 类型传递给这个参数。

案例 2:使用字节数组接受 body 的数据

代码语言:javascript复制
public void m1(@RequestBody byte[] bytes);

springmvc 会将请求中 body 部分的数据读取出来,然后转换为字节数组然后传递给 bytes 参数。

2 个案例代码位置

8、(重点)HandlerMethodArgumentResolver

这里给大家扩展点知识,到目前我们知道可以使用@RequestParam 接收表单的值,@RequestBody 可以接收请求中 body 的数据,@PathVariable 可以接受 url 中动态参数。

那么问题来了,控制器的方法具体可以接收哪些类型的参数呢?这是个好问题

说句实话,可以接收参数的类型非常的多,这里我教大家大家一招,看看 springmvc 具体可以接受哪些类型的参数。

这里只需要掌握一个关键的接口就可以了:HandlerMethodArgumentResolver(控制器方法参数解析器),这个接口特别重要,负责将 http 请求中的数据转换为 controller 中的方法能够接收的数据,就是根据控制器中方法参数信息,将 http 请求中的信息,转换控制器方法需要的参数的值。

这个接口有 2 个方法大家需要掌握

代码语言:javascript复制
public interface HandlerMethodArgumentResolver {

 //判断当前解析器是否能处理这个parameter这个参数,也就是说是否能够将请求中的数据转换为parameter指定的参数的值
 boolean supportsParameter(MethodParameter parameter);

 //解析参数:从http请求中解析出控制器需要的参数的值
 Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
   NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;

}

这个接口有很多实现类,列几个比较熟悉的,当大家想知道 springmvc 还可以接收哪些类型的参数,以及这些参数有什么特点的时候,看看源码

实现类

对应的控制器参数

说明

PathVariableMapMethodArgumentResolver

@PathVariable 标注参数

从 url 中提取参数的值

RequestHeaderMethodArgumentResolver

@RequestHeader 标注参数

从 http 头中提取参数值

RequestParamMethodArgumentResolver

@RequestParam 标注参数

http 请求参数中获取值

RequestResponseBodyMethodProcessor

@RequestBody 标注参数

提取 body 数据,转换为参数类型

ServletResponseMethodArgumentResolver

ServletResponse、OutputStream、Writer 这 3 种类型的参数

这几种类型用来控制 http 请求的响应输出流

HttpEntityMethodProcessorHttpEntity

HttpEntity 类型的参数

HttpEntity 中包含了 http 请求头和 body 的所有信息

ExpressionValueMethodArgumentResolver

@Value 标注的参数

spel 表达式,从 spring 容器中获取值

MapMethodProcessor

参数为 Map 或者子类型

-

ModelMethodProcessor

参数为 org.springframework.ui.Model 或子类型

-

ModelAttributeMethodProcessor

@ModelAttribute 标注的参数

-

9、tomcat9 乱码问题

大家在 tomcat9 中跑案例的时候,控制台可能会输出乱码,需要配置下编码

10、SpringMVC 系列

  1. SpringMVC 系列第 1 篇:helloword
  2. SpringMVC 系列第 2 篇:@Controller、@RequestMapping
  3. SpringMVC 系列第 3 篇:异常高效的一款接口测试利器
  4. SpringMVC 系列第 4 篇:controller 常见的接收参数的方式

11、更多好文章

  1. Spring 高手系列(共 56 篇)
  2. Java 高并发系列(共 34 篇)
  3. MySql 高手系列(共 27 篇)
  4. Maven 高手系列(共 10 篇)
  5. Mybatis 系列(共 12 篇)
  6. 聊聊 db 和缓存一致性常见的实现方式
  7. 接口幂等性这么重要,它是什么?怎么实现?
  8. 泛型,有点难度,会让很多人懵逼,那是因为你没有看这篇文章!

0 人点赞